Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1f88399
Object files in obj
rs028 Jul 10, 2025
8b111c1
Force shared library to configuration dir
rs028 Jul 10, 2025
f241b08
Fix long lines and indentation
rs028 Jul 10, 2025
84ccca3
Save logfiles for debugging
rs028 Jul 12, 2025
d4f1cae
Save logfiles for debugging
rs028 Jul 12, 2025
b3f6ad2
Save logfiles for debugging
rs028 Jul 12, 2025
a39855e
Revert argparse changes
rs028 Jul 14, 2025
c8ff01e
fix compilation of sharedlib
rs028 Jul 15, 2025
4212156
Adjust indentation
rs028 Jul 15, 2025
645b82b
Make build process more robust
rs028 Jul 15, 2025
a01eb8b
Source files order
rs028 Jul 15, 2025
f5af0c2
Add missing line break
rs028 Jul 15, 2025
8704cef
Use .gitkeep to simplify .gitignore files, add model/include dir
rs028 Oct 7, 2025
9d1e69b
move generated mechanism files to model/include
rs028 Oct 7, 2025
463eaf3
Move include/ into configuration/
rs028 Oct 9, 2025
f61a9c5
Generated mechanism files go to configuration/include
rs028 Oct 10, 2025
967ec64
Move test files to include
rs028 Oct 14, 2025
d50c544
Correct paths in old tests
rs028 Oct 14, 2025
1cfa05f
Upload test log files
rs028 Oct 14, 2025
3f1cc4f
Correct paths in model tests
rs028 Oct 14, 2025
c01a900
Correct tests out files
rs028 Oct 14, 2025
bdc3101
Correct model tests out files
rs028 Oct 14, 2025
3a575d4
Correct output message in tests
rs028 Oct 14, 2025
4793979
Check actions run numbers
rs028 Oct 14, 2025
9293265
Check actions run numbers
rs028 Oct 14, 2025
1a897ea
Assign unique names to logfiles
rs028 Oct 14, 2025
d5ae918
Correcr obj dir in Makefile
rs028 Oct 22, 2025
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
18 changes: 14 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ jobs:
# -------------------------------------------------------------
# (3) Install the AtChem2 dependencies: CVODE, openlibm, numdiff, FRUIT
#
# NB: Ruby v3.2 does not work with the current version of FRUIT,
# so v3.0 is used here as a temporary fix
# NB: the current version of FRUIT (v3.4.3) does not work with the most
# recent versions of Ruby; as a temporary fix, Ruby v3.0 is used for
# all unit tests in this workflow
#
# ACTION: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby

Expand Down Expand Up @@ -134,8 +135,10 @@ jobs:
fi

# -------------------------------------------------------------
# (5) Run the Testsuite using the standard compilation flags and
# the default model settings
# (5) Run the Testsuite using the standard compilation flags and the
# default model settings, then upload the log files as artifacts
#
# ACTION: https://github.com/marketplace/actions/upload-a-build-artifact

- name: Indent and Style tests
run: |
Expand All @@ -145,12 +148,19 @@ jobs:
- name: Unit and Model tests
env:
FORT_VERSION: ${{ matrix.fortran }}
# continue-on-error: true
run: |
export PATH=$PATH:$PWD/numdiff/bin
make unittests
make oldtests # NB: oldtests will eventually be merged into modeltests
make modeltests

