Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate MPAS build infrastructure with CIME #245

Merged
merged 12 commits into from
Jan 25, 2024
Merged
51 changes: 51 additions & 0 deletions cime_config/buildlib
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,57 @@ def _build_cam():
_LOGGER.info("%s: \n\n output:\n %s \n\n err:\n\n%s\n", cmd, out, err)
expect(retcode == 0, f"Command {cmd} failed with rc={retcode}")

# If dynamical core is MPAS, build it after CAM due to dependencies.
if dycore == "mpas":
_build_mpas(case)

def _build_mpas(case: Case) -> None:
"""
Build MPAS by invoking its build infrastructure.
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
"""

case_root = os.path.normpath(case.get_value("CASEROOT"))
atm_src_root = os.path.normpath(case.get_value("COMP_ROOT_DIR_ATM"))
atm_bld_root = os.path.normpath(os.path.join(case.get_value("EXEROOT"), "atm", "obj"))
lib_root = os.path.normpath(os.path.join(case.get_value("EXEROOT"), "lib"))

gmake = case.get_value("GMAKE")
gmake_j = case.get_value("GMAKE_J")
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved

mpas_dycore_src_root = os.path.join(atm_src_root, "src", "dynamics", "mpas", "dycore", "src")
mpas_dycore_bld_root = os.path.join(atm_bld_root, "mpas")

# Make sure `mpas_dycore_src_root` exists. If not, it is likely that `./manage_externals/checkout_externals` did not succeed.
if os.path.isfile(mpas_dycore_src_root):
raise FileExistsError(1, "Unexpected file", mpas_dycore_src_root)

if not os.path.isdir(mpas_dycore_src_root):
raise FileNotFoundError(1, "No such directory", mpas_dycore_src_root)

# MPAS supports "in-source" build only. Copy source code to `mpas_dycore_bld_root` to avoid polluting `mpas_dycore_src_root`.
if os.path.isfile(mpas_dycore_bld_root):
raise FileExistsError(1, "Unexpected file", mpas_dycore_bld_root)

if not os.path.isdir(mpas_dycore_bld_root):
shutil.copytree(mpas_dycore_src_root, mpas_dycore_bld_root)
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
shutil.copy2(os.path.normpath(os.path.join(mpas_dycore_src_root, "../../Makefile.in.CESM")), os.path.join(mpas_dycore_bld_root, "Makefile.in.CESM"))
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved

# Invoke makefile target `libmpas-prepare`.
mpas_dycore_make_command = f'{gmake} -C {mpas_dycore_bld_root} libmpas-prepare ESM="CESM" CASEROOT="{case_root}" LIBROOT="{lib_root}" '
mpas_dycore_make_command += f'FCINCLUDES="-I{atm_bld_root}"'

(sta, out, err) = run_cmd(mpas_dycore_make_command, from_dir=mpas_dycore_bld_root)
_LOGGER.info("* Command %s:\n\n Output:\n%s\n\n Error:\n%s\n\n", mpas_dycore_make_command, out, err)
expect(sta == 0, f"Command {mpas_dycore_make_command} failed with status {sta}")

# Invoke makefile target `libmpas-build`.
mpas_dycore_make_command = f'{gmake} -C {mpas_dycore_bld_root} -j {gmake_j} libmpas-build ESM="CESM" CASEROOT="{case_root}" LIBROOT="{lib_root}" '
mpas_dycore_make_command += f'FCINCLUDES="-I{atm_bld_root}"'

(sta, out, err) = run_cmd(mpas_dycore_make_command, from_dir=mpas_dycore_bld_root)
_LOGGER.info("* Command %s:\n\n Output:\n%s\n\n Error:\n%s\n\n", mpas_dycore_make_command, out, err)
expect(sta == 0, f"Command {mpas_dycore_make_command} failed with status {sta}")
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved

###############################################################################

if __name__ == "__main__":
Expand Down
12 changes: 7 additions & 5 deletions cime_config/config_component.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@

<entry id="CAM_DYCORE">
<type>char</type>
<valid_values>eul,fv,se,none</valid_values>
<valid_values>eul,fv,mpasa,se,none</valid_values>
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
<default_value>fv</default_value>
<values match="last">
<value grid="a%T[1-9]" >eul</value>
<value grid="a%T[1-9]">eul</value>
<value grid="a%mpasa[0-9]+">mpasa</value>
<value grid="a%ne[0-9]">se</value>
</values>
<group>build_component_cam</group>
Expand Down Expand Up @@ -303,11 +304,12 @@

<entry id="CAM_LINKED_LIBS">
<type>char</type>
<valid_values></valid_values>
<valid_values>-lmpas</valid_values>
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
<default_value>-lmusica -ljsonfortran</default_value>
<values match="last">
<!--Turn off for physics testbed -->
<value compset="_CAM%PHYSTEST"> </value>
<!-- Turn off for physics testbed -->
<value compset="_CAM%PHYSTEST"></value>
<value grid="a%mpasa[0-9]+">-lmpas</value>
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
</values>
<group>build_component_cam</group>
<file>env_build.xml</file>
Expand Down
110 changes: 110 additions & 0 deletions src/dynamics/mpas/Makefile.in.CESM
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
ifeq ($(strip $(CASEROOT)),)
$(warning `CASEROOT` should not be empty. Defaulting to `.`)

