Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cice.setup
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ echo "${testname_base}"
cd ${testname_base}
source ./cice.settings
set ciceexe = "../ciceexe.\${ICE_COMPILER}.\${ICE_COMMDIR}.\${ICE_BLDDEBUG}.\${ICE_THREADED}.\${ICE_IOTYPE}"
./cice.build \${ciceexe}
./cice.build --exe \${ciceexe}
if !(-e \${ciceexe}) cp -p \${ICE_RUNDIR}/cice \${ciceexe}
EOF
end
Expand Down
80 changes: 56 additions & 24 deletions configuration/scripts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
# SRCS=<files> ~ list of src files, default is all .c .F .F90 files in VPATH
# VPFILE=<file> ~ file with list of dirs, used to create VPATH
# SRCFILE=<file> ~ file with list of src files, used to create SRCS
# DEPGEN=<exec> ~ dependency generator utility, default is makdep
#
# <macro defns> ~ any macro definitions found in this file or the included
# MACFILE will be over-riden by cmd-line macro definitions
Expand All @@ -31,7 +30,9 @@ VPFILE := NONE
VPATH := .
SRCFILE := NONE
SRCS := NONE
DEPGEN := ./makdep # an externally provided dependency generator

# dependency generator
DEPGEN := ./makdep

ifneq ($(VPATH),.)
# this variable was specified on cmd line or in an env var
Expand All @@ -58,26 +59,35 @@ endif
OBJS := $(addsuffix .o, $(sort $(basename $(notdir $(SRCS)))))
DEPS := $(addsuffix .d, $(sort $(basename $(notdir $(SRCS)))))
INCS := $(patsubst %,-I%, $(VPATH) )
OBJS_DEPGEN := $(addprefix $(ICE_CASEDIR)/,$(addsuffix .c, $(notdir $(DEPGEN))))
MODDIR:= -I.
RM := rm

.SUFFIXES:
.SUFFIXES: .F90 .F .c .o

.PHONY: all

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a single .PHONY: all cice db_files db_flags mostlyclean clean realclean line would also work

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, good to know. I may do that instead, it's cleaner.

all: $(EXEC)

.PHONY: cice
cice: $(EXEC)

#-------------------------------------------------------------------------------
# include the file that provides macro definitions required by build rules
# note: the MACFILE may not be needed for certain goals
#-------------------------------------------------------------------------------

ifneq ($(MAKECMDGOALS), db_files)
-include $(MACFILE)
endif
-include $(MACFILE)

#-------------------------------------------------------------------------------
# echo file names, paths, compile flags, etc. used during build
# echo supported targets, file names, paths, compile flags, etc. used during build
#-------------------------------------------------------------------------------

.PHONY: targets
targets:
@echo " "
@echo "Supported Makefile Targets are: cice, makdep, depends, mostlyclean, clean, realclean, targets, db_files, db_flags"

.PHONY: db_files
db_files:
@echo " "
@echo "* EXEC := $(EXEC)"
Expand All @@ -89,12 +99,23 @@ db_files:
@echo "* SRCS := $(SRCS)"
@echo "* OBJS := $(OBJS)"
@echo "* DEPS := $(DEPS)"
@echo "* ULIBS := $(ULIBS)"
@echo "* SLIBS := $(SLIBS)"
@echo "* INCLDIR := $(INCLDIR)"
@echo "* OBJS_DEPGEN := $(OBJS_DEPGEN)"
.PHONY: db_flags
db_flags:
@echo " "
@echo "* cpp := $(CPP) $(CPPFLAGS) $(CPPDEFS) $(INCS) $(INCLDIR)"
@echo "* cc := $(CC) -c $(CFLAGS) $(INCS) $(INCLDIR)"
@echo "* .F.o := $(FC) -c $(FFLAGS) $(FIXEDFLAGS) $(INCS) $(INCLDIR)"
@echo "* .F90.o := $(FC) -c $(FFLAGS) $(FREEFLAGS) $(INCS) $(INCLDIR)"
@echo "* $(DEPGEN) := $(SCC) $(CFLAGS_HOST)"
@echo "* %.d : %.c := $(DEPGEN) $(INCS)"
@echo "* %.d : %.F := $(DEPGEN) $(INCS)"
@echo "* %.d : %.F90 := $(DEPGEN) $(INCS)"
@echo "* %.d : %.H := $(DEPGEN) $(INCS)"
@echo "* cpp := $(CPP) $(CPPFLAGS) $(CPPDEFS) $(INCLDIR)"
@echo "* .c.o := $(CC) $(CFLAGS) $(CPPDEFS) $(INCLDIR)"
@echo "* .F.o := $(FC) -c $(FFLAGS) $(FIXEDFLAGS) $(CPPDEFS) $(INCLDIR)"
@echo "* .F90.o := $(FC) -c $(FFLAGS) $(FREEFLAGS) $(CPPDEFS) $(MODDIR) $(INCLDIR)"
@echo "* $(notdir $(EXEC)) := $(LD) $(LDFLAGS) $(ULIBS) $(SLIBS)"