- name: Save log files
uses: actions/upload-artifact@v4
with:
name: testsuite_${{ matrix.os }}_fortran-${{ matrix.fortran }}.log
path: tests/*.log

# -------------------------------------------------------------
# (6) Recompile AtChem2 using the code coverage compilation flags,
# run the Testsuite and upload the gcov files to Codecov
Expand Down
94 changes: 58 additions & 36 deletions build/build_atchem2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,77 @@
# -----------------------------------------------------------------------------

# -----------------------------------------------------------------------------
# Script to process the mechanism file (*.fac) and convert it to the
# correct format for AtChem2.
# Script to build and compile AtChem2.
#
# $1 is the location of the chemical mechanism file in FACSIMILE
# format. Argument $1 is NOT optional, and there is no default.
# `$1` is the chemical mechanism file in FACSIMILE or KPP format.
# Argument `$1` is NOT optional, and there is no default.
#
# $2 is the directory for the chemical mechanism in Fortran format:
# - mechanism.species
# - mechanism.reac
# - mechanism.prod
# - mechanism.ro2
# - mechanism.f90
# By default, argument $2 is: ./model/configuration/
# `$2` is the model comfiguration directory, which contanins:
# - the model configuration files (`*.config` and `*.parameters`)
# - the subdirectory `include/` for the chemical mechanism in Fortran
# format (`mechanism.*`) and the pre-compiled mechanism shared
# library (`mechanism.so`).
# By default, argument `$2` is: ./model/configuration/
#
# $3 is the directory of the MCM data files:
# - list of organic peroxy radicals (RO2)
# - parameters to calculate photolysis rates
# By default, argument $3 is: ./mcm/
# `$3` is the directory of the MCM data files, which contains:
# - the reference list of organic peroxy radicals (RO2)
# - the empirical parameters to calculate photolysis rates
# By default, argument `$3` is: ./mcm/
#
# Usage:
# ./build/build_atchem2.sh /path/to/mechanism/file
# OR
# ./build/build_atchem2.sh /path/to/mechanism/file /path/to/mechanism/directory
# -----------------------------------------------------------------------------
set -eu

echo ""
echo " AtChem2 v1.3-dev"
echo ""
printf "\n--> Building AtChem2...\n"

echo "* Chemical mechanism file:" $1
echo "* Fortran mechanism directory [ default = ./model/configuration/ ]:" $2
echo "* MCM data files directory [ default = ./mcm/ ]:" $3
# set chemical mechanism file (argument `$1`)
if [ -z "$1" ] ; then
printf "\n[INPUT ERROR] Missing argument: chemical mechanism file (.fac/.kpp).\n"
exit 1
else
MECHF="$1"
if [ ! -f "$MECHF" ]; then
printf "\n[INPUT ERROR] The chemical mechanism file does not exist.\n"
exit 1
else
printf "\n[*] Chemical mechanism file: %s\n" "$MECHF"
fi
fi

echo ""
echo "-> Call mech_converter.py"
python ./build/mech_converter.py $1 $2 $3
# set model configuration directory (argument `$2`)
CONFIGD="${2:-./model/configuration/}"
printf "\n[*] Model configuration directory: %s\n" "$CONFIGD"
if [ ! -d "$CONFIGD" ]; then
printf "\n[INPUT ERROR] The model configuration directory does not exist.\n"
exit 1
fi

echo ""
echo "-> Create shared library"
if [ -z $2 ]; then
make sharedlib
echo "=> shared library created in: ./model/configuration/"
else
make sharedlib SHAREDLIBDIR=$2
echo "=> shared library created in:" $2
# set MCM data directory (argument `$3`)
MCMV="${3:-./mcm/}"
printf "\n[*] MCM data directory: %s\n" "$MCMV"
if [ ! -d "$MCMV" ]; then
printf "\n[INPUT ERROR] The MCM data directory does not exist.\n"
exit 1
fi

echo ""
echo "-> Create atchem2 executable"
make
echo ""
# compile chemical mechanism shared library (`mechanism.so`)
printf "\n--> Compiling shared library...\n"
make sharedlib MECHFILE="$MECHF" CONFIGDIR="$CONFIGD" MCMDIR="$MCMV"
if [ $? -ne 0 ] ; then
printf "\n[FAIL] Check output above for details.\n"
exit 1
fi

# compile atchem executable
printf "\n--> Compiling atchem executable...\n"
make -j
if [ $? -ne 0 ] ; then
printf "\n[FAIL] Check output above for details.\n"
exit 1
fi

printf "\n--> AtChem2 build process successfully completed!\n"
exit 0
33 changes: 18 additions & 15 deletions build/mech_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# This script converts a chemical mechanism file -- in FACSIMILE (.fac)
# or KPP (.kpp) format -- into the Fortran-compatible format used by
# AtChem2. The script generates 5 files in the model configuration
# directory:
# `include/` directory:
#
# - mechanism.species
# - mechanism.reac
Expand Down Expand Up @@ -149,7 +149,7 @@ def separate_stoichiometry(input_species):
format: '{input_species}'. Note that species names should
not begin with numerical characters.""")

def convert_to_fortran(input_file, mech_dir, mcm_vers):
def convert_to_fortran(input_file, conf_dir, mcm_vers):
"""
This function converts a chemical mechanism file into the
Fortran-compatible format used by the AtChem2 ODE solver. The
Expand All @@ -161,36 +161,37 @@ def convert_to_fortran(input_file, mech_dir, mcm_vers):
an ID number.

* The equations defined in sections 'Generic Rate Coefficients'
and 'Complex reactions' go to the mechanism.f90 file with little
and 'Complex reactions' go to the `mechanism.f90` file with little
more than formatting changes -- each line is replicated in full,
with each named rate converted to an element in vector q.

* The reaction rates defined in section 'Reaction definitions' go
to the mechanism.f90 file as elements of vector p.
to the `mechanism.f90` file as elements of vector p.

* The species involved as reactants (respectively products) in the
reactions in section 'Reaction definitions' are split up into
individual species, and the species and reactions ID numbers go
to mechanism.reac (respectively mechanism.prod). Combining
mechanism.reac, mechanism.prod and the last section of
mechanism.f90 gives the original information contained in
to `mechanism.reac` (respectively `mechanism.prod`). Combining
`mechanism.reac`, `mechanism.prod` and the last section of
`mechanism.f90` gives the original information contained in
section 'Reaction definitions' of the .fac file, but in a
format that AtChem2 can parse.

* The ID numbers and names of all species in the chemical
mechanism go to the mechanism.species file.
mechanism go to the `mechanism.species` file.

* The ID numbers and names of all RO2 species in section 'Peroxy
radicals' go to the mechanism.ro2 file.
radicals' go to the `mechanism.ro2` file.

Args:
input_file (str): relative or absolute reference to the .fac file
mech_dir (str): relative or absolute reference to the directory where
the mechanism.* files will be created, and where
the environmentVariables.config file should be read from
conf_dir (str): relative or absolute reference to the configuration
directory where the mechanism.* files will be created
(inside the `include/` subdirectory), and where the
`environmentVariables.config` file should be read from
By default it is: model/configuration/
mcm_vers (str): relative or absolute reference to the directory containing
the reference list of RO2 species (peroxy-radicals_v*)
the reference list of RO2 species (`peroxy-radicals_v*`)
By default it is: mcm/
"""

Expand All @@ -203,6 +204,8 @@ def convert_to_fortran(input_file, mech_dir, mcm_vers):
'The input file ' + str(input_path) + ' does not exist.'
print('Chemical mechanism file in:', input_directory)

mech_dir = os.path.join(conf_dir, 'include/')

# Check if the chemical mechanism file is in KPP format, in which case convert it
# to FACSIMILE format (see documentation of `kpp_conversion.py` for more info)
if input_filename.split('.')[-1] == 'kpp':
Expand Down Expand Up @@ -290,7 +293,7 @@ def convert_to_fortran(input_file, mech_dir, mcm_vers):

# Check the DILUTE environment variable to identify whether dilution should be applied.
dilute = False
with open(mech_dir + '/environmentVariables.config') as env_var_file:
with open(conf_dir + '/environmentVariables.config') as env_var_file:
environmentVariables = env_var_file.readlines()
for x in environmentVariables:
x = x.split()
Expand All @@ -304,7 +307,7 @@ def convert_to_fortran(input_file, mech_dir, mcm_vers):
# Read in the names of user-defined custom rate functions and add them
# to the list of reserved names so that they will be carried through the
# rate definitions (in a similar manner to LOG10)
with open(mech_dir + '/customRateFuncs.f90') as custom_func_file:
with open(conf_dir + '/customRateFuncs.f90') as custom_func_file:
func_def_pat = r'function +([a-zA-Z0-9_]*) *\('
custom_func_names = re.findall(func_def_pat, custom_func_file.read(), re.I)

Expand Down
9 changes: 7 additions & 2 deletions model/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Ignore auto-generated mechanism files and output files in the model/ directory
configuration/mechanism.*
configuration/customRateFuncs.o
constraints/environment/*
constraints/photolysis/*
constraints/species/*
configuration/include/*
output/*.output
output/*.pdf
output/reactionRates/*

!.gitkeep
5 changes: 0 additions & 5 deletions model/constraints/environment/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions model/constraints/photolysis/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions model/constraints/species/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions model/output/reactionRates/.gitignore

This file was deleted.

3 changes: 2 additions & 1 deletion obj/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Ignore fortran module files in the obj/ directory
# Ignore fortran object and module files in the obj/ directory
*.o
*.mod
60 changes: 35 additions & 25 deletions src/argparse.f90
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ module argparse_mod
end type flag

! Arguments for the atchem2 executable
type(flag), parameter :: valid_flags(10) = &
[ flag('--help', 'Displays this help message.'), &
type(flag), parameter :: valid_flags(9) = &
[ flag('--help', 'Displays the help message.'), &
flag('--model', 'The base directory of the model.'), &
flag('--output', 'The destination directory for output.'), &
flag('--configuration', 'The directory of the model configuration.'), &
flag('--constraints', 'The base directory of constraints. ' // &
'This typically contains 3 subdirectories: environment, photolysis, and species.'), &
flag('--env_constraints', 'The directory containing environment constraints data.'), &
flag('--photo_constraints', 'The directory containing photolysis constraints data.'), &
flag('--spec_constraints', 'The directory containing species constraints data.'), &
flag('--mcm', 'The directory containing the MCM data files.'), &
flag('--shared_lib', 'The full path to the mechanism.so shared library ' // &
'(generated by ./build/build_atchem2.sh).') ]
flag('--output', 'The destination directory for output. ' // &
'Contains one subdirectory: reactionRates.'), &
flag('--configuration', 'The directory for the model configuration. ' // &
'Contains the shared library: mechanism.so.'), &
flag('--constraints', 'The base directory of the model constraints. ' // &
'Contains 3 subdirectories: environment, photolysis, and species.'), &
flag('--env_constraints', 'The directory containing the environment constraints data.'), &
flag('--photo_constraints', 'The directory containing the photolysis constraints data.'), &
flag('--spec_constraints', 'The directory containing the species constraints data.'), &
flag('--mcm', 'The directory containing the MCM data files.') ]

contains

Expand Down Expand Up @@ -67,13 +67,13 @@ subroutine print_help()
write(*,*) 'In essence, the directories default to sit in the following tree.'
write(*,*) 'Modification via the input parameters cascades to lower directories, but is overwritten by explicit input.'
write(*,*)
write(*,*) ' +--------------------+--------------------+'
write(*,*) ' | | |'
write(*,*) ' model_dir mcm_dir shared_lib_dir'
write(*,*) ' +--------------------+'
write(*,*) ' | |'
write(*,*) ' model_dir mcm_dir'
write(*,*) ' | '
write(*,*) ' +--------------------------------+--------------------------------+'
write(*,*) ' | | |'
write(*,*) ' output_dir constraints_dir configuration_dir'
write(*,*) ' output_dir constraints_dir configuration_dir'
write(*,*) ' |'
write(*,*) ' +------------------------+------------------------+'
write(*,*) ' | | |'
Expand Down Expand Up @@ -270,16 +270,25 @@ subroutine get_and_set_directories_from_command_arguments()

! set each of the directory locations from the command-line, following the
! defined logic for defaults if some are not supplied
model_dir = read_value_or_default( valid_flags(2)%flag_switch, 'model', names, values )
output_dir = read_value_or_default( valid_flags(3)%flag_switch, trim(model_dir)//'/output', names, values )
model_dir = read_value_or_default( valid_flags(2)%flag_switch, &
'model', names, values )
output_dir = read_value_or_default( valid_flags(3)%flag_switch, &
trim(model_dir)//'/output', names, values )
reactionRates_dir = trim(output_dir)//'/reactionRates'
configuration_dir = read_value_or_default( valid_flags(4)%flag_switch, trim(model_dir)//'/configuration', names, values )
constraints_dir = read_value_or_default( valid_flags(5)%flag_switch, trim(model_dir)//'/constraints', names, values )
env_constraints_dir = read_value_or_default( valid_flags(6)%flag_switch, trim(constraints_dir)//'/environment', names, values )
photo_constraints_dir = read_value_or_default( valid_flags(7)%flag_switch, trim(constraints_dir)//'/photolysis', names, values )
spec_constraints_dir = read_value_or_default( valid_flags(8)%flag_switch, trim(constraints_dir)//'/species', names, values )
mcm_dir = read_value_or_default( valid_flags(9)%flag_switch, 'mcm', names, values )
shared_library = read_value_or_default( valid_flags(10)%flag_switch, 'model/configuration/mechanism.so', names, values )
configuration_dir = read_value_or_default( valid_flags(4)%flag_switch, &
trim(model_dir)//'/configuration', names, values )
constraints_dir = read_value_or_default( valid_flags(5)%flag_switch, &
trim(model_dir)//'/constraints', names, values )
env_constraints_dir = read_value_or_default( valid_flags(6)%flag_switch, &
trim(constraints_dir)//'/environment', names, values )
photo_constraints_dir = read_value_or_default( valid_flags(7)%flag_switch, &
trim(constraints_dir)//'/photolysis', names, values )
spec_constraints_dir = read_value_or_default( valid_flags(8)%flag_switch, &
trim(constraints_dir)//'/species', names, values )
mcm_dir = read_value_or_default( valid_flags(9)%flag_switch, &
'mcm', names, values )
mechanism_dir = trim(configuration_dir)//'/include'
shared_library = trim(mechanism_dir)//'/mechanism.so'

write (*, '(2A)') ' Model directory is: ', trim( model_dir )
write (*, '(2A)') ' Output directory is: ', trim( output_dir )
Expand All @@ -290,6 +299,7 @@ subroutine get_and_set_directories_from_command_arguments()
write (*, '(2A)') ' Photolysis Constraints directory is: ', trim( photo_constraints_dir )
write (*, '(2A)') ' Species Constraints directory is: ', trim( spec_constraints_dir )
write (*, '(2A)') ' MCM directory is: ', trim( mcm_dir )
write (*, '(2A)') ' Mechanism directory is: ', trim( mechanism_dir )
write (*, '(2A)') ' Shared library is: ', trim( shared_library )

end subroutine get_and_set_directories_from_command_arguments
Expand Down
3 changes: 2 additions & 1 deletion src/dataStructures.f90
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ module directories_mod
character(len=maxFilepathLength) :: model_dir, output_dir, reactionRates_dir, &
configuration_dir, mcm_dir, shared_library, &
constraints_dir, spec_constraints_dir, &
env_constraints_dir, photo_constraints_dir
env_constraints_dir, photo_constraints_dir, &
mechanism_dir

end module directories_mod

Expand Down
Loading