CASEROOT = .
endif

ifeq ($(strip $(LIBROOT)),)
$(warning `LIBROOT` should not be empty. Defaulting to `..`)

LIBROOT = ..
endif

#
# Define and export variables used by MPAS build infrastructure.
#

export CP = cp -afv
export RM = rm -frv

# Constants.
export AUTOCLEAN = false
export BUILD_TARGET = N/A
export CORE = atmosphere
export EXE_NAME = atmosphere_model
export GEN_F90 = false
export GIT_VERSION = N/A
export NAMELIST_SUFFIX = atmosphere

# Read variables (e.g., build options) from `Macros.make`.
include $(CASEROOT)/Macros.make

# Translate variables (e.g., build options) from `Macros.make` to their equivalent ones used by MPAS build infrastructure.
export AR := ar
export ARFLAGS := -M
export CC := $(strip $(MPICC))
export CFLAGS := $(strip $(CFLAGS))
export CPP := cpp -P -traditional
export CPPFLAGS := -D_MPI \
-DMPAS_BUILD_TARGET="$(BUILD_TARGET)" \
-DMPAS_CAM_DYCORE \
-DMPAS_EXE_NAME="$(EXE_NAME)" \
-DMPAS_EXTERNAL_ESMF_LIB \
-DMPAS_GIT_VERSION="$(GIT_VERSION)" \
-DMPAS_NAMELIST_SUFFIX="$(NAMELIST_SUFFIX)" \
-DMPAS_NATIVE_TIMERS \
-DMPAS_NO_ESMF_INIT \
-DMPAS_PIO_SUPPORT \
-DUSE_PIO2
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
export CPPINCLUDES := $(strip $(CPPINCLUDES))
export CXX := $(strip $(MPICXX))
export CXXFLAGS := $(strip $(CXXFLAGS))
export FC := $(strip $(MPIFC))
export FCINCLUDES := $(strip $(FCINCLUDES))
export FFLAGS := $(strip $(FC_AUTO_R8) $(FFLAGS) $(FREEFLAGS))
kuanchihwang marked this conversation as resolved.
Show resolved Hide resolved
export LDFLAGS := $(strip $(LDFLAGS))
export LIBS := $(strip $(LIBS))
export LINKER := $(strip $(MPIFC))
export SCC := $(strip $(SCC))
export SCXX := $(strip $(SCXX))
export SFC := $(strip $(SFC))

#
# Targets.
#

.PHONY: all
all:
@echo 'Supplemental Makefile for MPAS Dynamical Core in CESM'
@echo ''
@echo 'Variables (e.g., build options) will be read from `$${CASEROOT}/Macros.make`.'
@echo 'MPAS will be built as a static library located at `$${LIBROOT}/libmpas.a`.'
@echo ''
@echo 'Usage hints:'
@echo ' `make libmpas-prepare ESM="CESM" CASEROOT="..." LIBROOT="..."`'
@echo ' `make libmpas-build ESM="CESM" CASEROOT="..." LIBROOT="..."`'
@echo ' `make libmpas-clean ESM="CESM" CASEROOT="..." LIBROOT="..."`'

.PHONY: libmpas-prepare
libmpas-prepare: libmpas-archiver-script.txt libmpas-no-physics

# Combine multiple static libraries into `libmpas.a` via archiver/MRI script. This requires GNU or GNU-like archiver (`ar`) program.
libmpas-archiver-script.txt:
@echo "create libmpas.a" > $(@)
@echo "addlib libdycore.a" >> $(@)
@echo "addlib libframework.a" >> $(@)
@echo "addlib libops.a" >> $(@)
@echo "save" >> $(@)
@echo "end" >> $(@)

# Do not use built-in MPAS/WRF physics.
.PHONY: libmpas-no-physics
libmpas-no-physics:
@sed -E -i -e "s/^ *PHYSICS=.+$$/PHYSICS=/g" core_atmosphere/Makefile

.PHONY: libmpas-build
libmpas-build: $(LIBROOT)/libmpas.a

$(LIBROOT)/libmpas.a: libmpas.a
$(CP) $(<) $(@)

libmpas.a: $(AUTOCLEAN_DEPS) dycore externals frame ops
$(AR) $(ARFLAGS) < libmpas-archiver-script.txt

.PHONY: libmpas-clean
libmpas-clean: clean
$(RM) $(LIBROOT)/libmpas.a libmpas.a

.PHONY: externals
externals: $(AUTOCLEAN_DEPS)
( cd external; $(MAKE) FC="$(FC)" SFC="$(SFC)" CC="$(CC)" SCC="$(SCC)" FFLAGS="$(FFLAGS)" CFLAGS="$(CFLAGS)" CPP="$(CPP)" NETCDF="$(NETCDF)" CORE="$(CORE)" ezxml-lib )