#-------------------------------------------------------------------------------
# build rule for makdep: MACFILE, cmd-line, or env vars must provide
Expand All @@ -105,7 +126,8 @@ ifndef $(CFLAGS_HOST)
CFLAGS_HOST :=
endif

$(DEPGEN): $(ICE_CASEDIR)/makdep.c
$(DEPGEN): $(OBJS_DEPGEN)
@ echo "Building makdep"
$(SCC) -o $@ $(CFLAGS_HOST) $<

#-------------------------------------------------------------------------------
Expand All @@ -116,46 +138,50 @@ $(EXEC): $(OBJS)
$(LD) -o $(EXEC) $(LDFLAGS) $(OBJS) $(ULIBS) $(SLIBS)

.c.o:
$(CC) $(CFLAGS) $(CPPDEFS) $(INCS) $(INCLDIR) $<
$(CC) $(CFLAGS) $(CPPDEFS) $(INCLDIR) $<

.F.o:
$(FC) -c $(FFLAGS) $(FIXEDFLAGS) $(CPPDEFS) $(INCS) $(INCLDIR) $<
$(FC) -c $(FFLAGS) $(FIXEDFLAGS) $(CPPDEFS) $(INCLDIR) $<

.F90.o:
$(FC) -c $(FFLAGS) $(FREEFLAGS) $(CPPDEFS) $(INCS) $(INCLDIR) $<
$(FC) -c $(FFLAGS) $(FREEFLAGS) $(CPPDEFS) $(MODDIR) $(INCLDIR) $<

.PHONY: mostlyclean
mostlyclean:
$(RM) -f *.f *.f90
$(RM) -f $(DEPS) $(OBJS) $(EXEC)

.PHONY: clean
clean:
$(RM) -f *.f *.f90 *.d *.mod *.o $(EXEC)
# $(RM) -f *.f *.f90 *.d *.$(MOD_SUFFIX) $(OBJS)
$(RM) -f *.f *.f90 $(DEPS) $(OBJS) $(DEPGEN) $(EXEC)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I think we can take this opportunity to simplify the clean targets. I don't think we need 3. I think that having a 'clean' target that deletes all *.o, *.mod, *.d and the exe is sufficient, plus a 'realclean' target that does the same plus deletes the 'makdep' executable. (this way the 'clean' target does the same thing as a clean build in terms of the CICE code itself)
  • I prefer the 'rm' command in these targets to use '*.o' instead of '$(OBJS)' (for example) since the latter dumps a lot of text to the command line. (and in clean builds, this is amongst the first text that is outputed)
  • I think we can remove the *.f and *.f90 from these targets since our build system does not generate any preprocessed sources.

I suggest the following, which is also simpler :

clean:
	$(RM) -f *.o *.d *.mod $(EXEC)
realclean: clean
	$(RM) -f $(DEPGEN)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I will refactor a bit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other comment, the clean that the CICE code does by default is now using the Makefile clean. I changed that recently (maybe in this PR), not sure why it wasn't doing that before.


.PHONY: realclean
realclean:
$(RM) -f *.f *.f90 *.d *.$(MOD_SUFFIX) $(OBJS) $(EXEC)
$(RM) -f *.f *.f90 *.d *.mod *.o $(DEPS) $(OBJS) $(DEPGEN) $(EXEC)

#-------------------------------------------------------------------------------
# Build & include dependency files

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could also take this opportunity to clean up what is uneeded here : all our files are *.F90 or *.c so the dependency generation for *.F and *.H can be removed.
Same for the rule

.F.o:
	$(FC) -c $(FFLAGS) $(FIXEDFLAGS) $(CPPDEFS) $(INCLDIR) $<

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to leave the other make rules in the Makefile for now. It could be that future development will need them. I don't think it hurts to have them there. I don't think folks actually look at the Makefile all that much. But I could be convinced otherwise. For now, I think I'll leave them as is.

#-------------------------------------------------------------------------------
# ASSUMPTIONS:
# o an externally provided dependency generator, $(DEPGEN), is available,
# o the dependency generator, $(DEPGEN), can be built,
# its cmd line syntax is compatible with the build rules below. Eg, for
# each .o file, there is a corresponding .d (dependency) file, and both
# will be dependent on the same src file, eg. foo.o foo.d : foo.F90
# Also, the dependancy genorator's capabilities, limitations, and assumptions
# are understood & accepted.
#-------------------------------------------------------------------------------

%.d : %.c
depends: $(DEPS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the 'depends' target is needed... it's only use would be to manually recreate the dependencies by calling cice.build depends, right ? I don't see a use case for that; either the user uses incremental builds or clean builds; in both cases the makefile generates the dependencies before starting the compilation. I think that having a depends target can create some confusion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right that we may not need depends. I don't think it hurts to have it. Maybe someone wants to just generate the depends without building the rest of the code?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right that it does not hurt to have it. Although in that case I would mention somewhere in the documentation that the dependencies are usually automatically generated.


%.d : %.c $(DEPGEN)
@ echo "Building dependency for $@"
@ $(DEPGEN) -f $(INCS) $< | head -3 > $@
%.d : %.F
%.d : %.F $(DEPGEN)
@ echo "Building dependency for $@"
@ $(DEPGEN) -f $(INCS) $< > $@
%.d : %.F90
%.d : %.F90 $(DEPGEN)
@ echo "Building dependency for $@"
@ $(DEPGEN) -f $(INCS) $< > $@
%.d : %.H
%.d : %.H $(DEPGEN)
@ echo "Building dependency for $@"
@ $(DEPGEN) -f $(INCS) $< > $@

Expand All @@ -165,9 +191,15 @@ ifneq ($(MAKECMDGOALS), db_flags)
ifneq ($(MAKECMDGOALS), mostlyclean)
ifneq ($(MAKECMDGOALS), clean)
ifneq ($(MAKECMDGOALS), realclean)
ifneq ($(MAKECMDGOALS), targets)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new target 'target' should also have it's line here : ifneq ($(MAKECMDGOALS), target)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

ifneq ($(MAKECMDGOALS), makdep)
ifneq ($(MAKECMDGOALS), depends)
-include $(DEPS)
endif
endif
endif
endif
endif
endif
endif
endif
92 changes: 81 additions & 11 deletions configuration/scripts/cice.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,31 @@
# If the cice binary is passed as an argument and the file exists,
# copy it into the run directory and don't build the model.

set dohelp = 0
set directmake = 0
set target = "UnDEFineD"
set ciceexe = "UnDEFineD"
if ($#argv == 1) then
set ciceexe = $1
if ($#argv == 0) then
# continue, standard way to build
else if ($#argv == 1) then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the argument checking is too drastic; it prevents one from using all the features of make (ex. see https://www.gnu.org/software/make/manual/make.html#Instead-of-Execution where some flags that are supported by make are listed). This is one of the reason I passed all arguments in my initial implementation ($*). I suggest that we check if the first argument is '--exe', '-h' or '--help' but apart from that we pass all other arguments to make. This way we can use an arbitrary number of make flags, both when using cice.build or cice.build target

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let me see what I can do. I didn't think about passing command line arguments directly to gmake and wanted to keep the parsing simple. But I can see what that might be useful, I will try to refactor. Thanks for the careful review, not too picky at all!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phil-blain, what do you think the requirements are here? Is it just

cice.build # standard approach
cice.build -h
cice.build target # our makefile targets
cice.build [gmake option] # gmake options, one flag only
cice.build --exe filename

or is there also a requirement for

cice.build [gmake option] [gmake option] ... [target]

and so forth. Should we support gmake arguments with and/or without a target like

gmake --debug --keep-going
gmake --debug cice
gmake --silent --keep-going cice

and others as well? It seems to me if we are going to allow the ability to pass the gmake arguments from cice.build to gmake, it needs to be general, support multiple arguments, and work with a target as well. I will try to do that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've got it working, we definitely want the most flexibility and I think that was suggested in the review.

@phil-blain phil-blain Aug 27, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that more flexibility is good, so all of these should work :

cice.build # standard approach
cice.build -h
cice.build target # our makefile targets
cice.build target1 target2 ... # multiple Makefile targets
cice.build [gmake option] [gmake option] [... other options ....] # gmake options
cice.build [gmake option] [gmake option] [[... other options ....] target # gmake options and target
cice.build [gmake option] [gmake option] [[... other options ....] target1 target2 ... # gmake options and multiple targets
cice.build --exe filename

As a side note, with the changes you already made we are now able to call
cice.build ice_dyn_evp.o
to compile a single file. This can be useful sometimes when you are just debugging compilation errors in a single file (This works because all objects file are implicit targets in the Makefile).
Do you think this should be mentioned in the documentation ?

# -h, --help, or target
if ("$1" == "-h" || "$1" == "--help") then
set dohelp = 1
else
set directmake = 1
set target = $1
if ("$target" =~ "-*") then
echo "${0}: ERROR: invalid target ${target} starts with dash"
exit -99
endif
endif
else if ($#argv == 2) then
# --exe ciceexe (undocumented feature, used only in test suites)
if ("$1" != "--exe") then
echo "${0}: ERROR: 2 arguments assume --exe ciceexe"
exit -99
endif
set ciceexe = $2
echo "${0}: ciceexe = ${ciceexe}"
if (-e ${ciceexe}) then

Expand All @@ -25,6 +47,45 @@ if ($#argv == 1) then
exit 0

endif
else
echo "${0}: ERROR in arguments"
set dohelp = 1
endif

if (${dohelp} == 1) then
cat << EOF1

NAME
cice.build [-h,--help] [target]

SYNOPSIS
-h || --help
target

DESCRIPTION
--help, -h : help
target : specify make target, defined in Makefile

EXAMPLES
cice.build
will build the model using the recommended approach with all the bells and whistles
cice.build clean
is an example of a targeted build
cice.build --help
will show cice.build help
cice.build targets
will show valid Makefile targets

ADDITIONAL INFORMATION
The argument implementation is fairly primitive. It accepts only no arguments
(where it builds the default target), a target argument, or a -h||--help
argument. These cannot be mixed.

SEE ALSO
User Documentation at https://github.com/cice-consortium/cice/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to link to read-the-docs here instead ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is what version of readthedocs? Almost certainly whatever version we might link in the help output is incorrect. Master documentation is only correct for the current master. For released versions, would we need to manually change the link for each release? This is a case where it's easy for things to get out of sync. While pointing to the general cice repo isn't particularly useful either, at least I feel like it's never incorrect.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand.


EOF1
exit -99
endif

#====================================
Expand All @@ -47,10 +108,12 @@ set stamp = `date '+%y%m%d-%H%M%S'`
set ICE_BLDLOG_FILE = "cice.bldlog.${stamp}"
set quiet = ${ICE_QUIETMODE}

if (${ICE_CLEANBUILD} == 'true') then
echo "cleaning objdir"
rm -r -f ${ICE_OBJDIR}
endif
# tcraig, this is handled below, is it needed here?
#if (${ICE_CLEANBUILD} == 'true') then
# echo "cleaning objdir"
# rm -r -f ${ICE_OBJDIR}
#endif
if !(-d ${ICE_RUNDIR}) mkdir -p ${ICE_RUNDIR}
if !(-d ${ICE_OBJDIR}) mkdir -p ${ICE_OBJDIR}
cd ${ICE_OBJDIR}

Expand Down Expand Up @@ -79,6 +142,18 @@ ${ICE_SANDBOX}/cicecore/shared
${ICE_SANDBOX}/icepack/columnphysics
EOF

if (${directmake} == 1) then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I would actually put this block just before line if (${ICE_CLEANBUILD} == 'true') then. This way ICE_* variables are always shown, and ICE_MACHINE_BLDTHRDS is defined (the way it is now, the '-j' flag will be passed to Make in all cases, even if the ICE_MACHINE_BLDTHRDS variable is not defined, and Make will use all threads available on the machine (I've read this can impact performance...)
  • Also, I think that in the 'directmake ' case we should still write to the build log file with ... |& tee ${ICE_BLDLOG_FILE}. This way we can also trap circular dependencies in that case. (Maybe we should also respect the ICE_QUIETMODE variable, though I personally don't care for that one)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I am making those changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the second point, I think we decided for a direct make to avoid all the fluff. I think writing the make output to a bldlog file is part of that. I guess I view the circular dependencies as part of the fluff you get if you use the scripts the standard way. Also, the quietmode should not generally be used except by travis. For whatever reason, if we don't use the quiet mode with travis, it creates problems. it either concatenates the raw log file or it makes it very hard to find the errors. this was added just for travis and serves a purpose.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I guess I viewed the 'fluff' as only the README.case file. But I don't feel strongly about that. So either way is fine.
Regarding quietmode, I didn't know the history, I thought it predated our Git/GitHub migration.

echo "make ${target}"
${ICE_MACHINE_MAKE} -j ${ICE_MACHINE_BLDTHRDS} VPFILE=Filepath EXEC=${ICE_RUNDIR}/cice \
-f ${ICE_CASEDIR}/Makefile MACFILE=${ICE_CASEDIR}/Macros.${ICE_MACHCOMP} ${target}
set bldstat = ${status}
if (${bldstat} != 0) then
echo "${0}: targeted make FAILED"
exit -99
endif
exit 0
endif

echo " "
echo ICE_GRID = ${ICE_GRID}
echo ICE_NTASK = ${ICE_NTASKS}
Expand All @@ -88,13 +163,8 @@ echo "Filepath = "
cat ${ICE_OBJDIR}/Filepath
echo " "

echo "building makdep"
${ICE_MACHINE_MAKE} \
-f ${ICE_CASEDIR}/Makefile MACFILE=${ICE_CASEDIR}/Macros.${ICE_MACHCOMP} makdep || exit 2

echo "building cice > ${ICE_OBJDIR}/${ICE_BLDLOG_FILE}"

if !(-d ${ICE_RUNDIR}) mkdir -p ${ICE_RUNDIR}
if !($?ICE_MACHINE_BLDTHRDS) then
set ICE_MACHINE_BLDTHRDS = 1
endif
Expand Down
49 changes: 47 additions & 2 deletions doc/source/user_guide/ug_running.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Once a case/test is created, several files are placed in the case directory
- **makdep.c** is a tool that will automatically generate the make dependencies
- **Macros.[machine]** defines the Makefile macros
- **Makefile** is the makefile used to build the model
- **cice.build** is a script that builds and compiles the model
- **cice.build** is a script that calls the Makefile and compiles the model
- **ice\_in** is the namelist input file
- **setup\_run\_dirs.csh** is a script that will create the run directories. This will be called automatically from the **cice.run** script if the user does not invoke it.
- **cice.run** is a batch run script
Expand Down Expand Up @@ -96,7 +96,7 @@ case directory, NOT the run directory.

.. _case_options:

Command Line Options
**cice.setup** Command Line Options
~~~~~~~~~~~~~~~~~~~~

``cice.setup -h`` provides a summary of the command line options. There are three different modes, ``--case``, ``--test``, and ``--suite``. This section provides details about the relevant options for setting up cases with examples.
Expand Down Expand Up @@ -202,6 +202,51 @@ To add some optional settings, one might do::

Once the cases are created, users are free to modify the cice.settings and ice_in namelist to further modify their setup.

.. _cicebuild:

More about **cice.build**
~~~~~~~~~~~~~~~~~~~~~~~~~~

**cice.build** is copied into the case directory and should be run interactively from the
case directory to build the model. The standard and recommendeded way to run is with
no arguments,

cice.build

However, **cice.build** does support a couple of argument options.

cice.build [-h|--help]

provides a summary of the usage.
Basically, **cice.build** can be run with a single target argument. When run in this
mode, some of the features of the CICE scripts are turned off. You can see all the
possible targets by executing

cice.build targets

To build the model, try

cice.build cice

or

cice.build all

These commands are largely equivalent to running **cice.build** without an argument,
although as noted earlier, some of the cice script functions are turned off. Clean
options include

cice.build [mostlyclean|clean|reallyclean]

to write out information about the Makefile setup,

cice.build [db_files|db_flags]

and to build the makdep tool or the dependencies,

cice.build [makdep|depends]


.. _porting:

Porting
Expand Down