diff --git a/.ci-pipelines/ci-common-defs.sh b/.ci-pipelines/ci-common-defs.sh index ef52b61..32f5b25 100755 --- a/.ci-pipelines/ci-common-defs.sh +++ b/.ci-pipelines/ci-common-defs.sh @@ -24,6 +24,7 @@ F90_rosadj F90_ros_autoreduce F90_rosenbrock F90_ros_h211b +F90_ros_passivespc F90_ros_split F90_rostlm F90_ros_upcase @@ -59,8 +60,8 @@ function print_compiler_versions() { "###########################################################################" echo " KPP CONTINUOUS INTEGRATION TESTS, USING THESE COMPILERS:" echo "" - gcc --version - gfortran --version + ${CC} --version + ${FC} --version echo \ "###########################################################################" } diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..91291bf --- /dev/null +++ b/.gitattributes @@ -0,0 +1,45 @@ +# KPP .gitattributes file +# +# Normalizes line endings for text source files (this codebase has +# contributions from multiple organizations and platforms going back +# decades) and marks flex/bison-generated files as generated so they +# are collapsed by default in GitHub diffs/blame. +# +# For info on how .gitattributes rules work, see: +# https://git-scm.com/docs/gitattributes + +# Default: normalize line endings to LF in the repo, let git decide +# checkout behavior based on the platform. +* text=auto eol=lf + +# Source code +*.c text +*.h text +*.f text +*.f90 text +*.F90 text +*.m text +*.kpp text +*.eqn text +*.spc text +*.def text +*.l text +*.y text +Makefile* text +*.sh text eol=lf + +# Docs +*.md text +*.rst text + +# Files generated by flex/bison at build time (see src/Makefile) -- +# hide them from GitHub's diff/blame view by default. +src/lex.yy.c linguist-generated=true +src/y.tab.c linguist-generated=true +src/y.tab.h linguist-generated=true + +# Binary/opaque files: do not attempt line-ending or diff normalization +*.pdf -text binary +*.exe -text binary +*.o -text binary +*.mod -text binary diff --git a/.github/workflows/run-ci-tests.yml b/.github/workflows/run-ci-tests.yml index 66fb966..c547938 100644 --- a/.github/workflows/run-ci-tests.yml +++ b/.github/workflows/run-ci-tests.yml @@ -20,7 +20,7 @@ jobs: KPP_FLEX_LIB_DIR: /usr/lib/x86_64-linux-gnu strategy: matrix: - gcc-version: [9, 10, 11, 12, 13] + gcc-version: [9, 10, 11, 12, 13, 14, 15, 16] name: Run C-I tests with GCC ${{ matrix.gcc-version }} @@ -33,6 +33,10 @@ jobs: - name: Install libraries run: | + sudo grep -rl 'packages.microsoft.com' /etc/apt/sources.list.d/ | xargs -r sudo rm -f + sudo apt update -y + sudo apt install -y software-properties-common + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt update -y sudo apt install -y flex bison libfl-dev sudo apt install -y gcc-${{ matrix.gcc-version }} g++-${{ matrix.gcc-version }} gfortran-${{ matrix.gcc-version }} diff --git a/.gitignore b/.gitignore index 25826a2..abc0c12 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ **/*~ **/.\#* **/\#* +**/.DS_Store # Ignore files generated by bison (in src/) /src/lex.yy.c @@ -31,6 +32,9 @@ /ci-tests/**/*results* /ci-tests/**/*.csv +# Ignore byte-compiled emacs lisp files +/site-lisp/*.elc + # Ignore files generated by KPP (everywhere) **/*_Function* **/*_Global* @@ -73,4 +77,4 @@ docs/build/* !/util/Makefile* # ReadTheDocs -docs/_build/* \ No newline at end of file +docs/_build/* diff --git a/.readthedocs.yaml b/.readthedocs.yaml index eb05e5c..10d20eb 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -14,10 +14,8 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.12" - nodejs: "14" - rust: "1.55" - golang: "1.17" + python: "3.13" + nodejs: "24" # Build documentation in the docs/ directory with Sphinx sphinx: diff --git a/CHANGELOG.md b/CHANGELOG.md index aef3332..be6d42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.5.0] - 2026-07-09 +### Added +- Added function `F90_FunctionBeginNoArgDecl` in `src/code_f90.c` with corresponding function prototypes in `src/code.c` and `src/code.h` +- Added macro `DefElmO` in `src/code.h`, which writes a scalar F90 variable with the `OPTIONAL` attribute +- Added code to `src/gen.c` to add `NonPassiveSpc_Count` and `NonPassiveSpc_Indices` to `ROOT_Global` (only for F90) +- Added code to `src/gen.c` to filter out passive species if the `PassiveSpc_ATOL_Threshold` optioal argument is passed to `ROOT_Initialize` (F90-only) +- Added GCC 14, 15, and 16 to the list of compilers used to run C-I tests in GitHub Actions +- Added `F90_ros_passivespc` C-I test to validate filtering out of passive species +- Added `drv/general_passivespc.f90` driver program, which passes optional `PassiveSpc_ATOL_Threshold` argument to `ROOT_Initialize` +- Added documentation about excluding passive species to ReadTheDocs +- Added `.gitattributes`, `CLAUDE.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md` + +### Changed +- Updated `Makefile.defs` and `util/Makefile*` to look for the value of `CC` or `FC` from the shell before explicitly setting it +- Updated documentation about forcing MacOSX to prefer GNU compilers over Clang +- Updated `Makefile.defs` with robust cross-architecture code +- Updated the C-I test function `print_compiler_versions` to display the proper compiler info +- Initialized `Hacc` and `ErrOld` variables to `ZERO` in `int/runge_kutta.c`, to avoid compiler warnings +- Updated all `int/rosenbrock*.f90` integrators to use `NonPassiveSpc_Count` and `NonPassiveSpc_Indices` to exclude passive species from the error norm calculation +- Split ReadTheDocs documentation files into smaller files and reorganized folders in `docs/source` + +### Fixed +- Fixed several emacs font-lock issues in `site-lisp/kpp.el` +- Fixed `src/gen.c` to avoid generating an uninitialized variable compiler warning + +### Removed +- Removed references to unneccessary `azure-cli` and `microsoft-prod` packages in `.github/workflows/run-ci-tests.yml` + ## [3.4.0] - 2026-04-29 ### Added - Added `Rodas3_1` integration method (with updated coefficents by @msl3v) to `rosenbrock_autoreduce.f90`, `rosenbrock.{c,f90,m}`, `rosenbrock_adj.{c,f90}`, `rosenbrock_tlm.f90` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..299963b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,153 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repository is + +KPP (Kinetic PreProcessor) is a source-code generator (written in C, built +with flex/bison) for chemical kinetics simulations. Given a chemical +mechanism description written in the KPP domain-specific language +(`.kpp`, `.spc`, `.eqn`, `.def` files), the `kpp` executable generates +standalone simulation code in Fortran90, C, or Matlab: ODE +function/Jacobian/Hessian evaluation, sparse-matrix data structures, a +numerical integrator, and a driver program. + +KPP itself is not a chemistry solver — it is a compiler whose target +languages are Fortran90/C/Matlab and whose output is a complete, +compilable box-model simulation. + +## Build + +```bash +export KPP_HOME=/home/bob/repos/KPP3 +export PATH=$PATH:$KPP_HOME/bin +export KPP_FLEX_LIB_DIR=/usr/lib # wherever libfl.a/libfl.so lives + +cd $KPP_HOME/src +make clean # remove *.o (optional, only needed after a prior build) +make distclean # also remove bin/kpp (optional) +make # builds bin/kpp via gcc + flex + bison +``` + +Requires `gcc`, `flex`, `bison`, and `sed` on the PATH. Compiler/flags are +configured in `src/Makefile.defs` (defaults to `gcc`; honors `CC`/`FC` +from the shell environment if set). On macOS, `gcc` is aliased to +`clang` by default — see `docs/source/getting_started/installation.rst` +for the Homebrew GCC workaround, the flex-library-path workaround, and +the stack-size (`ulimit -s`) requirement. + +`kpp` must be invoked with `KPP_HOME` set, since it looks up +`$KPP_HOME/models`, `$KPP_HOME/int`, and `$KPP_HOME/drv` by default +(overridable via `KPP_MODEL`, `KPP_INT`, `KPP_DRV`). + +## Running a single mechanism through KPP + +```bash +cd ci-tests/F90_small_strato +$KPP_HOME/bin/kpp F90_small_strato.kpp +make -f Makefile_F90_small_strato COMPILER=GFORTRAN +./F90_small_strato.exe +``` + +This generates `_Function.f90`, `_Jacobian*.f90`, +`_Global.f90`, `_Parameters.f90`, `_Rates.f90`, +`_Initialize.f90`, `_Integrator.f90`, `_Main.f90`, +etc., named after the `ROOT` in `#DRIVER`/model name. + +## Tests (C-I tests) + +There is no unit test framework — correctness is verified end-to-end by +generating code for real mechanisms, compiling, and running a box-model +simulation. Requires `bin/kpp` to be built first. + +```bash +# Run the full C-I test suite (all mechanism/integrator/language combos) +$KPP_HOME/.ci-pipelines/ci-testing-script.sh | tee ci-tests.log + +# Remove compiler-generated files from all C-I test folders afterward +$KPP_HOME/.ci-pipelines/ci-cleanup-script.sh +``` + +To run/inspect a single C-I test, see "Running a single mechanism" +above — each subdirectory of `ci-tests/` is one test, using the naming +convention `_` (e.g. `F90_rosadj`, `C_sd`). The list +of test directory names to run is maintained in +`GENERAL_TESTS`/`MCM_1`/`MCM_2`/`MINVERSION_TEST` in +`.ci-pipelines/ci-common-defs.sh` — new C-I tests must be added there +or they won't run in CI. GitHub Actions (`.github/workflows/run-ci-tests.yml`) +runs this same script across a matrix of GCC versions (9–16) on every +push/PR. + +## Documentation + +User docs are Sphinx/ReadTheDocs sources under `docs/source/`, built +from `docs/source/conf.py` (see `.readthedocs.yaml`). When changing +behavior (new command, new integrator, new output file), update the +corresponding `.rst` file — `docs/source/input/kpp_commands.rst` for +`#COMMAND` options, `docs/source/output/` for generated-file formats, +`docs/source/num_methods/` for integrators. + +## Architecture + +### Directory roles (each maps to a `KPP_*` search path or a fixed role) + +- `src/` — the KPP program itself (C, flex/bison). Builds `bin/kpp`. +- `bin/` — holds the built `kpp` executable. +- `models/` — chemical mechanism definitions (`.def`/`.eqn`/`.spc`) + usable via `#MODEL`; searched by default, overridable with `KPP_MODEL`. +- `int/` — integrator (numerical solver) templates, one `.def` + + language-specific source (`.f90`/`.c`/`.m`) per integrator, selected + via `#INTEGRATOR`; overridable with `KPP_INT`. `int/user_contributed/` + holds community-contributed integrators. +- `drv/` — driver program templates (the `main`/box-model driver), + selected via `#DRIVER`; overridable with `KPP_DRV`. +- `util/` — per-language function templates (Fortran90/C/Matlab + variants of the same utility) substituted into generated code. +- `examples/` — example `.kpp` mechanism files. +- `ci-tests/` — one subdirectory per C-I test (see Tests above). +- `.ci-pipelines/` — shell scripts that run/clean the C-I tests. +- `site-lisp/` — `kpp.el`, an Emacs major mode for KPP files. +- `docs/` — Sphinx source for the ReadTheDocs user manual. + +### How KPP itself works (`src/`) + +1. **Scanner/parser** (`scan.l` → `lex.yy.c`, `scan.y` → `y.tab.c`, + `scanner.c`, `scanutil.c`): flex/bison-based lexer+parser reads the + `.kpp`/`.def`/`.eqn`/`.spc` input language and fills in-memory tables + (atom list, species list, stoichiometry matrices, rate expressions, + option list), declared in `gdata.h`. `kpp.c` is the driver/`main`. +2. **Species reordering**: variable vs. fixed species are separated and + variable species are reordered with a Markowitz-type algorithm to + minimize Jacobian LU fill-in (unless `#REORDER OFF`). +3. **Expression-tree / code generation core** (`gen.c`, `code.c`, + `code.h`): builds a language-independent expression-tree + representation of each generated statement (production/destruction + terms, Jacobian, Hessian, stoichiometric matrix, etc.) directly from + the coefficient matrices — one statement at a time, not one + whole-program IR. +4. **Per-target-language emitters** (`code_f90.c`, `code_c.c`, + `code_f77.c` [deprecated], `code_matlab.c`): each expression tree is + rendered into valid syntax for the selected `#LANGUAGE`, then + line-wrapped for readability. +5. Driver/integrator/util *template* files (in `drv/`, `int/`, `util/`) + are passed through a substitution preprocessor (symbol substitution, + not full macro expansion) rather than being generated from scratch. + +Adding a new `#COMMAND` touches `scan.h`, `scan.l`, `scan.y`, +`scanner.c` in `src/`, plus a new C-I test and new `.rst` docs and +`site-lisp/kpp.el` — see +`docs/source/tech_info/adding_new_commands.rst` for the exact checklist. + +### Versioning + +The version string (`X.Y.Z`, semver, checked against `#MINVERSION` in +mechanism files) must be kept in sync in four places whenever it +changes: `src/gdata.h` (`KPP_VERSION`), `CHANGELOG.md`, +`docs/source/conf.py` (`release`), and the KPP Wikipedia page. + +### macOS-specific constraint + +macOS's default 64KB stack limit means `MAX_EQN`/`MAX_SPECIES` in +`src/gdata.h` are conditionally compiled smaller on macOS (`#ifdef +MACOS`) than on Linux; if a mechanism is too large to parse, these +constants (and possibly `ulimit -s`) need adjusting. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e02670e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation +in our community a harassment-free experience for everyone, regardless +of age, body size, visible or invisible disability, ethnicity, sex +characteristics, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, +welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for +our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our + mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or + political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in + a professional setting + +## Enforcement Responsibilities + +The KPP development team (listed in [`AUTHORS.txt`](AUTHORS.txt)) is +responsible for clarifying and enforcing our standards of acceptable +behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, +offensive, or harmful. + +## Scope + +This Code of Conduct applies within all community spaces (GitHub +issues, pull requests, and discussions in this repository), and also +applies when an individual is officially representing the community in +public spaces. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may +be reported to the KPP development team by opening a private report +through the "Report content" option on the relevant GitHub issue, +pull request, or comment, or by contacting a maintainer listed in +[`AUTHORS.txt`](AUTHORS.txt) directly. + +All complaints will be reviewed and investigated promptly and fairly. +All community leaders are obligated to respect the privacy and security +of the reporter of any incident. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3bbe9af --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,34 @@ +# Security Policy + +## Supported Versions + +KPP is a source-code generator run locally as a development-time tool; +there is no hosted service to secure. Security fixes are applied to +the latest release on the `main` branch. We do not backport fixes to +older released versions. + +## Reporting a Vulnerability + +If you discover a security vulnerability in KPP (for example, in the +scanner/parser in `src/`, which processes user-supplied `.kpp`/`.def`/ +`.eqn`/`.spc` input files), please report it privately rather than +opening a public GitHub issue. + +**Preferred method:** Use GitHub's private vulnerability reporting +feature for this repository: +[https://github.com/KineticPreProcessor/KPP/security/advisories/new](https://github.com/KineticPreProcessor/KPP/security/advisories/new) + +**Alternative:** Contact a maintainer listed in +[`AUTHORS.txt`](AUTHORS.txt) directly. + +Please include: +- A description of the vulnerability and its potential impact +- Steps to reproduce it (a minimal `.kpp`/mechanism file that triggers + the issue is ideal) +- The KPP version or commit affected + +## What to Expect + +We will acknowledge receipt of your report, investigate, and work with +you to understand and address the issue. We will credit reporters +(unless they prefer to remain anonymous) when a fix is released. diff --git a/ci-tests/F90_ros_passivespc/F90_ros_passivespc.kpp b/ci-tests/F90_ros_passivespc/F90_ros_passivespc.kpp new file mode 100644 index 0000000..9399972 --- /dev/null +++ b/ci-tests/F90_ros_passivespc/F90_ros_passivespc.kpp @@ -0,0 +1,66 @@ +#INCLUDE atoms.kpp { Periodic table definitions } +#INTEGRATOR rosenbrock { Use rosenbrock integrator } +#LANGUAGE Fortran90 { Use F90 language } +#DRIVER general_passivespc { Use the general driver program } + + +#DEFVAR { VARIABLE SPECIES } +O = O; { Oxygen atomic ground state } +O1D = O; { Oxygen atomic excited state } +O3 = O + O + O; { Ozone } +NO = N + O; { Nitric oxide } +NO2 = N + O + O; { Nitrogen dioxide } +PASV1 = IGNORE; { Passive species 1 } +PASV2 = IGNORE; { Passive species 2 } +PASV3 = IGNORE; { Passive species 3 } + + +#DEFFIX { FIXED SPECIES } +M = O + O + N + N; { Atmospheric generic molecule } +O2 = O + O; { Molecular oxygen } + + +#EQUATIONS { SMALL STRATOSPHERIC MECHANISM } + O2 + hv = 2O : (2.643E-10) * SUN*SUN*SUN; + O + O2 = O3 : (8.018E-17); + O3 + hv = O + O2 : (6.120E-04) * SUN; + O + O3 = 2O2 : (1.576E-15); + O3 + hv = O1D + O2 : (1.070E-03) * SUN*SUN; + O1D + M = O + M : (7.110E-11); + O1D + O3 = 2O2 + PASV1 : (1.200E-10); + NO + O3 = NO2 + O2 + PASV2 : (6.062E-15); + NO2 + O = NO + O2 : (1.069E-11); + NO2 + hv = NO + O + PASV3 : (1.289E-02) * SUN; + + + { OUTPUT OPTIONS } +#LOOKATALL { Output all species to small_strato.dat } +#MONITOR O3;N;O2;O;NO;O1D;NO2; { Print selected species to screen } + + +#CHECK O; N; { Check Mass Balance of oxygen & nitrogen } + + +#INITVALUES { Set initial values of species } + CFACTOR = 1.0e0 ; { and set units conversion factor to 1 } + O1D = 9.906E+01 ; + O = 6.624E+08 ; + O3 = 5.326E+11 ; + O2 = 1.697E+16 ; + NO = 8.725E+08 ; + NO2 = 2.240E+08 ; + M = 8.120E+16 ; + PASV1 = 0.0e0 ; + PASV2 = 0.0e0 ; + PASV3 = 0.0e0 ; + + { F90 code to be inlined into ROOT_Global } +#INLINE F90_INIT + ATOL(ind_PASV1) = 1.0d25 + ATOL(ind_PASV2) = 1.0d25 + ATOL(ind_PASV3) = 1.0d25 + TSTART = (12 * 3600) + TEND = TSTART + (3* 24 * 3600) + DT = 0.25 * 3600 + TEMP = 270 +#ENDINLINE diff --git a/docs/source/citations/09_acknowledgments.rst b/docs/source/citations/acknowledgments.rst similarity index 100% rename from docs/source/citations/09_acknowledgments.rst rename to docs/source/citations/acknowledgments.rst diff --git a/docs/source/citations/10_kpp_references.rst b/docs/source/citations/kpp_references.rst similarity index 100% rename from docs/source/citations/10_kpp_references.rst rename to docs/source/citations/kpp_references.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 55c0d87..5e54553 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ # The full version, including alpha/beta/rc tags # (version numbers must be synchronized in CHANGELOG.md, src/gdata.h, # docs/source/conf.py and https://en.wikipedia.org/wiki/Kinetic_PreProcessor) -release = "3.4.0" +release = "3.5.0" # -- General configuration --------------------------------------------------- diff --git a/docs/source/getting_started/01_installation.rst b/docs/source/getting_started/installation.rst similarity index 77% rename from docs/source/getting_started/01_installation.rst rename to docs/source/getting_started/installation.rst index 008180c..6e37736 100644 --- a/docs/source/getting_started/01_installation.rst +++ b/docs/source/getting_started/installation.rst @@ -17,8 +17,8 @@ Clone the KPP source code from the `KPP GitHub repository .. code-block:: console - cd $HOME - git clone https://github.com/KineticPreProcessor/KPP.git + $ cd $HOME + $ git clone https://github.com/KineticPreProcessor/KPP.git This will create a directory named :file:`KPP` in your home directory. @@ -71,7 +71,6 @@ may be placed in your shell startup file, as shown below. $ source $HOME/.zshrc - .. important:: macOS Catalina (2019) and later versions use :program:`zsh` @@ -122,7 +121,7 @@ gcc .. important:: macOS users: please read :ref:`installation-macos-gcc` before - proceeding. + proceeding further. KPP uses the `GNU Compiler Collection `_ (:program:`gcc`) by default. A version of :program:`gcc` comes @@ -137,11 +136,10 @@ This will display version information such as: .. code-block:: none - gcc (GCC) 11.2.0 - Copyright (C) 2021 Free Software Foundation, Inc. - This is free software; see the source for copying conditions. - There is NO warranty; not even for MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. + gcc-15 (GCC 15.3.0) 15.3.0 + Copyright (C) 2025 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .. _installation-sed: @@ -180,7 +178,7 @@ flex .. important:: macOS users: please read :ref:`installation-macos-flex` before - proceeding. + proceeding further. The :program:`flex` (Fast Lexical Analyzer) utility creates a scanner that recognizes the syntax generated by :program:`bison`. To test @@ -304,7 +302,7 @@ Create the KPP executable with: .. code-block:: console - make + $ make You should see output similar to: @@ -361,14 +359,14 @@ On macOS, the command: .. code-block:: console - gcc --version + $ gcc --version will typically produce output similar to: .. code-block:: none - Apple clang version 13.1.6 (clang-1316.0.21.2.5) - Target: x86_64-apple-darwin21.5.0 + Apple clang version 17.0.0 (clang-1700.6.4.2) + Target: x86_64-apple-darwin24.6.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin @@ -383,32 +381,7 @@ Follow the steps below to make your shell use the GNU brew install gcc -2. Determine which version of gcc was installed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - ls $(brew --prefix gcc)/bin/ | grep "^gcc-" - -You will see output such as: - -.. code-block:: none - - gcc-13 - gcc-ar-13 - gcc-nm-13 - gcc-ranlib-13 - -This indicates that gcc version 13 was installed and that the -executable is named :file:`gcc-13`. Your installed version may differ. - -.. important:: - - The version number returned by the command above may differ from - the examples shown here. Always use the actual version number - found on your system in the steps that follow. - -3. Define compiler settings in your shell startup file +2. Define compiler settings in your shell startup file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following code block uses :command:`brew --prefix` to locate the @@ -424,28 +397,52 @@ on both Intel Macs (:file:`/usr/local`) and Apple Silicon Macs .. code-block:: bash - #================================================================== - # Compiler settings (macOS) + #============================================================================ + # %%%%% Personal settings: Compilers (MacOS) %%%%% # - # Detect the gcc version installed by Homebrew and define - # aliases and environment variables accordingly. - # This overrides the Apple clang that macOS installs as gcc. - #================================================================== - _GCC_VER=$(ls "$(brew --prefix gcc)/bin/" \ - | grep '^gcc-[0-9]' \ - | grep -oP '[0-9]+$' \ - | sort -n | tail -1) - - if [[ -n "${_GCC_VER}" ]]; then - alias gcc="gcc-${_GCC_VER}" - alias g++="g++-${_GCC_VER}" - alias gfortran="gfortran-${_GCC_VER}" - export CC="gcc-${_GCC_VER}" - export CXX="g++-${_GCC_VER}" - export FC="gfortran-${_GCC_VER}" - export F77="gfortran-${_GCC_VER}" + # NOTE: MacOSX installs Clang as /usr/bin/gcc, so we have to manually + # force reference to GNU compilers in /usr/local/opt/gcc/bin. + #============================================================================ + + # --- Homebrew GCC (override Apple Clang) ----------------------------------- + GCC_BIN="$(brew --prefix gcc)/bin" + + if [[ -d "${GCC_BIN}" ]]; then + + # Auto-detect the GCC major version by finding the gcc-NN executable + # Pipeline: find gcc-NN files --> extract 'gcc-NN' --> + # sort numerically --> take highest --> extract number + GCC_VER=$(find "${GCC_BIN}" -maxdepth 1 -name 'gcc-[0-9]*' 2>/dev/null \ + | grep -oE 'gcc-[0-9]+$' \ + | sort -t'-' -k2 -n \ + | tail -1 \ + | grep -oE '[0-9]+$') + + if [[ "x${GCC_VER}" != "x" ]]; then + + unset CC + unset CXX + unset FC + + # --- Interactive shell aliases ---------------------------------------- + alias gcc="${GCC_BIN}/gcc-${GCC_VER}" + alias cc="${GCC_BIN}/gcc-${GCC_VER}" + alias g++="${GCC_BIN}/g++-${GCC_VER}" + alias c++="${GCC_BIN}/g++-${GCC_VER}" + alias gfortran="${GCC_BIN}/gfortran-${GCC_VER}" + + # --- Build-system variables (make, cmake, autoconf, etc.) ------------ + export CC="${GCC_BIN}/gcc-${GCC_VER}" + export CXX="${GCC_BIN}/g++-${GCC_VER}" + export FC="${GCC_BIN}/gfortran-${GCC_VER}" + export F77="${FC}" + else + echo "WARNING: Could not detect GCC version in ${GCC_BIN}" >&2 + fi + fi - unset _GCC_VER + unset GCC_BIN + unset GCC_VER Then apply the changes with: @@ -459,28 +456,52 @@ on both Intel Macs (:file:`/usr/local`) and Apple Silicon Macs .. code-block:: zsh - #================================================================== - # Compiler settings (macOS) + #============================================================================ + # %%%%% Personal settings: Compilers (MacOS) %%%%% # - # Detect the gcc version installed by Homebrew and define - # aliases and environment variables accordingly. - # This overrides the Apple clang that macOS installs as gcc. - #================================================================== - _GCC_VER=$(ls "$(brew --prefix gcc)/bin/" \ - | grep '^gcc-[0-9]' \ - | grep -oE '[0-9]+$' \ - | sort -n | tail -1) - - if [[ -n "${_GCC_VER}" ]]; then - alias gcc="gcc-${_GCC_VER}" - alias g++="g++-${_GCC_VER}" - alias gfortran="gfortran-${_GCC_VER}" - export CC="gcc-${_GCC_VER}" - export CXX="g++-${_GCC_VER}" - export FC="gfortran-${_GCC_VER}" - export F77="gfortran-${_GCC_VER}" + # NOTE: MacOSX installs Clang as /usr/bin/gcc, so we have to manually + # force reference to GNU compilers in /usr/local/opt/gcc/bin. + #============================================================================ + + # --- Homebrew GCC (override Apple Clang) ----------------------------------- + GCC_BIN="$(brew --prefix gcc)/bin" + + if [[ -d "${GCC_BIN}" ]]; then + + # Auto-detect the GCC major version by finding the gcc-NN executable + # Pipeline: find gcc-NN files --> extract 'gcc-NN' --> + # sort numerically --> take highest --> extract number + GCC_VER=$(find "${GCC_BIN}" -maxdepth 1 -name 'gcc-[0-9]*' 2>/dev/null \ + | grep -oE 'gcc-[0-9]+$' \ + | sort -t'-' -k2 -n \ + | tail -1 \ + | grep -oE '[0-9]+$') + + if [[ "x${GCC_VER}" != "x" ]]; then + + unset CC + unset CXX + unset FC + + # --- Interactive shell aliases ---------------------------------------- + alias gcc="${GCC_BIN}/gcc-${GCC_VER}" + alias cc="${GCC_BIN}/gcc-${GCC_VER}" + alias g++="${GCC_BIN}/g++-${GCC_VER}" + alias c++="${GCC_BIN}/g++-${GCC_VER}" + alias gfortran="${GCC_BIN}/gfortran-${GCC_VER}" + + # --- Build-system variables (make, cmake, autoconf, etc.) ------------ + export CC="${GCC_BIN}/gcc-${GCC_VER}" + export CXX="${GCC_BIN}/g++-${GCC_VER}" + export FC="${GCC_BIN}/gfortran-${GCC_VER}" + export F77="${FC}" + else + echo "WARNING: Could not detect GCC version in ${GCC_BIN}" >&2 + fi + fi - unset _GCC_VER + unset GCC_BIN + unset GCC_VER Then apply the changes with: @@ -488,7 +509,7 @@ on both Intel Macs (:file:`/usr/local`) and Apple Silicon Macs $ source ~/.zshrc -4. Verify that your shell now recognizes the GNU gcc compiler +3. Verify that your shell now recognizes the GNU gcc compiler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: console @@ -499,11 +520,10 @@ You should see output similar to: .. code-block:: none - gcc-13 (Homebrew GCC 13.2.0) 13.2.0 - Copyright (C) 2023 Free Software Foundation, Inc. - This is free software; see the source for copying conditions. - There is NO warranty; not even for MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. + gcc-15 (Homebrew GCC 15.3.0) 15.3.0 + Copyright (C) 2025 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This confirms that your shell is using GNU :program:`gcc` rather than :program:`clang`. @@ -596,7 +616,7 @@ following line to your shell startup file: $ source ~/.bashrc **If you use zsh:** - + Add this code to your :file:`~/.zshrc` file: .. code-block:: zsh diff --git a/docs/source/getting_started/00_revision_history.rst b/docs/source/getting_started/revision_history.rst similarity index 95% rename from docs/source/getting_started/00_revision_history.rst rename to docs/source/getting_started/revision_history.rst index 7826b3f..29057f0 100644 --- a/docs/source/getting_started/00_revision_history.rst +++ b/docs/source/getting_started/revision_history.rst @@ -10,6 +10,23 @@ of the changes, read `CHANGELOG.md .. _unreleased: +========== +Unreleased +========== + +- Updated KPP code to exclude passive species from the Rosenbrock + error norm computation when the optional + :code:`PassiveSpc_ATOL_Threshold` argument is passed to the + :code:`Initialize` routine +- Added `F90_ros_passivespc` C-I test and `drv/general_passivespc.f90` + driver program +- Added GCC compiler versions 14, 15, and 16 to the "Run C-I tests" + GitHub Action +- Fixed several build issues for MacOSX with ARM chipsets +- Fixed emacs font-lock issues in :file:`site_lisp/kpp.el` +- Split ReadTheDocs documentation into smaller files and reorganized + documentation folders + .. _kpp340: ========= diff --git a/docs/source/getting_started/02_running_kpp_sample_mech.rst b/docs/source/getting_started/running_kpp_sample_mech.rst similarity index 100% rename from docs/source/getting_started/02_running_kpp_sample_mech.rst rename to docs/source/getting_started/running_kpp_sample_mech.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 1133c2b..a993dd4 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,32 +1,52 @@ +.. |br| raw:: html + +
+ ############################# The Kinetic PreProcessor: KPP ############################# -.. raw:: html - -

An Environment for the
Simuation of Chemical Kinetic Systems

-

Adrian Sandu1, Rolf Sander2, - Michael S. Long3, Haipeng Lin4,
- Robert M. Yantosca4, Lucas Estrada4, Lu - Shen5, and Daniel J. Jacob4

-

- 1 Virginia Polytechnic Institute and State University, Blacksburg, VA, USA
- 2 Max-Planck Institute for Chemistry, Mainz, Germany
- 3 Renaissance Fiber, LLC, North Carolina, USA
- 4 Harvard John A. Paulson School of Engineering and - Applied Sciences, Cambridge, MA, USA
- 5 School of Physics, Peking University, Bejing, China
-

- -

- - - - - - - -

+| **An Environment for the Simuation of Chemical Kinetic Systems** + +| **Adrian Sandu**\ :sup:`1`\ **, Rolf Sander**\ :sup:`2`\ **, Michael S. Long**\ :sup:`3`\ **, Haipeng Lin**\ :sup:`4`\ **,** +| **Robert M. Yantosca**\ :sup:`4`\ **, Lucas Estrada**\ :sup:`4`\ **, Lu Shen**\ :sup:`5`\ **, and Daniel J. Jacob**\ :sup:`4` + +| :sup:`1` *Virginia Polytechnic Institute and State University, Blacksburg, VA, USA* +| :sup:`2` *Max-Planck Institute for Chemistry, Mainz, Germany* +| :sup:`3` *Renaissance Fiber, LLC, North Carolina, USA* +| :sup:`4` *Harvard John A. Paulson School of Engineering and Applied Sciences, Cambridge, MA, USA* +| :sup:`5` *School of Physics, Peking University, Beijing, China* + +---- + +.. |latest-stable-release| image:: https://img.shields.io/github/v/release/KineticPreProcessor/KPP?label=Latest%20Stable%20Release + :target: https://github.com/KineticPreProcessor/KPP/releases/ + :alt: Latest Stable Release + +.. |release-date| image:: https://img.shields.io/github/release-date/KineticPreProcessor/KPP + :target: https://github.com/KineticPreProcessor/KPP/releases/ + :alt: Release Date + +.. |license| image:: https://img.shields.io/badge/License-GPLv3-blue.svg + :target: https://github.com/KineticPreProcessor/KPP/blob/main/LICENSE.txt + :alt: License: GPLv3 + +.. |doi| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6828025.svg + :target: https://doi.org/10.5281/zenodo.6828025 + :alt: DOI + +.. |readthedocs| image:: https://readthedocs.org/projects/kpp/badge/?version=stable + :target: https://kpp.readthedocs.io/en/latest/ + :alt: ReadTheDocs + +.. |ci-tests| image:: https://github.com/KineticPreProcessor/KPP/actions/workflows/run-ci-tests.yml/badge.svg + :target: https://github.com/KineticPreProcessor/KPP/actions/workflows/run-ci-tests.yml + :alt: C-I tests + +|latest-stable-release| |release-date| |license| |br| +|doi| |readthedocs| |ci-tests| + +---- This site provides instructions for :program:`KPP`, the Kinetic PreProcessor. @@ -38,31 +58,59 @@ guidelines. If you find something hard to understand---let us know! :caption: Getting Started :maxdepth: 2 - getting_started/00_revision_history.rst - getting_started/01_installation.rst - getting_started/02_running_kpp_sample_mech.rst + getting_started/revision_history.rst + getting_started/installation.rst + getting_started/running_kpp_sample_mech.rst .. toctree:: - :caption: Using KPP - :maxdepth: 2 + :caption: Input for KPP + :maxdepth: 3 + + input/input_overview.rst + input/kpp_sections.rst + input/kpp_commands.rst + input/inlined_code.rst + input/auxiliary_files.rst + input/filter-passive-spc.rst + +.. toctree:: + :caption: Output from KPP + :maxdepth: 3 - using_kpp/04_input_for_kpp.rst - using_kpp/05_output_from_kpp.rst + output/code_f90.rst + output/code_c.rst + output/code_matlab.rst + output/makefile.rst + output/log_file.rst + +.. toctree:: + :caption: Numerical Integration Methods + :maxdepth: 3 + + num_methods/rosenbrock-methods.rst + num_methods/runge_kutta_methods.rst + num_methods/backward_diff.rst + num_methods/forward_diff.rst + num_methods/controlling_the_integrator.rst + num_methods/output_from_integrators.rst .. toctree:: :caption: Technical information - :maxdepth: 2 + :maxdepth: 3 - tech_info/06_info_for_kpp_developers.rst - tech_info/07_numerical_methods.rst - tech_info/08_bnf_description_of_kpp_lang.rst + tech_info/kpp_dir_structure.rst + tech_info/kpp_env_vars.rst + tech_info/kpp_internal_modules.rst + tech_info/adding_new_commands.rst + tech_info/about_ci_tests.rst + tech_info/bnf_description_of_kpp_lang.rst .. toctree:: :caption: KPP Reference :maxdepth: 2 - citations/09_acknowledgments.rst - citations/10_kpp_references.rst + citations/acknowledgments.rst + citations/kpp_references.rst .. toctree:: :caption: Help and Support diff --git a/docs/source/input/auxiliary_files.rst b/docs/source/input/auxiliary_files.rst new file mode 100644 index 0000000..bbe1a2e --- /dev/null +++ b/docs/source/input/auxiliary_files.rst @@ -0,0 +1,138 @@ +.. _auxiliary-files-and-the-substitution-preprocessor: + +################################################# +Auxiliary files and the substitution preprocessor +################################################# + +The `auxiliary files `_ in the +:file:`$KPP_HOME/util` subdirectory are templates for integrators, +drivers, and utilities. They are inserted into the KPP output after +being run through the substitution preprocessor. This preprocessor +replaces `several placeholder symbols `_ in +the template files with their particular values in the model at hand. +Usually, only :command:`KPP_ROOT` and :command:`KPP_REAL` are needed +because the other values can also be obtained via the variables listed +in :ref:`table-inl-type`. + +:command:`KPP_REAL` is replaced by the appropriate single or double +precision declaration type. Depending on the target language KPP will +select the correct declaration type. For example if one needs to +declare an array BIG of size 1000, a declaration like the following +must be used: + +.. code-block:: fortran + + KPP_REAL :: BIG(1000) + +When used with the command :command:`#DOUBLE ON`, the above line will be +automatically translated into: + +.. code-block:: fortran + + REAL(kind=dp) :: BIG(1000) + +and when used with the command :command:`#DOUBLE OFF`, the same line will +become: + +.. code-block:: fortran + + REAL(kind=sp) :: BIG(1000) + +in the resulting Fortran90 output file. + +:command:`KPP_ROOT` is replaced by the root file name of the main kinetic +description file. In our example where we are processing +:file:`small_strato.kpp`, a line in an auxiliary Fortran90 file like + +.. code-block:: fortran + + USE KPP_ROOT_Monitor + +will be translated into + +.. code-block:: fortran + + USE small_strato_Monitor + +in the generated Fortran90 output file. + +.. _auxiliary-files-for-fortran-90: + +===================================== +List of auxiliary files for Fortran90 +===================================== + +.. _table-aux-files: + +.. list-table:: Auxiliary files for Fortran90 + :align: center + :header-rows: 1 + + * - File + - Contents + * - :code:`dFun_dRcoeff.f90` + - Derivatives with respect to reaction rates + * - :code:`dJac_dRcoeff.f90` + - Derivatives with respect to reaction rates + * - :code:`Makefile_f90` and :code:`Makefile_upper_F90` + - Makefiles to build Fortran-90 code + * - :code:`Mex_Fun.f90` and :code:`Mex_Jac_SP.f90` + - Mex files. + * - :code:`Mex_Hessian.f90` + - Mex files. + * - :code:`sutil.f90` + - Sparse utility functions. + * - :code:`tag2num.f90` + - Function related to equation tags. + * - :code:`UpdateSun.f90` + - Function related to solar zenith angle. + * - :code:`UserRateLaws.f90` and :code:`UserRateLawsInterfaces.f90` + - User-defined rate-law functions. + * - :code:`util.f90` + - Input/output utilities. + +.. _list-of-symbols-replaced: + +========================================================= +List of symbols replaced by the substitution preprocessor +========================================================= + +.. _table-sym-repl: + +.. list-table:: Symbols and their replacements + :align: center + :header-rows: 1 + + * - Symbol + - Replacement + - Example + * - **KPP_ROOT** + - The :literal:`ROOT` name + - :literal:`small_strato` + * - **KPP_REAL** + - The real data type + - :code:`REAL(kind=dp)` + * - **KPP_NSPEC** + - Number of species + - 7 + * - **KPP_NVAR** + - Number of variable species + - 5 + * - **KPP_NFIX** + - Number of fixed species + - 2 + * - **KPP_NREACT** + - Number of chemical reactopms + - 10 + * - **KPP_NONZERO** + - Number of Jacobian nonzero elements + - 18 + * - **KPP_LU_NONZERO** + - Number of Jacobian nonzero elements, with LU fill0in + - 19 + * - **KPP_LU_NHESS** + - Number of Hessian nonzero elements + - 19 + * - **KPP_FUN_OR_FUN_SPLIT** + - Name of the function to be called + - ``FUN(Y,FIX,RCONST,Ydot)`` diff --git a/docs/source/input/filter-passive-spc.rst b/docs/source/input/filter-passive-spc.rst new file mode 100644 index 0000000..4a4620c --- /dev/null +++ b/docs/source/input/filter-passive-spc.rst @@ -0,0 +1,96 @@ +.. _filter-passive-spc: + +================================================================== +Filtering out passive species with an absolute tolerance threshold +================================================================== + +In some external models that use KPP (such as GEOS-Chem) it is common +to attach "passive" species to reactions. This is usually done to +optain production or loss rates for diagnostic purposes. + +We have created a simple passive species example C-I test (see the +chemcial mechanism description file +:file:`ci-tests/F90_ros_passivespc/F90_ros_passivespc.kpp`). In this +example we add 3 passive species (:literal:`PASV1`, :literal:`PASV2`, +:literal:`PASV3`) are to the :literal:`small_strato` mechanism: + +.. code-block:: console + + #EQUATIONS { SMALL STRATOSPHERIC MECHANISM } + O2 + hv = 2O : (2.643E-10) * SUN*SUN*SUN; + O + O2 = O3 : (8.018E-17); + O3 + hv = O + O2 : (6.120E-04) * SUN; + O + O3 = 2O2 : (1.576E-15); + O3 + hv = O1D + O2 : (1.070E-03) * SUN*SUN; + O1D + M = O + M : (7.110E-11); + O1D + O3 = 2O2 + PASV1 : (1.200E-10); + NO + O3 = NO2 + O2 + PASV2 : (6.062E-15); + NO2 + O = NO + O2 : (1.069E-11); + NO2 + hv = NO + O + PASV3 : (1.289E-02) * SUN; + +Passive species, however, should not be allowed to influence certain +computations (such as the Rosenbrock error norm), as this may lead to +numerical instability. In the case of the Rosenbrock error norm, we +have found that results of key species (such as O3 and NO) can vary +depending on the number of passive species that are added to the +mechanism. + +In KPP 3.5.0 we have introduced the capability to filter out passive +species. This feature is currently only available when generating +Fortran90 source code with KPP. You may do this as follows: + +First, give each passive species an extremely high absolute tolerance +(:code:`ATOL`) value: + +.. code-block:: Fortran + + USE ROOT_Parameters + + ... + + ATOL(ind_PASV1) = 1.0d25 + ATOL(ind_PASV2) = 1.0d25 + ATOL(ind_PASV3) = 1.0d25 + +Next, pass the optional argument :code:`PassiveSpc_ATOL_Threshold` to +the :ref:`Initialize ` routine (this needs to be done +only once at the model initialization phase): + +.. code-block:: Fortran + + CALL Initialize( PassiveSpc_ATOL_Threshold = 1.0d25 ) + +Any species having a value of :code:`ATOL` greater than or equal to +:code:`PassiveSpc_ATOL_Threshold` will be denoted as a passive +species. Subroutine :ref:`Initialize ` will then generate +the number and list of non-passive species in the following variables, +which are stored in the :ref:`Global` module: + +.. code-block:: Fortran + + ! NonPassiveSpc_Count - Number of non-passive species in mechanism + INTEGER :: NonPassiveSpc_Count + ! NonPassiveSpc_Indices - Indices of non-passive species in mechanism + INTEGER :: NonPassiveSpc_Indices(NVAR) + +You may then use these variables to exclude passive species from +certain computations, such as: + +.. code-block:: Fortran + + USE ROOT_Global + + ... + + INTEGER :: NP, I + + ! Loop over the number of non-passive species + DO NP = 1, NonPassiveSpc_Count + + ! Only use non-passive species in computation + I = NonPassiveSpc_Indices(NP) + Err = ATOL(I) * RTOL(I) * YMAX + + ... etc ... + + ENDDO diff --git a/docs/source/input/inlined_code.rst b/docs/source/input/inlined_code.rst new file mode 100644 index 0000000..ff6312d --- /dev/null +++ b/docs/source/input/inlined_code.rst @@ -0,0 +1,214 @@ +.. |br| raw:: html + +
+ +.. _inlined-code: + +############ +Inlined code +############ + +In order to offer maximum flexibility, KPP allows the user to include +pieces of code in the kinetic description file. Inlined code begins on a +new line with :command:`#INLINE` and the *inline_type*. Next, one or +more lines of code follow, written in the target language (Fortran90, C, +or Matlab) as specified by the *inline_type*. The inlined code ends with +:command:`#ENDINLINE`. The code is inserted into the KPP output at a +position which is also determined by *inline_type* as shown in +:ref:`table-inl-type`. If two inline commands with the same inline type +are declared, then the contents of the second is appended to the first +one. + +.. _list-of-inlined-types: + +===================== +List of inlined types +===================== + +In this manual, we show the inline types for Fortran90. The inline +types for the other languages are produced by replacing :code:`F90` +by :code:`C`, or :code:`matlab`, respectively. + +.. _table-inl-type: + +.. list-table:: KPP inlined types + :align: center + :header-rows: 1 + + * - Inline_type + - File + - Placement + - Usage + * - **F90_DATA** + - :ref:`Monitor` + - specification section + - (obsolete) + * - **F90_GLOBAL** + - :ref:`Global` + - specification section + - global variables + * - **F90_INIT** + - :ref:`Initialize` + - subroutine + - integration parameters + * - **F90_RATES** + - :ref:`Rates` + - executable section + - rate law functions + * - **F90_RCONST** + - :ref:`Rates` + - subroutine + - rate coefficient definitions + * - **F90_RCONST_USE** + - :ref:`Rates` + - subroutine + - rate coefficient definitions + * - **F90_UTIL** + - :ref:`Util` + - executable section + - utility functions + +.. _f90-data: + +======== +F90_DATA +======== + +This inline type was introduced in a previous version of KPP to +initialize variables. It is now obsolete but kept for compatibility. For +Fortran90, :command:`F90_GLOBAL` should be used instead. + +.. _f90-global: + +========== +F90_GLOBAL +========== + +This inline type can be used to declare global variables, e.g. for a +special rate coefficient: + +.. code-block:: fortran + + #INLINE F90_GLOBAL + REAL(dp) :: k_DMS_OH + #ENDINLINE + +Inlining code can be useful to introduce additional state variables +(such as temperature, humidity, etc.) for use by KPP routines, such as +for calculating rate coefficients. + +If a large number of state variables needs to be held in inline code, or +require intermediate computation that may be repeated for many rate +coefficients, a derived type object should be used for efficiency, e.g.: + +.. code-block:: fortran + + #INLINE F90_GLOBAL + TYPE, PUBLIC :: ObjGlobal_t + ! ... add variable fields to this type ... + END TYPE ObjGlobal_t + TYPE(ObjGlobal_t), TARGET, PUBLIC :: ObjGlobal + #ENDINLINE + +This global variable :code:`ObjGlobal` can then be used globally in KPP. + +Another way to avoid cluttering up the KPP input file is to +:code:`#include` a header file with global variables: + +.. code-block:: fortran + + #INLINE F90_GLOBAL + ! Inline common variables into KPP_ROOT_Global.f90 + #include "commonIncludeVars.f90" + #ENDINLINE + +In future versions of KPP, the global state will be reorganized into +derived type objects as well. + +.. _inline-type-f90-init: + +======== +F90_INIT +======== + +This inline type can be used to define initial values before the start of the +integration, e.g.: + +.. code-block:: fortran + + #INLINE F90_INIT + TSTART = (12.*3600.) + TEND = TSTART + (3.*24.*3600.) + DT = 0.25*3600. + TEMP = 270. + #ENDINLINE + +.. _f90-rates: + +========= +F90_RATES +========= + +This inline type can be used to add new subroutines to calculate rate +coefficients, e.g.: + +.. code-block:: fortran + + #INLINE F90_RATES + REAL FUNCTION k_SIV_H2O2(k_298,tdep,cHp,temp) + ! special rate function for S(IV) + H2O2 + REAL, INTENT(IN) :: k_298, tdep, cHp, temp + k_SIV_H2O2 = k_298 & + * EXP(tdep*(1./temp-3.3540E-3)) & + * cHp / (cHp+0.1) + END FUNCTION k_SIV_H2O2 + #ENDINLINE + +.. _f90-rconst: + +========== +F90_RCONST +========== + +This inline type can be used to define time-dependent values of rate +coefficients. You may inline variables directly, e.g.: + +.. code-block:: fortran + + #INLINE F90_RCONST + k_DMS_OH = 1.E-9*EXP(5820./temp)*C(ind_O2)/ & + (1.E30+5.*EXP(6280./temp)*C(ind_O2)) + #ENDINLINE + +The inlined code will be placed directly into the subroutines +:code:`UPDATE_RCONST` and :code:`UPDATE_PHOTO` in the :ref:`Rates` file. + +.. _f90-rconst-use: + +============== +F90_RCONST_USE +============== + +Similar to :ref:`f90-rconst`, but allows you to inline Fortran-90 +:code:`USE` statements referencing modules where rate coefficients are +computed, such as: + +.. code-block:: fortran + + #INLINE F90_RCONST_USE + USE MyRateFunctionModule + #ENDINLINE + +The inlined code will be placed directly into the subroutines +:code:`UPDATE_RCONST` and :code:`UPDATE_PHOTO` in the :ref:`Rates` +file. :code:`USE` statements will be placed before Fortran variable +definitions and executable statements, as is required by the +Fortran-90 language standard. + +.. _f90-util: + +======== +F90_UTIL +======== + +This inline type can be used to define utility subroutines. diff --git a/docs/source/input/input_overview.rst b/docs/source/input/input_overview.rst new file mode 100644 index 0000000..b22bdc3 --- /dev/null +++ b/docs/source/input/input_overview.rst @@ -0,0 +1,48 @@ +.. _input-for-kpp: + +############## +Input overview +############## + +KPP basically handles two types of input files: **Kinetic description +files** and **auxiliary files**. Kinetic description files are in KPP +syntax and described in the following sections. Auxiliary files are +described in the section entitled +:ref:`auxiliary-files-and-the-substitution-preprocessor`. + +KPP kinetic description files specify the chemical equations, the +initial values of each of the species involved, the integration +parameters, and many other options. The KPP preprocessor parses the +kinetic description files and generates several output files. Files +that are written in KPP syntax have one of the suffixes :file:`.kpp`, +:file:`.spc`, :file:`.eqn`, or :file:`def`. + +The following general rules define the structure of a kinetic +description file: + +- A KPP program is composed of :ref:`kpp-sections`, + :ref:`kpp-commands`, and :ref:`inlined-code`. Their syntax is + presented in :ref:`bnf-description`. + +- Comments are either enclosed between the curly braces ":code:`{`" + and ":code:`}`", or written in a line starting with two slashes and + a space "// ". + +- Any name given by the user to denote an atom or a species is + restricted to be less than 32 character in length and can only + contain letters, numbers, or the underscore character. The first + character cannot be a number. All names are case insensitive. + +The kinetic description files contain a detailed specification of the +chemical model, information about the integration method and the desired +type of results. KPP accepts only one of these files as input, but using +the :ref:`include-cmd` command, code from separate files can be +combined. The include files can be nested up to 10 levels. KPP will +parse these files as if they were a single big file. By carefully +splitting the chemical description, KPP can be configured for a broad +range of users. In this way the users can have direct access to that +part of the model that they are interested in, and all the other details +can be hidden inside several include files. Often, the atom definitions +(:file:`atoms.kpp`) are included first, then species definitions +(:file:`*.spc`), and finally the equations of the chemical mechanism +(:file:`*.eqn`). diff --git a/docs/source/input/kpp_commands.rst b/docs/source/input/kpp_commands.rst new file mode 100644 index 0000000..8209c77 --- /dev/null +++ b/docs/source/input/kpp_commands.rst @@ -0,0 +1,553 @@ +.. _kpp-commands: + +############ +KPP commands +############ + +A KPP command begins on a new line with a :code:`#` sign, followed by a +command name and one or more parameters. Details about each command +are given in the following subsections. + +.. _table-cmd-defaults: + +.. list-table:: Default values for KPP commands + :align: center + :header-rows: 1 + + * - KPP command + - default value + - KPP command + - default value + * - :command:`#AUTOREDUCE` + - :code:`OFF` + - :command:`#CHECKALL` + - + * - :command:`#DECLARE` + - :code:`SYMBOL` + - :command:`#DOUBLE` + - :code:`ON` + * - :command:`#DRIVER` + - :code:`none` + - :command:`#DUMMYINDEX` + - :code:`OFF` + * - :command:`#EQNTAGS` + - :code:`OFF` + - :command:`#FUNCTION` + - :code:`AGGREGATE` + * - :command:`#GRAPH` + - :code:`OFF` + - :command:`#HESSIAN` + - :code:`ON` + * - :command:`#INCLUDE` + - + - :command:`#INTEGRATOR` + - + * - :command:`#INTFILE` + - + - :command:`#JACOBIAN` + - :code:`SPARSE_LU_ROW` + * - :command:`#LANGUAGE` + - + - :command:`#LOOKATALL` + - + * - :command:`#MEX` + - :code:`ON` + - :command:`#MINVERSION` + - + * - :command:`#MODEL` + - + - :command:`#REORDER` + - :code:`ON` + * - :command:`#STOCHASTIC` + - :code:`OFF` + - :command:`#STOICMAT` + - :code:`ON` + * - :command:`#UPPERCASEF90` + - :code:`OFF` + - + - + +.. _autoreduce-cmd: + +=========== +#AUTOREDUCE +=========== + +The :command:`#AUTOREDUCE ON` command can be used with +:command:`#INTEGRATOR rosenbrock` to enable +:ref:`automatic mechanism reduction ` as +described in :cite:t:`Lin_et_al._2022`. Automatic mechanism reduction +is disabled by default. + +.. _declare-cmd: + +======== +#DECLARE +======== + +The :command:`#DECLARE` command determines how constants like +:code:`dp`, :code:`NSPEC`, :code:`NVAR`, :code:`NFIX`, and +:code:`NREACT` are inserted into the KPP-generated code. +:command:`#DECLARE SYMBOL` (the default) will declare array variables +using parameters from the :ref:`Parameters` file. :command:`#DECLARE VALUE` +will replace each parameter with its value. + +For example, the global array variable :code:`C` is declared in the +:ref:`Global` file generated by KPP. In the :program:`small_strato` +example (described in :ref:`running-kpp-with-an-example-mechanism`), +:code:`C` has dimension :code:`NSPEC=7`. Using :command:`#DECLARE +SYMBOL` will generate the following code in :ref:`Global`: + +.. code-block:: fortran + + ! C - Concentration of all species + REAL(kind=dp), TARGET :: C(NSPEC) + +Whereas :command:`#DECLARE VALUE` will generate this code instead: + +.. code-block:: fortran + + ! C - Concentration of all species + REAL(kind=dp), TARGET :: C(7) + +We recommend using :command:`#DECLARE SYMBOL`, as most modern compilers +will automatically replace each parameter (e.g. :code:`NSPEC`) with its +value (e.g :code:`7`). However, if you are using a very old compiler +that is not as sophisticated, :command:`#DECLARE VALUE` might result in +better-optmized code. + +.. _double-cmd: + +======= +#DOUBLE +======= + +The :command:`#DOUBLE` command selects single or double precision +arithmetic. :command:`ON` (the default) means use double precision, +:command:`OFF` means use single precision (see the section entitled +:ref:`Precision`). + +.. important:: + + We recommend using double precision whenever possible. Using + single precision may lead to integration non-convergence errors + caused by roundoff and/or underflow. + +.. _driver-cmd: + +======= +#DRIVER +======= + +The :command:`#DRIVER` command selects the driver, i.e., the file from +which the main function is to be taken. The parameter is a file name, +without suffix. The appropriate suffix (:code:`.f90`, :code:`.F90`, +:code:`.c`, or :code:`.m`) is automatically appended. + +Normally, KPP tries to find the selected driver file in the directory +:file:`$KPP_HOME/drv/`. However, if the supplied file name contains a slash, +it is assumed to be absolute. To access a driver in the current +directory, the prefix :file:`./` can be used, e.g.: + +.. code-block:: console + + #DRIVER ./mydriver + +It is possible to choose the empty dummy driver :command:`none`, if the +user wants to include the KPP generated modules into a larger model +(e.g. a general circulation or a chemical transport model) instead of +creating a stand-alone version of the chemical integrator. The driver +:command:`none` is also selected when the :command:`#DRIVER` command +is missing. If the command occurs twice, the second replaces the first. + +.. _dummyindex-cmd: + +=========== +#DUMMYINDEX +=========== + +It is possible to declare species in the :ref:`defvar-and-deffix` +sections that are not used in the :ref:`equations` section. If your +model needs to check at run-time if a certain species is included in +the current mechanism, you can set to :command:`#DUMMYINDEX ON`. Then, +KPP will set the indices to zero for all species that do not occur in +any reaction. With :command:`#DUMMYINDEX OFF` (the default), those are +undefined variables. For example, if you frequently switch between +mechanisms with and without sulfuric acid, you can use this code: + +.. code-block:: fortran + + IF (ind_H2SO4=0) THEN + PRINT *, 'no H2SO4 in current mechanism' + ELSE + PRINT *, 'c(H2SO4) =', C(ind_H2SO4) + ENDIF + +.. _eqntags-cmd: + +======== +#EQNTAGS +======== + +Each reaction in the :ref:`equations` section may start with an +equation tag which is enclosed in angle brackets, e.g.: + +.. code-block:: console + + NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0); + +With :command:`#EQNTAGS` set to :command:`ON`, this equation tag can be +used to refer to a specific equation (cf. :ref:`monitor`). The default +for :command:`#EQNTAGS` is :command:`OFF`. + +.. _function-cmd: + +========= +#FUNCTION +========= + +The :command:`#FUNCTION` command controls which functions are generated +to compute the production/destruction terms for variable +species. :command:`AGGREGATE` generates one function that computes the +normal derivatives. :command:`SPLIT` generates two functions +for the derivatives in production and destruction forms. + +.. _graph-cmd: + +====== +#GRAPH +====== + +Off by default, the :command:`#GRAPH` command leverages the +pre-existing parsing of stoichiometric structure to create +graph-based representations of the chemical mechanism. +:command:`#GRAPH` currently supports two options, described below. + +.. _graph-cmd-stoic: + +#GRAPH stoic +------------ + +This option generates two CSV files describing the structure of the +mechanism based on stoichiometric balances and species composition. + +1. :file:`ROOT_BiadjacencyMatrix.csv`: A sparse matrix of the + the net stoichiometric coefficients for each species in each + reaction. + + .. list-table:: Structure of :file:`ROOT_BiadjacencyMatrix.csv` + :header-rows: 1 + :widths: 10 30 60 + + * - Column + - Header + - Description + * - 1 + - spc_name + - Species name. + * - 2 + - species_index + - Number of the species in the chemical mechanism + * - 3 + - reaction_index + - Number of the reaction in the chemical mechanism + * - 4 + - stoichiometric_coefficient + - The the net, weighted biadjacency matrix of the bipartite + species-reaction graph, useful for automated detection of + system-wide stoichiometric invariants and other mass + conservation enforcing :cite:`Sturm_and_Wexler_2022`. + +2. :file:`ROOT_SpeciesCompositionMatrix.csv`: This is a species + composition dense matrix that for each variable species (row), + records the atom count of each element present (columns). + + .. list-table:: Structure of :file:`ROOT_SpeciesCompositionMatrix.csv` + :header-rows: 1 + :widths: 15 20 65 + + * - Column + - Name + - Description + * - 1 + - species_index + - Number of the species in the chemical mechanism + * - 2 + - species_name + - Species name. + * - 3 - NSPEC + - Species matrix + - One column for each atom present in the mechanism (including + IGNORE if used for some species). This matrix can be used + for automated mass balance checking of mechanism output or + individual reactions :cite:`Sturm_and_Silva_2025`. + +.. _graph-cmd-edgelist: + +#GRAPH edgelist +--------------- + +The :ref:`graph-cmd-stoic` option uses net stoichiometry, which +neglects reciprocal reactions (e.g. when the same species is a +reactant and a product its net stoichiometry is zero). This +:command:`#GRAPH edgelist` option generates a +:file:`ROOT_Edgelist.csv` file listing the edges of the +species-reaction bipartite graph. Each row represents a connection +between a species and a reaction, with direction and stoichiometric +value. + +.. list-table:: + :header-rows: 1 + :widths: 10 20 70 + + * - Column + - Name + - Description + * - 1 + - species_index + - Species index (starts from 1) + * - 2 + - reaction_index + - Reaction index (starts from 1) + * - 3 + - From + - Starting edge + * - 4 + - To + - Ending edge + * - 5 + - Stoichometric value + - Directed stoichiometric value + +.. _hessian-cmd: + +======== +#HESSIAN +======== + +The option :command:`ON` (the default) of the :command:`#HESSIAN` +command turns the Hessian generation on (see section +:ref:`Hessian-and-HessianSP`). With :command:`OFF` it is switched off. + +.. _include-cmd: + +======== +#INCLUDE +======== + +The :command:`#INCLUDE` command instructs KPP to look for the file +specified as a parameter and parse the content of this file before +proceeding to the next line. This allows the atoms definition, the +species definition and the equation definition to be shared between +several models. Moreover this allows for custom configuration of KPP to +accommodate various classes of users. Include files can be either in one +of the KPP directories or in the current directory. + +.. _integrator-cmd: + +=========== +#INTEGRATOR +=========== + +The :command:`#INTEGRATOR` command selects the integrator definition +file. The parameter is the file name of an integrator, without +suffix. The effect of + +.. code-block:: console + + #INTEGRATOR integrator_name + +is similar to: + +.. code-block:: console + + #INCLUDE $KPP_HOME/int/integrator_name.def + +The :command:`#INTEGRATOR` command allows the use of different +integration techniques on the same model. If it occurs twice, the second +replaces the first. Normally, KPP tries to find the selected integrator +files in the directory :file:`$KPP_HOME/int/`. However, if the supplied +file name contains a slash, it is assumed to be absolute. To access an +integrator in the current directory, the prefix :file:`./` can be used, +e.g.: + +.. code-block:: console + + #INTEGRATOR ./mydeffile + +.. _intfile-cmd: + +======== +#INTFILE +======== + +.. attention:: + + :command:`#INTFILE` is used internally by KPP but should not be used + by the KPP user. Using :ref:`integrator-cmd` alone suffices to + specify an integrator. + +The integrator definition file selects an integrator file with +:command:`#INTFILE` and also defines some suitable options for it. The +:command:`#INTFILE` command selects the file that contains the integrator +routine. The parameter of the +command is a file name, without suffix. The appropriate suffix +(:code:`.f90`, :code:`.F90`, :code:`.c`, or :code:`.m` is appended and +the result selects the file from which the integrator +is taken. This file will be copied into the code file in the appropriate +place. + +.. _jacobian-cmd: + +========= +#JACOBIAN +========= + +The :command:`#JACOBIAN` command controls which functions are generated +to compute the Jacobian. The option :command:`OFF` inhibits the +generation of the Jacobian routine. The option :command:`FULL` generates +the Jacobian as a square :code:`NVAR x NVAR` matrix. It should only be +used if the integrator needs the whole Jacobians. The options +:command:`SPARSE_ROW` and :command:`SPARSE_LU_ROW` (the default) both +generate the Jacobian in sparse (compressed on rows) format. They should +be used if the integrator needs the whole Jacobian, but in a sparse +form. The format used is compressed on rows. With +:command:`SPARSE_LU_ROW`, KPP extends the number of nonzeros to account +for the fill-in due to the LU decomposition. + +.. _language-cmd: + +========= +#LANGUAGE +========= + +.. attention:: + + The :command:`Fortran77` language option is deprecated in + :ref:`kpp250` and later versions. All further KPP development will + only support Fortran90. + +The :command:`#LANGUAGE` command selects the target language in which the +code file is to be generated. Available options are :command:`Fortran90`, +:command:`C`, or :command:`matlab`. + +You can select the suffix (:code:`.F90` or :code:`.f90`) to use for +Fortran90 source code generated by KPP (cf. :ref:`uppercasef90-cmd`). + +.. _mex-cmd: + +==== +#MEX +==== + +:program:`Mex` is a Matlab extension that allows +to call functions written in Fortran and C directly from within the +Matlab environment. KPP generates the mex interface routines for the +ODE function, Jacobian, and Hessian, for the target languages C, +Fortran77, and Fortran90. The default is :command:`#MEX ON`. With +:command:`#MEX OFF`, no Mex files are generated. + +.. _minversion-cmd: + +=========== +#MINVERSION +=========== + +You may restrict a chemical mechanism to use a given version of KPP or +later. To do this, add + +.. code-block:: console + + #MINVERSION X.Y.Z + +to the definition file. + +The version number (:code:`X.Y.Z`) adheres to the Semantic +Versioning style (https://semver.org), where :code:`X` is the major +version number, :code:`Y` is the minor version number, and :code:`Z` is the +bugfix (aka “patch”) version number. + +For example, if :command:`#MINVERSION 2.4.0` is specified, then KPP will +quit with an error message unless you are using KPP 2.4.0 or later. + +.. _model-cmd: + +====== +#MODEL +====== + +The chemical model contains the description of the atoms, species, and +chemical equations. It also contains default initial values for the +species and default options including a suitable integrator for the +model. In the simplest case, the main kinetic description file, i.e. the +one passed as parameter to KPP, can contain just a single line selecting +the model. KPP tries to find a file with the name of the model and the +suffix :file:`.def` in the :file:`$KPP_HOME/models` subdirectory. This +file is then parsed. The content of the model definition file is written +in the KPP language. The model definition file points to a species file +and an equation file. The species file includes further the atom +definition file. All default values regarding the model are +automatically selected. For convenience, the best integrator and driver +for the given model are also automatically selected. + +The :command:`#MODEL` command is optional, and intended for using a +predefined model. Users who supply their own reaction mechanism do not +need it. + +.. _reorder-cmd: + +======== +#REORDER +======== + +Reordering of the species is performed in order to minimize the fill-in +during the LU factorization, and therefore preserve the sparsity +structure and increase efficiency. The reordering is done using a +diagonal Markowitz algorithm. The details are explained in +:cite:t:`Sandu_et_al._1996`. The default is :command:`ON`. +:command:`OFF` means that KPP does not reorder the species. The order +of the variables is the order in which the species are +declared in the :command:`#DEFVAR` section. + +.. _stochastic-cmd: + +=========== +#STOCHASTIC +=========== + +The option :command:`ON` of the :command:`#STOCHASTIC` command turns +on the generation of code for stochastic kinetic simulations (see the +section entitled :ref:`Stochastic`. The default option is :command:`OFF`. + +.. _stoicmat-cmd: + +========= +#STOICMAT +========= + +Unless the :command:`#STOICMAT` command is set to :command:`OFF`, KPP +generates code for the stoichiometric matrix, the vector of reactant +products in each reaction, and the partial derivative of the time +derivative function with respect to rate coefficients +(cf. :ref:`Stoichiom-and-StoichiomSP`). + +.. _checkall-lookatall-cmd: + +===================== +#CHECKALL, #LOOKATALL +===================== + +The shorthand commands :command:`#CHECKALL` and :command:`#LOOKATALL` +apply :command:`#CHECK` and :command:`#LOOKAT`, respectively, to all +species in the mechanism. + +.. _uppercasef90-cmd: + +============= +#UPPERCASEF90 +============= + +If you have selected :command:`#LANGUAGE Fortran90` option, KPP will +generate source code ending in :code:`.f90` by default. Setting +:command:`#UPPERCASEF90 ON` will tell KPP to generate Fortran90 code +ending in :code:`.F90` instead. diff --git a/docs/source/input/kpp_sections.rst b/docs/source/input/kpp_sections.rst new file mode 100644 index 0000000..9b155dc --- /dev/null +++ b/docs/source/input/kpp_sections.rst @@ -0,0 +1,310 @@ +.. _kpp-sections: + +############ +KPP sections +############ + +A :literal:`#` sign at the beginning of a line followed by a section +name starts a new KPP section. Then a list of items separated by +semicolons follows. A section ends when another KPP section or command +occurs, i.e. when another :literal:`#` sign occurs at the beginning of +a line. The syntax of an item definition is different for each +particular section. + +.. _atoms: + +====== +#ATOMS +====== + +The atoms that will be further used to specify the components of a +species must be declared in an :command:`#ATOMS` section, e.g.: + +.. code-block:: console + + #ATOMS N; O; Na; Br; + +Usually, the names of the atoms are the ones specified in the periodic +table of elements. For this table there is a predefined file containing +all definitions that can be used by the command: + +.. code-block:: console + + #INCLUDE atoms.kpp + +This should be the first line in a KPP input file, because it allows to +use any atom in the periodic table of elements throughout the kinetic +description file. + +.. _check: + +====== +#CHECK +====== + +KPP is able to do mass balance checks for all equations. Some chemical +equations are not balanced for all atoms, and this might still be +correct from a chemical point of view. To accommodate for this, KPP can +perform mass balance checking only for the list of atoms specified in +the :command:`#CHECK` section, e.g.: + +.. code-block:: console + + #CHECK N; C; O; + +The balance checking for all atoms can be enabled by using the +:command:`#CHECKALL` command. Without :command:`#CHECK` or +:command:`#CHECKALL`, no checking is performed. The :literal:`IGNORE` +atom can also be used to control mass balance checking. + +.. _defvar-and-deffix: + +=================== +#DEFVAR and #DEFFIX +=================== + +There are two ways to declare new species together with their atom +composition: :command:`#DEFVAR` and :command:`#DEFFIX`. These sections +define all the species that will be used in the chemical mechanism. +Species can be variable or fixed. The type is implicitly specified by +defining the species in the appropriate sections. A fixed species does +not vary through chemical reactions. + +For each species the user has to declare the atom composition. This +information is used for mass balance checking. To ignore mass balance +checking for a given species, one can declare the predefined atom +:command:`IGNORE` as being part of the species composition. Examples +for these sections are: + +.. code-block:: console + + #DEFVAR + NO2 = N + 2O; + CH3OOH = C + 4H + 2O; + HSO4m = IGNORE; + RCHO = IGNORE; + #DEFFIX + CO2 = C + 2O; + +.. _equations: + +========== +#EQUATIONS +========== + +The chemical mechanism is specified in the :command:`#EQUATIONS` +section. Each equation is written in the natural way in which a +chemist would write it: + +.. code-block:: console + + #EQUATIONS + + NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0); + O3P + O2 + AIR = O3 : ARR_ac(5.68e-34, -2.80); + O3P + O3 = 2O2 : ARR_ab(8.00e-12, 2060.0); + O3P + NO + AIR = NO2 : ARR_ac(1.00e-31, -1.60); + //... etc ... + +.. note:: + + The above example is taken from the :command:`saprc99` mechanism + (see :file:`models/saprc99.eqn`), with some whitespace deleted for + clarity. Optional :ref:`equation tags ` are specified + by text within :code:`< >` angle brackets. Functions that compute + **saprc99** equation rates (e.g. :code:`ARR_ac`, + :code:`ARR_ab`) are defined in :file:`util/UserRateLaws.f90` + and :file:`util/UserRateLawsInterfaces.f90`. + +Only the names of already defined species can be used. The rate +coefficient has to be placed at the end of each equation, separated by a +colon. The rate coefficient does not necessarily need to be a numerical +value. Instead, it can be a valid expression (or a call to an +:ref:`inlined rate law function `) in the :ref:`target +language `. If there are several :command:`#EQUATIONS` +sections in the input, their contents will be concatenated. + +A minus sign in an equation shows that a species is consumed in a +reaction but it does not affect the reaction rate. For example, the +oxidation of methane can be written as: + +.. code-block:: console + + CH4 + OH = CH3OO + H2O - O2 : k_CH4_OH; + +However, it should be noted that using negative products may lead to +numerical instabilities. + +Often, the stoichiometric factors are integers. However, it is also +possible to have non-integer yields, which is very useful to +parameterize organic reactions that branch into several side reactions: + +.. code-block:: console + + CH4 + O1D = .75 CH3O2 + .75 OH + .25 HCHO + 0.4 H + .05 H2 : k_CH4_O1D; + +KPP provides two pre-defined dummy species: :literal:`hv` and +:literal:`PROD`. Using dummy species does not affect the numerics of +the integrators. It only serves to improve the readability of the +equations. For photolysis reactions, :literal:`hv` can be specified as +one of the reagents to indicate that light (:math:`h\nu`) is needed for this +reaction, e.g.: + +.. code-block:: console + + NO2 + hv = NO + O : J_NO2; + +When the products of a reaction are not known or not important, the +dummy species :literal:`PROD` should be used as a product. This is +necessary because the KPP syntax does not allow an empty list of +products. For example, the dry deposition of atmospheric ozone to the +surface can be written as: + +.. code-block:: console + + O3 = PROD : v_d_O3; + +The same equation must not occur twice in the :command:`#EQUATIONS` +section. For example, you may have both the gas-phase reaction of +:literal:`N2O5` with water in your mechanism and also the +heterogeneous reaction on aerosols: + +.. code-block:: console + + N2O5 + H2O = 2 HNO3 : k_gas; + N2O5 + H2O = 2 HNO3 : k_aerosol; + +These reactions must be merged by adding the rate coefficients: + +.. code-block:: console + + N2O5 + H2O = 2 HNO3 : k_gas + k_aerosol; + +.. _families: + +========= +#FAMILIES +========= + +Chemical families (for diagnostic purposes) may be specified in the +:command:`#FAMILIES` section as shown below. Family names beginning +with a :code:`P` denote production, and those beginning with an +:code:`L` denote loss. + +.. code-block:: console + + #FAMILIES + POx : O3 + NO2 + 2NO3 + HNO3 + ... etc. add more species as needed ... + LOx : O3 + NO2 + 2NO3 + HNO3 + ... etc. add more species as needed ... + PCO : CO; + LCO : CO; + PSO4 : SO4; + LCH4 : CH4; + PH2O2 : H2O2; + +KPP will examine the chemical mechanism and create a dummy species for +each defined family. Each dummy species will archive the production +and loss for the family. For example, each molecule of CO that is +produced will be added to the :code:`PCO` dummy species. Likewise, +each molecule of CO that is consumed will be added to the :code:`LCO` +dummy species. This will allow the :code:`PCO` and :code:`LCO` species +to be later archived for diagnostic purposes. Dummy species for chemical +families will not be included as active species in the mechanism. + +.. _initvalues: + +=========== +#INITVALUES +=========== + +The initial concentration values for all species can be defined in the +:command:`#INITVALUES` section, e.g.: + +.. code-block:: console + + #INITVALUES + CFACTOR = 2.5E+19; + NO2 = 1.4E-9; + CO2 = MyCO2Func(); + ALL_SPEC = 0.0; + +If no value is specified for a particular species, the default value +zero is used. One can set the default values using the generic species +names: :code:`VAR_SPEC`, :code:`FIX_SPEC`, and :code:`ALL_SPEC`. In order +to use coherent units for concentration and rate coefficients, it is +sometimes necessary to multiply each value by a constant factor. This +factor can be set by using the generic name :code:`CFACTOR`. Each of +the initial values will be multiplied by this factor before being +used. If :code:`CFACTOR` is omitted, it defaults to one. + +The information gathered in this section is used to generate the +:code:`Initialize` subroutine (cf :ref:`Initialize`). In more complex 3D +models, the initial values are usually taken from some input files or +some global data structures. In this case, :command:`#INITVALUES` may +not be needed. + +.. note:: + + If you are building your mechanism in Fortran 90, note that using + floating point constants such as :literal:`2.5E+19` will only give + you a single precision value (which will incur roundoff error after + the 6th or 7th decimal place. + + If you are using double precision, you should use Fortran double + precision exponents (e.g. :literal:`2.5D+19`) instead. This will + give you a true double precision value. + +.. _lookat-and-monitor: + +==================== +#LOOKAT and #MONITOR +==================== + +There are two sections in this category: :command:`#LOOKAT` and +:command:`#MONITOR`. + +The section instructs the preprocessor what are the species for which +the evolution of the concentration, should be saved in a data file. By +default, if no :command:`#LOOKAT` section is present, all the species +are saved. If an atom is specified in the :command:`#LOOKAT` list then +the total mass of the particular atom is reported. This allows to +check how the mass of a specific atom was conserved by the integration +method. The :command:`#LOOKATALL` command can be used to specify all +the species. Output of :command:`#LOOKAT` can be directed to the file +:file:`ROOT.dat` using the utility subroutines described in the +section entitled :ref:`Util`. + +The :command:`#MONITOR` section defines a different list of species +and atoms. This list is used by the driver to display the +concentration of the elements in the list during the integration. This +may give us a feedback of the evolution in time of the selected +species during the integration. The syntax is similar to the +:command:`#LOOKAT` section. With the driver :code:`general`, +output of :command:`#MONITOR` goes to the screen (STDOUT). The order +of the output is: first variable species, then fixed species, finally +atoms. It is not the order in the :command:`MONITOR` command. + +Examples for these sections are: + +.. code-block:: console + + #LOOKAT NO2; CO2; O3; N; + #MONITOR O3; N; + +.. _setvar-and-setfix: + +=================== +#SETVAR and #SETFIX +=================== + +The commands :command:`#SETVAR` and :command:`#SETFIX` change the type of an +already defined species. Then, depending on the integration method, +one may or may not use the initial classification, or can easily move +one species from one category to another. The use of the generic +species :code:`VAR_SPEC`, :code:`FIX_SPEC`, and :code:`ALL_SPEC` is +also allowed. Examples for these sections are: + +.. code-block:: console + + #SETVAR ALL_SPEC; + #SETFIX H2O; CO2; diff --git a/docs/source/num_methods/backward_diff.rst b/docs/source/num_methods/backward_diff.rst new file mode 100644 index 0000000..a13079e --- /dev/null +++ b/docs/source/num_methods/backward_diff.rst @@ -0,0 +1,72 @@ +.. _back-diff: + +################################ +Backward differentiation methods +################################ + +Backward differentiation formulas (BDF) are linear multistep methods +with excellent stability properties for the integration of chemical +systems (cf. :cite:t:`Hairer_and_Wanner_1991`, Section V.1). The +:math:`k`-step BDF method reads + +.. math:: + + \sum_{i=0}^k \alpha_i y^{n-i} = h_n \beta\; f\left(t^{n},y^{n}\right) + \label{BDF} + +where the coefficients :math:`\alpha_i` and :math:`\beta` are chosen +such that the method has order of consistency :math:`k`. + +The KPP library contains two off-the-shelf, highly popular +implementations of BDF methods, described in the following sections: + +.. _back-diff-lsode: + +===== +LSODE +===== + +**Integrator file:** :file:`int/lsode.f90` + +LSODE, the Livermore ODE solver +(:cite:t:`Radhakrishnan_and_Hindmarsh_1993`), implements backward +differentiation formula (BDF) methods for stiff problems. LSODE has +been translated to Fortran90 for the incorporation into the KPP library. + +.. attention:: + + We have discovered that the current implementation of the LSODE + integrator is not thread-safe for `OpenMP parallelization + `_. When LSODE is called from within + an OpenMP parallel loop, the integration will fail because key + internal variables in LSODE will be overwritten by concurrent + threads. + +.. _back-diff-vode: + +==== +VODE +==== + +**Integrator file:** :file:`int/dvode.f90` + +VODE (:cite:t:`Brown_Byrne_and_Hindmarsh_1989`) uses another formulation +of backward differentiation formulas. The version of VODE present in +the KPP library uses directly the KPP sparse linear algebra routines. + +.. _back-diff-beuler: + +====== +BEULER +====== + +**Integrator file:** :file:`int/sdirk.f90` + +Backward Euler integration method. To request this method, make sure +you select + +.. code-block:: console + + #INTEGRATOR sdirk + +in your definition file, and then set :code:`ICNTRL(3) = 6`. diff --git a/docs/source/num_methods/controlling_the_integrator.rst b/docs/source/num_methods/controlling_the_integrator.rst new file mode 100644 index 0000000..074ffd4 --- /dev/null +++ b/docs/source/num_methods/controlling_the_integrator.rst @@ -0,0 +1,690 @@ +.. _icntrl-rcntrl: + +###################################################### +Integrator options (:code:`ICNTRL` and :code:`RCNTRL`) +###################################################### + +In order to offer more control over the integrator, KPP provides the +arrays :code:`ICNTRL` (integer) and :code:`RCNTRL` (real). Each of them +is an array of 20 elements that allow the fine-tuning of the integrator. +All integrators (except for :code:`tau_leap` and :code:`gillespie`) use +:code:`ICNTRL` and :code:`RCNTRL`. Details can be found in the comment +lines of the individual integrator files in :code:`$KPP_HOME/int/`. + +====== +ICNTRL +====== + +.. _table-icntrl: + +.. table:: Summary of ICNTRL usage in the f90 integrators. + Here, Y = used, and s = solver-specific usage. + :align: center + + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | ICNTRL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | + +========================+===+===+===+===+===+===+===+===+===+====+====+====+====+====+====+====+====+====+ + | beuler | | Y | Y | Y | Y | Y | s | | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | dvode | | | | | | | | | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | exponential | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | feuler | | | | | | | | | | | | | | | Y | Y | Y | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | gillespie | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | lsode | | Y | | Y | | | | | | s | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | radau5 | | Y | | Y | Y | Y | | | | | Y | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | rosenbrock_adj | Y | Y | Y | Y | | s | s | s | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | rosenbrock | Y | Y | Y | Y | | | | | | | | | | | Y | Y | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | rosenbrock_tlm | Y | Y | Y | Y | | | | | | | | s | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | rosenbrock_autoreduce | Y | Y | Y | Y | | | | | | | | s | s | s | Y | Y | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | rosenbrock_h211b_qssa | Y | Y | Y | Y | | | | | | | | | | | Y | Y | | s | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | runge_kutta_adj | | Y | Y | Y | Y | s | s | s | s | s | Y | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | runge_kutta | | Y | Y | Y | Y | Y | | | | s | Y | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | runge_kutta_tlm | | Y | Y | | Y | Y | s | | s | s | Y | s | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | sdirk4 | | Y | | Y | | | | | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | sdirk_adj | | Y | Y | Y | Y | Y | s | s | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | sdirk | | Y | Y | Y | Y | Y | | | | | | | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | sdirk_tlm | | Y | Y | Y | Y | Y | s | | s | | | s | | | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | seulex | Y | Y | | Y | | | | | | s | s | s | s | s | Y | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + | tau_leap | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ + +ICNTRL(1) +--------- + +Specifies the time-dependence of the function :math:`F` to be integrated: + +.. table:: + :align: left + + +------------+----------------------------------------+ + | ICNTRL(1) | Time dependence of :math:`F` | + +============+========================================+ + | 0 | :math:`F = F(t,y)` aka non-autonomous | + +------------+----------------------------------------+ + | 1 | :math:`F = F(y)` aka autonomous | + +------------+----------------------------------------+ + +ICNTRL(2) +--------- + +Specifies the dimensionality of the absolute (:code:`ATOL`) and +relative (:code:`RTOL`) tolerances. These can be expressed by +either a scalar or individually for each species in a vector. + +.. table:: + :align: left + + +------------+-------------------------------------------+ + | ICNTRL(2) | Dimensionality of ``ATOL`` and ``RTOL`` | + +============+===========================================+ + | 0 | :code:`NVAR` -dimensional vector | + +------------+-------------------------------------------+ + | 1 | scalar | + +------------+-------------------------------------------+ + +ICNTRL(3) +--------- + +Selects a specific integration method. + +.. table:: + :align: left + + +-----------------------+------------+-----------------------+ + | Integrator | ICNTRL(3) | Method selected | + +=======================+============+=======================+ + | rosenbrock | 0 or 4 | Rodas3 (default) | + | +------------+-----------------------+ + | rosenbrock_adj | 1 | Ros2 | + | +------------+-----------------------+ + | rosenbrock_autoreduce | 2 | Ros3 | + | +------------+-----------------------+ + | rosenbrock_tlm | 3 | Ros4 | + | +------------+-----------------------+ + | | 5 | Rodas4 | + | +------------+-----------------------+ + | | 6 | Rang | + | +------------+-----------------------+ + | | 7 | Rodas3.1 | + +-----------------------+------------+-----------------------+ + | runge_kutta | 0 or 1 | Radau-2A (default) | + | +------------+-----------------------+ + | runge_kutta_adj | 2 | Lobatto-3C | + | +------------+-----------------------+ + | runge_kutta_tlm | 3 | Gauss | + | +------------+-----------------------+ + | | 4 | Radau-1A | + | +------------+-----------------------+ + | | 5 | Lobatto-3A | + +-----------------------+------------+-----------------------+ + | sdirk | 0 or 1 | Sdirk-2A (default) | + | +------------+-----------------------+ + | sdirk_adj | 2 | Sdirk-2B | + | +------------+-----------------------+ + | sdirk_tlm | 3 | Sdirk-3A | + | +------------+-----------------------+ + | | 4 | Sdirk-4A | + | +------------+-----------------------+ + | | 5 | Sdirk-4B | + | +------------+-----------------------+ + | | 6 | Backward Euler | + +-----------------------+------------+-----------------------+ + + +ICNTRL(4) +--------- + +Specifies the maximum number of integration steps. + +ICNTRL(5) +--------- + +Specifies the maximum number of Newton iterations. + +ICNTRL(6) +--------- + +Selects integrator-specific settings. + +.. table:: + :align: left + + +-----------------+------------+-----------------------------------+ + | Integrator | ICNTRL(6) | Option selected | + +=================+============+===================================+ + | rosenbrock_adj | 0 thru 6 | Selection of a particular | + | | | Rosenbrock method for the | + | | | continuous adjoint integration | + | | | (see ``ICNTRL(3)``) | + +-----------------+------------+-----------------------------------+ + | radau5 | 0 | Starting values for Newton | + | | | iterations are interpolated | + | | | (default) | + | runge_kutta_adj +------------+-----------------------------------+ + | | 1 | Starting values for Newton | + | runge_kutta_tlm | | iterations are zero | + | | | | + | sdirk | | | + | | | | + | sdirk_adj | | | + | | | | + | sdirk_tlm | | | + +-----------------+------------+-----------------------------------+ + +ICNTRL(7) +--------- + +Selects options for adjoint integrators. + +.. table:: Selection of adjoint algorithm + :align: left + + +-----------------+------------+----------------------------------+ + | Integrator | ICNTRL(7) | Adjoint algorithm selected | + +=================+============+==================================+ + | rosenbrock_adj | 0 or 2 | Discrete adjoint with method | + | | | ``ICNTRL(3)`` (default) | + | +------------+----------------------------------+ + | | 1 | No adjoint | + | +------------+----------------------------------+ + | | 3 | Fully adaptive continous adjoint | + | | | with method ``ICNTRL(6)`` | + | +------------+----------------------------------+ + | | 4 | Simplified continuous adjoint | + | | | with method ``ICNTRL(6)`` | + +-----------------+------------+----------------------------------+ + +.. table:: Method to solve the linear Adj equations + :align: left + + +-----------------+------------+----------------------------------+ + | Integrator | ICNTRL(7) | Method selected | + +=================+============+==================================+ + | runge_kutta_adj | 0 or 1 | Modified Newton re-using LU | + | | | (default) | + | +------------+----------------------------------+ + | | 2 | Direct solution (additional one | + | | | LU factorizsation of 3Nx3N | + | | | matrix per step; good for | + | | | debugging | + | +------------+----------------------------------+ + | | 3 | Adaptive solution (if Newton | + | | | does not converge, switch to | + | | | direct) | + +-----------------+------------+----------------------------------+ + | sdirk_adj | 0 | Modified Newton re-using LU | + | | | (default) | + | sdirk_tlm +------------+----------------------------------+ + | | 1 | Direct solution (additional one | + | | | LU factorizsation per stage) | + +-----------------+------------+----------------------------------+ + +ICNTRL(8) +--------- + +Determines if LU factorization will be checkpointed at each step +(for adjoint integrators only). + +.. table:: + :align: left + + +-----------------+------------+------------------------------------+ + | Integrator | ICNTRL(8) | Option selected | + +=================+============+====================================+ + | rosenbrock_adj | 0 | Do not save LU factorization at | + | | | each step (default) | + | runge_kutta_adj +------------+------------------------------------+ + | | 1 | Save LU factorization at each step | + | sdirk_adj | | | + +-----------------+------------+------------------------------------+ + +ICNTRL(9) +--------- + +Selects options for adjoint and tangent linear method (TLM) +integrators. + +.. table:: Selection of adjoint algorithm + :align: left + + +-----------------+------------+----------------------------------+ + | Integrator | ICNTRL(9) | Adjoint algorithm selected | + +=================+============+==================================+ + | runge_kutta_adj | 0 or 2 | Discrete adjoint with method | + | | | ``ICNTRL(3)`` (default) | + | +------------+----------------------------------+ + | | 1 | No adjoint | + | +------------+----------------------------------+ + | | 3 | Fully adaptive continous adjoint | + | | | with method ``ICNTRL(6)`` | + | +------------+----------------------------------+ + | | 4 | Simplified continuous adjoint | + | | | with method ``ICNTRL(6)`` | + +-----------------+------------+----------------------------------+ + +.. table:: Selection of tangent linear method (TLM) error + estimation strategy + :align: left + + +-----------------+------------+-----------------------------------+ + | Integrator | ICNTRL(9) | Strategy selected | + +=================+============+===================================+ + | runge_kutta_tlm | 0 | Base number of iterations as | + | | | forward solution | + | sdirk_tlm +------------+-----------------------------------+ + | | 1 | USE ``ATOL_tlm`` and ``RTOL_tlm`` | + | | | to calculate error estimation | + | | | for TLM at Newton stages | + +-----------------+------------+-----------------------------------+ + +ICNTRL(10) +---------- + +Selects integrator-specific options. + +.. table:: + :align: left + + +-----------------+------------+-----------------------------------+ + | Integrator | ICNTRL(10) | Option selected | + +=================+============+===================================+ + | lsode | user | Maximum order of the integration | + | | supplied | formula allowed | + +-----------------+------------+-----------------------------------+ + | runge_kutta | 0 | Error estimation strategy: | + | | | one additional stage at ``c=0`` | + | runge_kutta_adj | | (default) | + | +------------+-----------------------------------+ + | runge_kutta_tlm | 1 | Error estimation strategy: | + | | | Two additional stages at ``c=0`` | + | | | and SDIRK at ``c=1``, stiffly | + | | | accurate | + | +------------+-----------------------------------+ + | | | | + +-----------------+------------+-----------------------------------+ + | seulex | 0 | No verbose output | + | +------------+-----------------------------------+ + | | 1 | Dense verbose output | + +-----------------+------------+-----------------------------------+ + +ICNTRL(11) +---------- + +Selects integrator-specific settings. + +.. table:: + :align: left + + +-----------------+------------+-----------------------------------+ + | Integrator | ICNTRL(11) | Option selected | + +=================+============+===================================+ + | seulex | user | Maximum number of columns in the | + | | supplied | extrapolation. Default is 12. | + +-----------------+------------+-----------------------------------+ + | radau5 | 0 | Gustaffson step size control | + | +------------+-----------------------------------+ + | | 1 | Classical step size control | + | runge_kutta | | | + | | | | + | runge_kutta_adj | | | + | | | | + | runge_kutta_tlm | | | + | | | | + | | | | + +-----------------+------------+-----------------------------------+ + +ICNTRL(12) +---------- + +Selects integrator-specific settings. + +.. table:: + :align: left + + +-----------------------+------------+-----------------------------------+ + | Integrator | ICNTRL(12) | Option selected | + +=======================+============+===================================+ + | rosenbrock_autoreduce | 0 | Disable mechanism auto-reduction | + | | | (i.e. acts in the same way as the | + | | | ``rosenbrock`` integrator) | + | +------------+-----------------------------------+ + | | 1 | Enables mechanism auto-reduction, | + | | | set threshold in ``RCNTRL(`12)`` | + | +------------+-----------------------------------+ + | | | | + +-----------------------+------------+-----------------------------------+ + | rosenbrock_tlm | 0 | TLM truncation error is not used | + | +------------+-----------------------------------+ + | runge_kutta_tlm | 1 | TLM truncation error is computed | + | | | and used | + | sdirk_tlm | | | + | +------------+-----------------------------------+ + | | | | + +-----------------------+------------+-----------------------------------+ + | seulex | 0 | Nsequence = 2 (default) | + | +------------+-----------------------------------+ + | | 1 | Nsequence = | + | | | 1,2,3,4,6,8,12,16,24,32,48,... | + | +------------+-----------------------------------+ + | | 2 | Nsequence = | + | | | 2,3,4,6,8,12,16,24,32,48,64,... | + | +------------+-----------------------------------+ + | | 3 | Nsequence = | + | | | 1,2,3,4,5,6,7,8,9,10,... | + | +------------+-----------------------------------+ + | | 4 | Nsequence = | + | | | 2,3,4,5,6,7,8,9,10,11,... | + +-----------------------+------------+-----------------------------------+ + +ICNTRL(13) +---------- + +Selects integrator-specific settings. + +.. table:: + :align: left + + +-----------------------+------------+-----------------------------------+ + | Integrator | ICNTRL(13) | Option selected | + +=======================+============+===================================+ + | rosenbrock_autoreduce | 0 | In auto-reduction, disables | + | | | scanning species P and L rates | + | | | throughout the internal timesteps | + | | | of the integrator. | + | +------------+-----------------------------------+ + | | 1 | In auto-reduction, ensables | + | | | scanning species P and L rates | + | | | throughout the internal timesteps | + | | | of the integrator, for | + | | | repartitioning. | + +-----------------------+------------+-----------------------------------+ + | seulex | 0, 1 | Sets the ``lambda`` parameter | + | | | for verbose output. | + +-----------------------+------------+-----------------------------------+ + +ICNTRL(14) +---------- + +(Solver-specific for :code:`rosenbrock_autoreduce`) If set to +:code:`> 0`, then the threshold is calculated based on the max of +production and loss rate of the species ID specified in +:code:`ICNTRL(14)` multiplied by :code:`RCNTRL(14)`. + +ICNTRL(15) +---------- + +Determines which :code:`Update_*` subroutines are called within the +integrator. + +.. list-table:: + :align: left + :header-rows: 1 + + * - ICNTRL(15) + - Option selcted + * - -1 + - Do not call any :code:`Update_*` subroutines + * - 0 + - Use the integrator-specific default values + * - 1 + - Call :code:`Update_RCONST` from within the integrator. + * - 2 + - Call :code:`Update_PHOTO` from within the integrator + * - 3 + - Call :code:`Update_RCONST` and :code:`Update_PHOTO` from within + the integrator. + * - 4 + - Call :code:`Update_SUN` from within the integrator + * - 5 + - Call :code:`Update_SUN` and :code:`Update_RCONST` from within + the integrator + * - 6 + - Call :code:`Update_SUN` and :code:`Update_PHOTO` from within + the integrator. + * - 7 + - Call :code:`Update_SUN`, :code:`Update_PHOTO`, and + :code:`Update_RCONST` from within the integrator. + +Calling :code:`Update_RCONST` may be necessary when reaction rate +coefficients depend on the concentration of a specific species, e. +g.: + +.. code-block:: console + + HSO3m + HSO5m + Hp = 2 HSO4m + Hp : k_aqueous( C(ind_Hp) ); + +This ensures that the concentration :code:`C(ind_Hp)` at the specific +integration time is used when the reaction rate coefficient is +updated within the integrator. + +ICNTRL(16) +---------- + +Specifies how negative values should be handled. + +.. list-table:: + :align: left + :header-rows: 1 + + * - ICNTRL(16) + - Option selcted + * - 0 + - Leave negative values unchanged + * - 1 + - Set negative values to zero + * - 2 + - Print warning and continue + * - 3 + - Print error message and stop + +ICNTRL(17) +---------- + +Selects the amount of verbose output that will be generated. + +.. list-table:: + :align: left + :header-rows: 1 + + * - ICNTRL(17) + - Option selcted + * - 0 + - Only return error number + * - 1 + - Full verbose error output + +ICNTRL(18) +---------- + +Currently not used. + +ICNTRL(19) +---------- + +Currently not used. + +ICNTRL(20) +---------- + +Currently not used. + +====== +RCNTRL +====== + +.. _table-rcntrl: + +.. table:: Summary of RCNTRL usage in the f90 integrators. + Here, Y = used, and s = solver-specific usage. + :align: center + + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | RCNTRL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | + +========================+===+===+===+===+===+===+===+===+===+====+====+====+====+====+====+====+====+====+====+ + | beuler | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | dvode | | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | exponential | | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | feuler | | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | gillespie | | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | lsode | Y | Y | Y | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | radau5 | | Y | | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | rosenbrock_adj | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | rosenbrock | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | rosenbrock_tlm | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | rosenbrock_autoreduce | Y | Y | Y | Y | Y | Y | Y | | | | | s | | s | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | rosenbrock_h211b_qssa | Y | Y | Y | Y | Y | Y | Y | | | | | | | | s | s | s | s | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | runge_kutta_adj | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | runge_kutta | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | runge_kutta_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | sdirk4 | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | sdirk_adj | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | sdirk | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | sdirk_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | seulex | Y | Y | Y | Y | Y | Y | Y | Y | | s | s | s | s | s | s | s | s | s | s | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + | tau_leap | | | | | | | | | | | | | | | | | | | | + +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ + +RCNTRL(1) +--------- + +:code:`Hmin`, the lower bound of the integration step size. It is +not recommended to change the default value of zero. + +RCNTRL(2) +--------- + +:code:`Hmax`, the upper bound of the integration step size. + +RCNTRL(3) +--------- + +:code:`Hstart`, the starting value of the integration step size. + +RCNTRL(4) +--------- + +:code:`FacMin`, lower bound on step decrease factor. + +RCNTRL(5) +--------- + +:code:`FacMax`, upper bound on step increase factor. + +RCNTRL(6) +--------- + +:code:`FacRej`, step decrease factor after multiple rejections. + +RCNTRL(7) +--------- + +:code:`FacSafe`, the factor by which the new step is slightly +smaller than the predicted value. + +RCNTRL(8) +--------- + +:code:`ThetaMin`. If the Newton convergence rate is smaller than +ThetaMin, the Jacobian is not recomputed. + +RCNTRL(9) +--------- + +:code:`NewtonTol`, the stopping criterion for Newton’s method. + +RCNTRL(10) +---------- + +:code:`Qmin` + +Different, solver-specific settings for :code:`seulex`. + +RCNTRL(11) +---------- + +:code:`Qmax`. If :code:`Qmin < Hnew/Hold < Qmax`, then the step +size is kept constant and the LU factorization is reused. + +Different, solver-specific settings for :code:`seulex`. + +RCNTRL(12) +---------- + +(Solver-specific for :code:`rosenbrock_autoreduce`) Used to specify +the threshold for auto-reduction partitioning, if :code:`ICNTRL(12) = 1`, +and :code:`ICNTRL(14) = 0`. Will be ignored if :code:`ICNTRL(14) > 0`. + +Different, solver-specific settings for :code:`seulex`. + +RCNTRL(13) +---------- + +Solver-specific settings for :code:`seulex`. + +RCNTRL(14) +---------- + +(Solver-specific for :code:`rosenbrock_autoreduce`) Used to specify +the multiplier for threshold for auto-reduction partitioning, if +:code:`ICNTRL(12) = 1`, and :code:`ICNTRL(14) > 0`, :code:`RCNTRL(14)` +is multiplied against max of production and loss rates of species +:code:`ICNTRL(14)` to produce the partitioning threshold, ignoring +:code:`RCNTRL(12)`. + +Different, solver-specific settings for :code:`seulex`. + +RCNTRL(15) - RCNTRL(18) +----------------------- + +Solver-specific settings for :code:`rosenbrock_h211b_qssa`. + +Different, solver-specific settings for :code:`seulex`. + +RCNTRL(19) +---------- + +Solver-specific settings for :code:`seulex`. + +RCNTRL(20) +---------- + +Currently not used. diff --git a/docs/source/num_methods/forward_diff.rst b/docs/source/num_methods/forward_diff.rst new file mode 100644 index 0000000..20015a2 --- /dev/null +++ b/docs/source/num_methods/forward_diff.rst @@ -0,0 +1,22 @@ +.. _other-methods: + +############################### +Forward differentiation methods +############################### + +.. _other-methods-feuler: + +FEULER +------ + +**Integrator file:** :file:`int/feuler.f90` + +Forward Euler is an explicit integration method for non-stiff problems. +FEULER computes +:math:`y^{n+1}` as + +.. math:: + + \begin{aligned} + y^{n+1} = y^n + hf\left(t^{n},y^{n}\right) + \end{aligned} diff --git a/docs/source/num_methods/output_from_integrators.rst b/docs/source/num_methods/output_from_integrators.rst new file mode 100644 index 0000000..ac775a3 --- /dev/null +++ b/docs/source/num_methods/output_from_integrators.rst @@ -0,0 +1,206 @@ +.. _output-from-int: + +####################################################### +Integrator status (:code:`ISTATUS` and :code:`RSTATUS`) +####################################################### + +In order to obtain more information about the integration, KPP provides +the arrays :code:`ISTATUS` (integ mer) and :code:`RSTATUS` (real). Each of +them is an array of 20 elements. Array elements not listed here are +currently not used. Details can be found in the comment lines of the +individual integrator files in :code:`$KPP_HOME/int/`. + +.. _output-from-int-istatus: + +======= +ISTATUS +======= + +.. _table-istatus: + +.. table:: Summary of ISTATUS usage in the f90 integrators. + Here, Y = used. + :align: center + + +----------------------------+---+---+---+---+---+---+---+---+---+ + | ISTATUS | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + +============================+===+===+===+===+===+===+===+===+===+ + | beuler | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | dvode | | | | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | exponential | | | | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | feuler | | | | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | gillespie | | | | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | lsode | Y | Y | Y | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | radau5 | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | rosenbrock | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | rosenbrock_adj | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | rosenbrock_autoreduce | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | rosenbrock_h211b_qssa | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | rosenbrock_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | runge_kutta | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | runge_kutta_adj | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | runge_kutta_tlm | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | sdirk | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | sdirk_adj | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | sdirk_tlm | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | sdirk4 | Y | Y | Y | Y | Y | Y | Y | Y | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | seulex | Y | Y | Y | Y | Y | Y | Y | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + | tau_leap | | | | | | | | | | + +----------------------------+---+---+---+---+---+---+---+---+---+ + +ISTATUS(1) +---------- + +Number of times that the :ref:`function containing the chemical ODE system +` was called. + +ISTATUS(2) +---------- + +Number times :ref:`the Jacobian matrix ` was constructed. + +ISTATUS(3) +---------- + +Total number of integration timesteps. + +ISTATUS(4) +---------- + +Number of accepted timesteps. + +ISTATUS(5) +---------- + +Number of rejected timesteps (except at very beginning). + +ISTATUS(6) +---------- + +Number of LU decompositions that were performed. + +ISTATUS(7) +---------- + +Number of forward/backward substitutions that were performed. + +ISTATUS(8) +---------- + +Number of singular matrix decompositions that were performed. + +ISTATUS(9) +---------- + +Number of times :ref:`the Hessian matrix ` was evaluated. + +ISTATUS(10) .. ISTATUS(20) +-------------------------- + +Currently not used. + +======= +RSTATUS +======= + +.. _table-rstatus: + +.. table:: Summary of RSTATUS usage in the f90 integrators. + Here, Y = used, s = solver specific usage. + :align: center + + +----------------------------+---+---+---+---+ + | RSTATUS | 1 | 2 | 3 | 4 | + +============================+===+===+===+===+ + | beuler | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | dvode | | | | | + +----------------------------+---+---+---+---+ + | exponential | | | | | + +----------------------------+---+---+---+---+ + | feuler | Y | | | | + +----------------------------+---+---+---+---+ + | gillespie | | | | | + +----------------------------+---+---+---+---+ + | lsode | Y | Y | | | + +----------------------------+---+---+---+---+ + | radau5 | | | | | + +----------------------------+---+---+---+---+ + | rosenbrock | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | rosenbrock_adj | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | rosenbrock_autoreduce | Y | Y | Y | s | + +----------------------------+---+---+---+---+ + | rosenbrock_h211b_qssa | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | rosenbrock_tlm | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | runge_kutta | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | runge_kutta_adj | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | runge_kutta_tlm | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | sdirk | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | sdirk_adj | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | sdirk_tlm | Y | Y | Y | | + +----------------------------+---+---+---+---+ + | sdirk4 | Y | Y | | | + +----------------------------+---+---+---+---+ + | seulex | | | | | + +----------------------------+---+---+---+---+ + | tau_leap | | | | | + +----------------------------+---+---+---+---+ + +RSTATUS(1) +---------- + +:code:`Texit`, the time corresponding to the computed :math:`Y` +upon return. + +RSTATUS(2) +---------- + +:code:`Hexit`: the last accepted step before exit. + +RSTATUS(3) +---------- + +:code:`Hnew`: The last predicted step (not yet taken. For multiple +restarts, use :code:`Hnew` as :code:`Hstart` in the subsequent run. + +RSTATUS(4) +---------- + +(Solver-specific for :code:`rosenbrock_autoreduce`) :code:`AR_thr`: +used to output the calculated (used) auto-reduction threshold for +the integration. Useful when :code:`ICNTRL(10) > 0` where the +threshold is dynamically determined based on a given species. + +RSTATUS(5) .. RSTATUS(20) +------------------------- + +Currently not used. diff --git a/docs/source/tech_info/07_numerical_methods.rst b/docs/source/num_methods/rosenbrock-methods.rst similarity index 56% rename from docs/source/tech_info/07_numerical_methods.rst rename to docs/source/num_methods/rosenbrock-methods.rst index 897dd53..761b9c0 100644 --- a/docs/source/tech_info/07_numerical_methods.rst +++ b/docs/source/num_methods/rosenbrock-methods.rst @@ -1,90 +1,8 @@ -.. _numerical-methods: - -################# -Numerical methods -################# - -The KPP numerical library contains a set of numerical integrators -selected to be very efficient in the low to medium accuracy regime -(relative errors :math:`\sim 10^{-2} \dots 10^{-5}`). In addition, the -KPP numerical integrators preserve the linear invariants (i.e., mass) of -the chemical system. - -KPP implements several Rosenbrock methods: ROS–2 -(:cite:t:`Verwer_et_al._1999`), ROS–3 (:cite:t:`Sandu_et_al._1997b`), -RODAS–3 (:cite:t:`Sandu_et_al._1997b`), ROS–4 -(:cite:t:`Hairer_and_Wanner_1991`), and RODAS–4 -(:cite:t:`Hairer_and_Wanner_1991`). For each of them KPP implements the -tangent linear model (direct decoupled sensitivity) and the adjoint -models. The implementations distinguish between sensitivities with -respect to initial values and sensitivities with respect to parameters -for efficiency. - -Note that KPP produces the building blocks for the simulation and also -for the sensitivity calculations. It also provides application -programming templates. Some minimal programming may be required from the -users in order to construct their own application from the KPP building -blocks. - -The symbols used in the formulas of the following sections are: - -.. _table-symbols: - -.. list-table:: Symbols used in numerical methods - :align: center - :header-rows: 1 - :widths: auto - - * - Symbol - - Description - * - :math:`s` - - Number of stages - * - :math:`t^n` - - Discrete time moment - * - :math:`h` - - Time step :math:`h=t^{n+1}-t^n` - * - :math:`y^n` - - Numerical solution (concentration) at :math:`t^n` - * - :math:`\delta y^n` - - Tangent linear solution at :math:`t^n` - * - :math:`\lambda^n` - - Adjoint numerical solution at :math:`t^n` - * - :math:`f(\cdot,\cdot)` - - The ODE derivative function: :math:`y'=f(t,y)` - * - :math:`f_t(\cdot,\cdot)` - - Partial time derivative - :math:`f_t(t,y)=\partial f(t,y)/\partial t` - * - :math:`J(\cdot,\cdot)` - - The Jacobian - :math:`J(t,y)=\partial f(t,y)/\partial y` - * - :math:`J_t(\cdot,\cdot)` - - Partial time derivative of Jacobian - :math:`J_t(t,y)=\partial J(t,y)/\partial t` - * - :math:`A` - - The system matrix - * - :math:`H(\cdot,\cdot)` - - The Hessian - :math:`H(t,y)=\partial^2 f(t,y)/\partial y^2` - * - :math:`T_i` - - Internal stage time moment for Runge-Kutta and - Rosenbrock methods - * - :math:`Y_i` - - Internal stage solution for Runge-Kutta and - Rosenbrock methods - * - :math:`k_i`, :math:`\ell_i`, - :math:`u_i`, :math:`v_i` - - Internal stage vectors for Runge-Kutta and Rosenbrock - methods, their tangent linear and adjoint models - * - :math:`\alpha_i`, :math:`\alpha_{ij}`, - :math:`a_{ij}`, :math:`b_i`, :math:`c_i`, - :math:`c_{ij}`, :math:`e_i`, :math:`m_i` - - Method coefficients - .. _rosenbrock-methods: -================== +################## Rosenbrock methods -================== +################## **Integrator file:** :file:`int/rosenbrock.f90` @@ -122,8 +40,9 @@ The coefficients of the methods implemented in KPP are shown below: .. _rosenbrock-ros-2: +===== ROS-2 ------ +===== - Stages (:math:`s`): 2 - Funcion calls: 2 - Order: 2(1) @@ -141,8 +60,10 @@ ROS-2 .. _rosenbrock-ros-3: +===== ROS-3 ------ +===== + - Stages (:math:`s`): 3 - Funcion calls: 2 - Order: 3(2) @@ -162,8 +83,10 @@ ROS-3 .. _rosenbrock-ros-4: +===== ROS-4 ------ +===== + - Stages (:math:`s`): 4 - Funcion calls: 3 - Order: 4(3) @@ -187,8 +110,10 @@ ROS-4 .. _rosenbrock-rodas-3: +======= RODAS-3 -------- +======= + - Stages (:math:`s`): 4 - Funcion calls: 3 - Order: 3(2) @@ -210,11 +135,12 @@ RODAS-3 \gamma_4 = 0 \end{aligned} - .. _rosenbrock-rodas-3-1: +========= RODAS-3.1 ---------- +========= + - Reference: :cite:t:`Long_et_al._2026` - Stages (:math:`s`): 4 - Funcion calls: 3 @@ -243,8 +169,10 @@ RODAS-3.1 .. _rosenbrock-rodas-4: +======= RODAS-4 -------- +======= + - Stages (:math:`s`): 6 - Funcion calls: 5 - Order: 4(3) @@ -276,8 +204,9 @@ RODAS-4 .. _rosenbrock-tlm: +=============================== Rosenbrock tangent linear model --------------------------------- +=============================== **Integrator file:** :file:`int/rosenbrock_tlm.f90` @@ -321,8 +250,9 @@ efficiency. .. _rosenbrock-adjoint: +================================= Rosenbrock discrete adjoint model ---------------------------------- +================================= **Integrator file:** :file:`int/rosenbrock_adj.f90` @@ -356,8 +286,9 @@ for each of the Rosenbrock methods (:ref:`rosenbrock-ros-2`, .. _rosenbrock-autoreduce: +======================================== Rosenbrock with mechanism auto-reduction ------------------------------------------ +======================================== **Integrator file:** :file:`int/rosenbrock_autoreduce.f90` @@ -393,224 +324,11 @@ Rosenbrock solver. .. _rosenbrock-h211b-qssa: +=================================== Rosenbrock with H211b time stepping ------------------------------------ +=================================== **Integrator file:** :file:`int/rosenbrock_h211b_qssa.f90` H211b time stepping according to :cite:t:`Soederlind_2003`, as implemented by :cite:t:`Dreger_2025`. - -.. _rk-methods: - -============================ -Runge-Kutta (aka RK) methods -============================ - -A general :math:`s`-stage Runge-Kutta method is defined as (see -Section II.1 of :cite:t:`Hairer_Norsett_and_Wanner_1987`) - -.. math:: - - \begin{aligned} - y^{n+1} &=& y^n + h \sum_{i=1}^s b_i k_i~,\\ - \nonumber - T_i &=& t^n + c_i h~, \quad - Y_i = y^n + h \sum_{j=1}^{s} a_{ij} k_j~,\\ - \nonumber - k_i &=& f\left( \, T_i, \, Y_i \,\right)~,\end{aligned} - -where the coefficients :math:`a_{ij}`, :math:`b_i` and :math:`c_i` are -prescribed for the desired accuracy and stability properties. The stage -derivative values :math:`k_i` are defined implicitly, and require -solving a (set of) nonlinear system(s). Newton-type methods solve -coupled linear systems of dimension (at most) :math:`n \times s`. - -The Runge-Kutta methods implemented in KPP are summarized below: - -.. _rk-method-comparison: - -3-stage Runge-Kutta -------------------- - -**Integrator file:** :file:`int/runge_kutta.f90` - -Fully implicit 3-stage Runge-Kutta methods. Several variants are available: - -- RADAU-2A: order 5 -- RADAU-1A: order 5 -- Lobatto-3C: order 4 -- Gauss: order 6 - -RADAU5 ------- -**Integrator file:** :file:`int/radau5.f90` - -This Runge-Kutta method of order 5 based on RADAU-IIA quadrature -is stiffly accurate. The KPP implementation follows the original -implementation of :cite:t:`Hairer_and_Wanner_1991`, Section IV.10. While -RADAU5 is relatively expensive (when compared to the Rosenbrock -methods), it is more robust and is useful to obtain accurate reference -solutions. - -SDIRK ------ -**Integrator file:** :file:`int/sdirk.f90`, - -SDIRK is an L-stable, singly-diagonally-implicit Runge-Kutta method. The -implementation is based on :cite:t:`Hairer_and_Wanner_1991`. Several -variants are available: - - - Sdirk 2a, 2b: 2 stages, order 2 - - Sdirk 3a: 3 stages, order 2 - - Sdirk 4a, 4b: 5 stages, order 4 - -SDIRK4 ------- -**Integrator file:** :file:`int/sdirk4.f90` - -SDIRK4 is an L-stable, singly-diagonally-implicit Runge-Kutta method -of order 4. The implementation is based on :cite:t:`Hairer_and_Wanner_1991`. - -SEULEX ------- -**Integrator file:** :file:`int/seulex.f90` - -SEULEX is a variable order stiff extrapolation code able to produce -highly accurate solutions. The KPP implementation is based on the -implementation of :cite:t:`Hairer_and_Wanner_1991`. - -.. _rk-tlm: - -RK tangent linear model ------------------------ - -The tangent linear method associated with the Runge-Kutta method is - -.. math:: - - \begin{aligned} - %y^{n+1} &=& y^n + h \sum_{i=1}^s b_i k_i~,\\ - \delta y^{n+1} &=& \delta y^n + h \sum_{i=1}^s b_i \ell_i~,\\ - \nonumber - %Y_i &=& y^n + h \sum_{j=1}^{s} a_{ij} k_j~,\\ - \delta Y_i& =& \delta y^n + h \sum_{j=1}^{s} a_{ij} \ell_j~,\\ - \nonumber - %k_i &=& f\left( \, T_i, \, Y_i \,\right)~,\\ - \ell_i &=& J\left(T_i, \, Y_i \right) \cdot \delta Y_i ~.\end{aligned} - -The system is linear and does not require an iterative -procedure. However, even for a SDIRK method (:math:`a_{ij}=0` for -:math:`i>j` and :math:`a_{ii}=\gamma`) each stage requires the LU -factorization of a different matrix. - -.. _rk-adj: - -RK discrete adjoint model -------------------------- - -The first order Runge-Kutta adjoint is - -.. math:: - - \begin{aligned} - u_i &=& h \, J^T(T_i,Y_i)\cdot - \left( b_i \lambda^{n+1} + \sum_{j=1}^s a_{ji} u_j \right)\\ %\quad i = 1 \cdots s\\ - \nonumber - \lambda^{n} &=& \lambda^{n+1} +\sum_{j=1}^s u_j~.\end{aligned} - -For :math:`b_i \ne 0` the Runge-Kutta adjoint can be rewritten as -another Runge-Kutta method: - -.. math:: - - \begin{aligned} - u_i &=& h \, J^T(T_i,Y_i)\cdot - \left( \lambda^{n+1} + \sum_{j=1}^s \frac{b_j \, - a_{ji}}{b_i} u_j \right)\\ %~, \quad i = 1 \cdots s\\ - \nonumber - \lambda^{n} &=& \lambda^{n+1} +\sum_{j=1}^s b_j \, u_j~.\end{aligned} - -.. _back-diff: - -================================= -Backward differentiation formulas -================================= - -Backward differentiation formulas (BDF) are linear multistep methods -with excellent stability properties for the integration of chemical -systems (cf. :cite:t:`Hairer_and_Wanner_1991`, Section V.1). The -:math:`k`-step BDF method reads - -.. math:: - - \sum_{i=0}^k \alpha_i y^{n-i} = h_n \beta\; f\left(t^{n},y^{n}\right) - \label{BDF} - -where the coefficients :math:`\alpha_i` and :math:`\beta` are chosen -such that the method has order of consistency :math:`k`. - -The KPP library contains two off-the-shelf, highly popular -implementations of BDF methods, described in the following sections: - -LSODE ------ -**Integrator file:** :file:`int/lsode.f90` - -LSODE, the Livermore ODE solver -(:cite:t:`Radhakrishnan_and_Hindmarsh_1993`), implements backward -differentiation formula (BDF) methods for stiff problems. LSODE has -been translated to Fortran90 for the incorporation into the KPP library. - -.. attention:: - - We have discovered that the current implementation of the LSODE - integrator is not thread-safe for `OpenMP parallelization - `_. When LSODE is called from within - an OpenMP parallel loop, the integration will fail because key - internal variables in LSODE will be overwritten by concurrent - threads. - -VODE ----- - -**Integrator file:** :file:`int/dvode.f90` - -VODE (:cite:t:`Brown_Byrne_and_Hindmarsh_1989`) uses another formulation -of backward differentiation formulas. The version of VODE present in -the KPP library uses directly the KPP sparse linear algebra routines. - -BEULER ------- - -**Integrator file:** :file:`int/sdirk.f90` - -Backward Euler integration method. To request this method, make sure -you select - -.. code-block:: console - - #INTEGRATOR sdirk - -in your definition file, and then set :code:`ICNTRL(3) = 6`. - -.. _other-methods: - -========================= -Other integration methods -========================= - -FEULER ------- - -**Integrator file:** :file:`int/feuler.f90` - -Forward Euler is an explicit integration method for non-stiff problems. -FEULER computes -:math:`y^{n+1}` as - -.. math:: - - \begin{aligned} - y^{n+1} = y^n + hf\left(t^{n},y^{n}\right) - \end{aligned} diff --git a/docs/source/num_methods/runge_kutta_methods.rst b/docs/source/num_methods/runge_kutta_methods.rst new file mode 100644 index 0000000..676f201 --- /dev/null +++ b/docs/source/num_methods/runge_kutta_methods.rst @@ -0,0 +1,148 @@ +.. _rk-methods: + +############################ +Runge-Kutta (aka RK) methods +############################ + +A general :math:`s`-stage Runge-Kutta method is defined as (see +Section II.1 of :cite:t:`Hairer_Norsett_and_Wanner_1987`) + +.. math:: + + \begin{aligned} + y^{n+1} &=& y^n + h \sum_{i=1}^s b_i k_i~,\\ + \nonumber + T_i &=& t^n + c_i h~, \quad + Y_i = y^n + h \sum_{j=1}^{s} a_{ij} k_j~,\\ + \nonumber + k_i &=& f\left( \, T_i, \, Y_i \,\right)~,\end{aligned} + +where the coefficients :math:`a_{ij}`, :math:`b_i` and :math:`c_i` are +prescribed for the desired accuracy and stability properties. The stage +derivative values :math:`k_i` are defined implicitly, and require +solving a (set of) nonlinear system(s). Newton-type methods solve +coupled linear systems of dimension (at most) :math:`n \times s`. + +The Runge-Kutta methods implemented in KPP are summarized below: + +.. _rk-methods-3stage: + +=================== +3-stage Runge-Kutta +=================== + +**Integrator file:** :file:`int/runge_kutta.f90` + +Fully implicit 3-stage Runge-Kutta methods. Several variants are available: + +- RADAU-2A: order 5 +- RADAU-1A: order 5 +- Lobatto-3C: order 4 +- Gauss: order 6 + +.. _rk-methods-radau5: + +====== +RADAU5 +====== + +**Integrator file:** :file:`int/radau5.f90` + +This Runge-Kutta method of order 5 based on RADAU-IIA quadrature +is stiffly accurate. The KPP implementation follows the original +implementation of :cite:t:`Hairer_and_Wanner_1991`, Section IV.10. While +RADAU5 is relatively expensive (when compared to the Rosenbrock +methods), it is more robust and is useful to obtain accurate reference +solutions. + +.. _rk-methods-sdirk: + +===== +SDIRK +===== + +**Integrator file:** :file:`int/sdirk.f90`, + +SDIRK is an L-stable, singly-diagonally-implicit Runge-Kutta method. The +implementation is based on :cite:t:`Hairer_and_Wanner_1991`. Several +variants are available: + + - Sdirk 2a, 2b: 2 stages, order 2 + - Sdirk 3a: 3 stages, order 2 + - Sdirk 4a, 4b: 5 stages, order 4 + +.. _rk-methods-sdirk4: + +====== +SDIRK4 +====== + +**Integrator file:** :file:`int/sdirk4.f90` + +SDIRK4 is an L-stable, singly-diagonally-implicit Runge-Kutta method +of order 4. The implementation is based on :cite:t:`Hairer_and_Wanner_1991`. + +.. _rk-methods-seulex: + +====== +SEULEX +====== + +**Integrator file:** :file:`int/seulex.f90` + +SEULEX is a variable order stiff extrapolation code able to produce +highly accurate solutions. The KPP implementation is based on the +implementation of :cite:t:`Hairer_and_Wanner_1991`. + +.. _rk-methods-tlm: + +======================= +RK tangent linear model +======================= + +The tangent linear method associated with the Runge-Kutta method is + +.. math:: + + \begin{aligned} + %y^{n+1} &=& y^n + h \sum_{i=1}^s b_i k_i~,\\ + \delta y^{n+1} &=& \delta y^n + h \sum_{i=1}^s b_i \ell_i~,\\ + \nonumber + %Y_i &=& y^n + h \sum_{j=1}^{s} a_{ij} k_j~,\\ + \delta Y_i& =& \delta y^n + h \sum_{j=1}^{s} a_{ij} \ell_j~,\\ + \nonumber + %k_i &=& f\left( \, T_i, \, Y_i \,\right)~,\\ + \ell_i &=& J\left(T_i, \, Y_i \right) \cdot \delta Y_i ~.\end{aligned} + +The system is linear and does not require an iterative +procedure. However, even for a SDIRK method (:math:`a_{ij}=0` for +:math:`i>j` and :math:`a_{ii}=\gamma`) each stage requires the LU +factorization of a different matrix. + +.. _rk-methods-adj: + +========================= +RK discrete adjoint model +========================= + +The first order Runge-Kutta adjoint is + +.. math:: + + \begin{aligned} + u_i &=& h \, J^T(T_i,Y_i)\cdot + \left( b_i \lambda^{n+1} + \sum_{j=1}^s a_{ji} u_j \right)\\ %\quad i = 1 \cdots s\\ + \nonumber + \lambda^{n} &=& \lambda^{n+1} +\sum_{j=1}^s u_j~.\end{aligned} + +For :math:`b_i \ne 0` the Runge-Kutta adjoint can be rewritten as +another Runge-Kutta method: + +.. math:: + + \begin{aligned} + u_i &=& h \, J^T(T_i,Y_i)\cdot + \left( \lambda^{n+1} + \sum_{j=1}^s \frac{b_j \, + a_{ji}}{b_i} u_j \right)\\ %~, \quad i = 1 \cdots s\\ + \nonumber + \lambda^{n} &=& \lambda^{n+1} +\sum_{j=1}^s b_j \, u_j~.\end{aligned} diff --git a/docs/source/output/code_c.rst b/docs/source/output/code_c.rst new file mode 100644 index 0000000..5f38f80 --- /dev/null +++ b/docs/source/output/code_c.rst @@ -0,0 +1,74 @@ +.. |br| raw:: html + +
+ +.. _C-code: + +########## +The C code +########## + +.. important:: + + Some run-time options for C-language integrators (specified in + the :ref:`ICNTRL and RCNTRL arrays `) do not exactly + correspond to the Fortran90 run-time options. We will standardize + run-time integrator options across all target languages in a future + KPP release. + +The driver file :file:`ROOT.c` contains the main (driver) program and +numerical integrator functions, as well as declarations and +initializations of global variables. + +The generated C code includes three header files which are +:code:`#include`-d in other files as appropriate. + +#. :ref:`Global parameters ` are :code:`#include`-d + in the header file :file:`ROOT_Parameters.h`. |br| + |br| + +#. :ref:`Global variables ` are extern-declared in + :file:`ROOT_Global.h` and declared in the driver file + :file:`ROOT.c`. |br| + |br| + +#. Extern declarations of sparse data structures for the + :ref:`Jacobian `, :ref:`Hessian ` and + :ref:`stoichiometric matrix `, and the :ref:`Jacobian + of reaction products ` are in the header file + :file:`ROOT_Sparse.h`. The actual declarations of each + data structure is done in the corresponding files. + +The code for the :ref:`ODE function ` is in +:file:`ROOT_Function.c`. + +The :ref:`ODE Jacobian and sparse multiplications +` is in :file:`ROOT_Jacobian.c`, and the +declaration and initialization of the Jacobian sparse data structures +is in the file :file:`ROOT_JacobianSP.c`. + +Similarly, the :ref:`Hessian function and associated sparse +multiplications `) are in +:file:`ROOT_Hessian.c`, and the declaration and initialization of +Hessian sparse data structures are in :file:`ROOT_HessianSP.c`. + +Functions for :ref:`reactant products and its Jacobian, and +derivatives with respect to rate coefficients +` are in the file :file:`ROOT_Stoichiom.c`. + +The declaration and initialization of the :ref:`stoichiometric matrix +and the associated sparse data structures `) is done in +:file:`ROOT_StoichiomSP.c`. + +:ref:`Sparse linear algebra routines ` are in the file +:file:`ROOT_LinearAlgebra.c`. The code to update the rate constants +and user defined code for rate laws is in :file:`ROOT_Rates.c`. + +:ref:`Various utility and input/output functions ` are in +:file:`ROOT_Util.c` and :file:`ROOT_Monitor.c`. + +Finally, :ref:`mex gateway routines ` that allow the C +implementation of the ODE function, Jacobian, and Hessian to be called +directly from Matlab are also generated in the files +:file:`ROOT_mex_Fun.c`, :file:`ROOT_mex_Jac_SP.c`, and +:file:`ROOT_mex_Hessian.c`. diff --git a/docs/source/output/code_f90.rst b/docs/source/output/code_f90.rst new file mode 100644 index 0000000..0563876 --- /dev/null +++ b/docs/source/output/code_f90.rst @@ -0,0 +1,939 @@ +.. _f90-code: + +################## +The Fortran90 code +################## + +The code generated by KPP is organized in a set of separate files. Each +has a complete description of how it was generated at the begining of +the file. The files associated with root are named with a +corresponding prefix :code:`ROOT_` A short description of each file +is contained in the following sections. + +.. figure:: ../_static/kpp2_use_diagr.png + :align: center + :alt: Figure 1: Interdependencies of the KPP-generated files + + Figure 1: Interdependencies of the KPP-generated files. Each arrow + starts at the module that exports a variable or subroutine and + points to the module that imports it via the Fortran90 :code:`USE` + instruction. The prefix :code:`ROOT_` has been omitted from module + names for better readability. Dotted boxes show optional files that + are only produced under certain circumstances. + +All subroutines and functions, global parameters, variables, and +sparsity data structures are encapsulated in modules. There is exactly +one module in each file, and the name of the module is identical to the +file name but without the suffix :code:`.f90` or :code:`.F90`. `Figure 1 +(above) `_ shows how these modules are related to +each other. The generated code is consistent with the Fortran90 +standard. It may, however, exceed the official maximum number of 39 +continuation lines. + +.. tip:: + + The default Fortran90 file suffix is :code:`.f90`. To have KPP + generate Fortran90 code ending in :file:`.F90` instead, add the + command :command:`#UPPERCASEF90 ON` to the KPP definition file. + +.. _Main: + +========= +ROOT_Main +========= + +:file:`ROOT_Main.f90` (or :file:`.F90`) root is the main +Fortran90 program. It contains the driver after modifications by the +substitution preprocessor. The name of the file is computed by KPP by +appending the suffix to the root name. + +Using :command:`#DRIVER none` will skip generating this file. + +.. _Model: + +========== +ROOT_Model +========== + +The file :file:`ROOT_Model.f90` (or :file:`.F90`) unifies all model +definitions in a single module. This simplifies inclusion into +external Fortran programs. + +.. _Initialize: + +=============== +ROOT_Initialize +=============== + +The file :file:`ROOT_Initialize.f90` (or :file:`.F9O`) +contains the subroutine :code:`Initialize`, which defines initial +values of the chemical species. The driver calls the subroutine once +before the time integration loop starts. + +.. note:: + + In KPP 3.5.0 and later versions, you may pass the optional + :code:`PassiveSpc_ATOL_Threshold` to subroutine :code:`Initialize` + to prevent "passive" species intended for diagnostic purposes from + being used in certain computations (such as the Rosenbrock error + norm). At present this option is limited to Fortran90. For more + information, please see the :ref:`filter-passive-spc` section. + +.. _Integrator: + +=============== +ROOT_Integrator +=============== + +The file :file:`ROOT_Integrator.f90` (or :file:`.F90`) +contains the subroutine :code:`Integrate`, which is called every time +step during the integration. The integrator that was chosen with the +:ref:`integrator-cmd` command is also included in this file. In case +of an unsuccessful integration, the module root provides a short error +message in the public variable :code:`IERR_NAME`. + +.. _Monitor: + +============ +ROOT_Monitor +============ + +The file :file:`ROOT_Monitor.f90` (:file:`.F90`) contains +arrays with information about the chemical mechanism. The names of all +species are included in :code:`SPC_NAMES` and the names of all +equations are included in :code:`EQN_NAMES`. + +It was shown (cf. :ref:`eqntags-cmd`) that each reaction +in the section may start with an equation tag which is enclosed in +angle brackets, e.g.: + +.. code-block:: console + + NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0e0); + +If the equation tags are switched on, KPP also generates the +:code:`PARAMETER` array :code:`EQN_TAGS`. In combination with +:code:`EQN_NAMES` and the function :code:`tag2num` that converts the +equation tag to the KPP-internal tag number, this can be used to +describe a reaction: + +.. code-block:: none + + PRINT*, ’Reaction 1 is:’, EQN_NAMES( tag2num( ’R1’ ) ) + +.. _Precision: + +============== +ROOT_Precision +============== + +Fortran90 code uses parameterized real +types. :file:`ROOT_Precision.f90` (or :file:`.F90`) contains the +following real kind definitions: + +.. code-block:: fortran + + ! KPP_SP - Single precision kind + INTEGER, PARAMETER :: & + SP = SELECTED_REAL_KIND(6,30) + ! KPP_DP - Double precision kind + INTEGER, PARAMETER :: & + DP = SELECTED_REAL_KIND(12,300) + +Depending on the choice of the :ref:`double-cmd` command, the real +variables are of type double (:code:`REAL(kind=dp)`) or single +precision (:code:`REAL(kind=sp)`). Changing the parameters of the +:code:`SELECTED_REAL_KIND` function in this module will cause a change +in the working precision for the whole model. + +.. _Rates: + +========== +ROOT_Rates +========== + +The code to update the rate constants is in :file:`ROOT_Rates.f90` (or +:file:`.F90`). The user defined rate law functions (cf. +:ref:`table-rat-fun`) are also placed here. + +.. _table-rat-fun: + +.. list-table:: Fortran90 subrotutines in ROOT_Rates + :align: center + :header-rows: 1 + :widths: 25 75 + + * - Function + - Description + * - :code:`Update_PHOTO` + - Update photolysis rate coefficients + * - :code:`Update_RCONST` + - Update all rate coefficients + * - :code:`Update_SUN` + - Update sun intensity + +.. _Parameters: + +=============== +ROOT_Parameters +=============== + +Global parameters are defined and initialized in +:file:`ROOT_Parameters.f90` (or :file:`.F90`): + +.. _table-par: + +.. list-table:: Parameters Declared in ROOT_Parameters + :align: center + :widths: 20 60 20 + :header-rows: 1 + + * - Parameter + - Represents + - Example + * - ``NSPEC`` + - No. chemical species (``NVAR`` + ``NFIX``) + - 7 + * - ``NVAR`` + - No. variable species + - 5 + * - ``NFIX`` + - No. fixed species + - 2 + * - ``NREACT`` + - No. reactions + - 10 + * - ``NONZERO`` + - No. nonzero entries Jacobian + - 18 + * - ``LU_NONZERO`` + - As above, after LU factorization + - 19 + * - ``NHESS`` + - Length, sparse Hessian + - 10 + * - ``NJVRP`` + - Length, sparse Jacobian JVRP + - 13 + * - ``NSTOICM`` + - Length, stoichiometric matrix + - 22 + * - ``ind_spc`` + - Index of species *spc* in :code:`C` + - + * - ``indf_spc`` + - Index of fixed species *spc* in :code:`FIX` + - + +Example values listed in the 3rd column are taken from the +:program:`small_strato` mechanism (cf. +:ref:`running-kpp-with-an-example-mechanism`). + +KPP orders the variable species such that the sparsity pattern of the +Jacobian is maintained after an LU decomposition. For our example there +are five variable species (:code:`NVAR = 5`) ordered as + +.. code-block:: fortran + + ind_O1D=1, ind_O=2, ind_O3=3, ind_NO=4, ind_NO2=5 + +and two fixed species (:code:`NFIX = 2`) + +.. code-block:: fortran + + ind_M = 6, ind_O2 = 7. + +KPP defines a complete set of simulation parameters, including the +numbers of variable and fixed species, the number of chemical reactions, +the number of nonzero entries in the sparse Jacobian and in the sparse +Hessian, etc. + +.. _Global: + +=========== +ROOT_Global +=========== + +Several global variables are declared in :file:`ROOT_Global.f90` (or +:file:`.F90`): + +.. _table-glob: + +.. list-table:: Global Variables Declared in ROOT_Global + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Global variable + - Represents + * - :code:`C(NSPEC)` + - Concentrations, all species + * - :code:`VAR(:)` + - Concentrations, variable species (pointer) + * - :code:`FIX(:)` + - Concentrations, fixed species (pointer) + * - :code:`RCONST(NREACT)` + - Rate coefficient values + * - :code:`TIME` + - Current integration time + * - :code:`SUN` + - Sun intensity between 0 and 1 + * - :code:`TEMP` + - Temperature + * - :code:`TSTART, TEND` + - Simulation start/end time + * - :code:`DT` + - Simulation time step + * - :code:`ATOL(NSPEC)` + - Absolute tolerances + * - :code:`RTOL(NSPEC)` + - Relative tolerances + * - :code:`STEPMIN` + - Lower bound for time step + * - :code:`STEPMAX` + - Upper bound for time step + * - :code:`CFACTOR` + - Conversion factor + * - :code:`NonPassiveSpc_Count` + - Number of :non-passive species (cf. :ref:`filter-passive-spc`) + * - :code:`NonPassiveSpc_Indices` + - List of species indices for only the non-passive species + + +Both variable and fixed species are stored in the one-dimensional +array :code:`C`. The first part (indices from :code:`1` to :code:`NVAR`) +contains the variable species, and the second part (indices from to +:code:`NVAR+1` to :code:`NSPEC`) the fixed species. The total number +of species is the sum of the :code:`NVAR` and :code:`NFIX`. The parts +can also be accessed separately through pointer variables :code:`VAR` and +:code:`FIX`, which point to the proper elements in :code:`C`. + +.. code-block:: fortran + + VAR(1:NVAR) => C(1:NVAR) + FIX(1:NFIX) => C(NVAR+1:NSPEC) + +.. important:: + + In previous versions of KPP, Fortran90 code was generated with + :code:`VAR` and :code:`FIX` being linked to the :code:`C` array + with an :code:`EQUIVALENCE` statement. This construction, however, + is not thread-safe, and it prevents KPP-generated Fortran90 code + from being used within parallel environments (e.g. such as an + `OpenMP `_ parallel loop). + + We have modified :ref:`kpp250` and later versions to make KPP-generated + Fortran90 code thread-safe. :code:`VAR` and + :code:`FIX` are now :code:`POINTER` variables that + point to the proper slices of the :code:`C` array. They are also + nullified when no longer needed. :code:`VAR` and :code:`FIX` are + now also kept internal to the various integrator files located in + the :file:`$KPP_HOME/int` directory. + +.. _Function: + +============= +ROOT_Function +============= + +The chemical ODE system for our :program:`small_strato` example +(described in :ref:`running-kpp-with-an-example-mechanism`) is: + +.. math:: + + \begin{aligned} + \frac{d[O(^1D)]}{dt} & = & k_{5}\, [O_3] - k_{6}\, [O(^1D)]\, [M] - k_{7}\, [O(^1D)]\, [O_3]\\ + \frac{d[O]}{dt} & = & 2\, k_{1}\, [O_2] - k_{2}\, [O]\, [O_2] + k_{3}\, [O_3]\\ + & & - k_{4}\, [O]\, [O_3]+ k_{6}\, [O(^1D)]\, [M]\\ + & & - k_{9}\, [O]\, [NO_2] + k_{10}\, [NO_2]\\ + \frac{d[O_3]}{dt} & = & k_{2}\, [O]\, [O_2] - k_{3}\, + [O_3] - k_{4}\, [O]\, [O_3] - k_{5}\, [O_3]\\ + & & - k_{7}\, [O(^1D)]\, [O_3] - k_{8}\, [O_3]\, [NO]\\ + \frac{d[NO]}{dt} & = & - k_{8}\, [O_3]\, [NO] + k_{9}\, [O]\, [NO_2] + k_{10}\, [NO_2]\\ + \frac{d[NO_2]}{dt} & = & k_{8}\, [O_3]\, [NO] - k_{9}\, [O]\, [NO_2] - k_{10}\, [NO_2]\\ + \end{aligned} + +where square brackets denote concentrations of the species. The code for +the ODE function is in :code:`ROOT_Function.f90` (or :code:`.F90`) The +chemical reaction mechanism represents a set of ordinary differential +equations (ODEs) of dimension . The concentrations of fixed species +are parameters in the derivative function. The subroutine computes +first the vector :code:`A` of reaction rates and then the vector +:code:`Vdot` of variable species time derivatives. The input arguments +:code:`V`, :code:`F`, :code:`RCT` are the concentrations of variable +species, fixed species, and the rate coefficients, +respectively. :code:`A` and :code:`Vdot` may be returned to the +calling program (for diagnostic purposes) with optional ouptut +argument :code:`Aout`. Below is the Fortran90 +code generated by KPP for the ODE function of our +:program:`small_strato` example. + +.. code-block:: fortran + + SUBROUTINE Fun (V, F, RCT, Vdot, Aout, Vdotout ) + + ! V - Concentrations of variable species (local) + REAL(kind=dp) :: V(NVAR) + ! F - Concentrations of fixed species (local) + REAL(kind=dp) :: F(NVAR) + ! RCT - Rate constants (local) + REAL(kind=dp) :: RCT(NREACT) + ! Vdot - Time derivative of variable species concentrations + REAL(kind=dp) :: Vdot(NVAR) + ! Aout - Optional argument to return equation rate constants + REAL(kind=dp), OPTIONAL :: Aout(NREACT) + + + ! Computation of equation rates + A(1) = RCT(1)*F(2) + A(2) = RCT(2)*V(2)*F(2) + A(3) = RCT(3)*V(3) + A(4) = RCT(4)*V(2)*V(3) + A(5) = RCT(5)*V(3) + A(6) = RCT(6)*V(1)*F(1) + A(7) = RCT(7)*V(1)*V(3) + A(8) = RCT(8)*V(3)*V(4) + A(9) = RCT(9)*V(2)*V(5) + A(10) = RCT(10)*V(5) + + !### Use Aout to return equation rates + IF ( PRESENT( Aout ) ) Aout = A + + ! Aggregate function + Vdot(1) = A(5)-A(6)-A(7) + Vdot(2) = 2*A(1)-A(2)+A(3) & + -A(4)+A(6)-A(9)+A(10) + Vdot(3) = A(2)-A(3)-A(4)-A(5) & + -A(7)-A(8) + Vdot(4) = -A(8)+A(9)+A(10) + Vdot(5) = A(8)-A(9)-A(10) + + END SUBROUTINE Fun + +.. _Jacobian-and-JacobianSP: + +================================= +ROOT_Jacobian and ROOT_JacobianSP +================================= + +The Jacobian matrix for our example contains 18 non-zero elements: + +.. math:: + + \begin{aligned} + \mathbf{J}(1,1) & = & - k_{6}\, [{M}] - k_{7}\, [{O_3}]\\ + \mathbf{J}(1,3) & = & k_{5} - k_{7}\, [{O(^1D)}]\\ + \mathbf{J}(2,1) & = & k_{6}\, [{M}]\\ + \mathbf{J}(2,2) & = & - k_{2}\, [{O_2}] - k_{4}\, [{O_3}] + - k_{9}\, [{NO_2}]\\ + \mathbf{J}(2,3) & = & k_{3} - k_{4}\, [{O}]\\ + \mathbf{J}(2,5) & = & - k_{9}\, [{O}] + k_{10}\\ + \mathbf{J}(3,1) & = & - k_{7}\, [{O_3}]\\ + \mathbf{J}(3,2) & = & k_{2}\, [{O_2}] - k_{4}\, [{O_3}]\\ + \mathbf{J}(3,3) & = & - k_{3} - k_{4}\, [{O}] - k_{5} - k_{7}\, + [{O(^1D)}] - k_{8}\, [{NO}]\\ + \mathbf{J}(3,4) & = & - k_{8}\, [{O_3}]\\ + \mathbf{J}(4,2) & = & k_{9}\, [{NO_2}]\\ + \mathbf{J}(4,3) & = & - k_{8}\, [{NO}]\\ + \mathbf{J}(4,4) & = & - k_{8}\, [{O_3}]\\ + \mathbf{J}(4,5) & = & k_{9}\, [{O}] + k_{10}\\ + \mathbf{J}(5,2) & = & - k_{9}\, [{NO_2}]\\ + \mathbf{J}(5,3) & = & k_{8}\, [{NO}]\\ + \mathbf{J}(5,4) & = & k_{8}\, [{O_3}]\\ + \mathbf{J}(5,5) & = & - k_{9}\, [{O}] - k_{10}\\ + \end{aligned} + +It defines how the temporal change of each chemical species depends on +all other species. For example, :math:`\mathbf{J}(5,2)` shows that :math:`NO_2` +(species number 5) is affected by :math:`O` (species number 2) via +reaction R9. The sparse data structures for the Jacobian are +declared and initialized in :file:`ROOT_JacobianSP.f90` (or +:file:`.F90`). The code for the ODE Jacobian and +sparse multiplications is in :file:`ROOT_Jacobian.f90` (or +:file:`.F90`). + +.. tip:: + + Adding either :command:`#JACOBIAN SPARSE_ROW` or + :command:`#JACOBIAN SPARSE_LU_ROW` to the KPP definition file will + create the file :file:`ROOT_JacobianSP.f90` (or :file:`.F90`). + +The Jacobian of the ODE function is automatically constructed by KPP. +KPP generates the Jacobian subroutine :code:`Jac` or :code:`JacSP` where +the latter is generated when the sparse format is required. Using the +variable species :code:`V`, the fixed species :code:`F`, and the rate +coefficients :code:`RCT` as input, the subroutine calculates the +Jacobian :code:`JVS`. The default data structures for the sparse +compressed on rows Jacobian representation (for the case where the LU +fill-in is accounted for) are: + +.. _table-jac: + +.. list-table:: Sparse Jacobian Data Structures + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Global variable + - Represents + * - :code:`JVS(LU_NONZERO)` + - Jacobian nonzero elements + * - :code:`LU_IROW(LU_NONZERO)` + - Row indices + * - :code:`LU_ICOL(LU_NONZERO)` + - Column indices + * - :code:`LU_CROW(NVAR+1)` + - Start of rows + * - :code:`LU_DIAG(NVAR+1)` + - Diagonal entries + +:code:`JVS` stores the :code:`LU_NONZERO` elements of the +Jacobian in row order. Each row :code:`I` starts at position +:code:`LU_CROW(I)`, and :code:`LU_CROW(NVAR+1)` = +:code:`LU_NONZERO+1`. The location of the :code:`I`-th diagonal +element is :code:`LU_DIAG(I)`. The sparse element :code:`JVS(K)` is +the Jacobian entry in row :code:`LU_IROW(K)` and column +:code:`LU_ICOL(K`). For the :program:`small_strato` example KPP +generates the following Jacobian sparse data structure: + +.. code-block:: fortran + + LU_ICOL = (/ 1,3,1,2,3,5,1,2,3,4, & + 5,2,3,4,5,2,3,4,5 /) + LU_IROW = (/ 1,1,2,2,2,2,3,3,3,3, & + 3,4,4,4,4,5,5,5,5 /) + LU_CROW = (/ 1,3,7,12,16,20 /) + LU_DIAG = (/ 1,4,9,14,19,20 /) + +This is visualized in Figure 2 below.. The sparsity coordinate +vectors are computed by KPP and initialized statically. These vectors +are constant as the sparsity pattern of the Jacobian does not change +during the computation. + +.. _figure-2: + +.. figure:: ../_static/small_jac.png + :alt: Figure 2: The sparsity pattern of the Jacobian for the + small_strato example. + :scale: 60% + :align: center + + Figure 2: The sparsity pattern of the Jacobian for the + :program:`small_strato` example. All non-zero elements are marked + with a bullet. Note that even though :math:`\mathbf{J}(3,5)` is + zero, it is also included here because of the fill-in. + +Two other KPP-generated routines, :code:`Jac_SP_Vec` and +:code:`JacTR_SP_Vec` (see :ref:`table-jac-fun`) are useful for direct +and adjoint sensitivity analysis. They perform sparse multiplication of +:code:`JVS` (or its transpose for :code:`JacTR_SP_Vec`) with the +user-supplied vector :code:`UV` without any indirect addressing. + +.. _table-jac-fun: + +.. list-table:: Fortran90 subroutines in ROOT_Jacobian + :align: center + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + * - :code:`Jac_SP` + - ODE Jacobian in sparse format + * - :code:`Jac_SP_Vec` + - Sparse multiplication + * - :code:`JacTR_SP_Vec` + - Sparse multiplication + * - :code:`Jac` + - ODE Jacobian in full format + +.. _Hessian-and-HessianSP: + +=============================== +ROOT_Hessian and ROOT_HessianSP +=============================== + +The sparse data structures for the Hessian are declared and initialized +in :file:`ROOT_Hessian.f90` (or :file:`.F90`). The Hessian +function and associated sparse multiplications are in +:code:`ROOT_HessianSP.f90` (or :code:`.F90`). + +The Hessian contains the second order derivatives of the time derivative +functions. More exactly, the Hessian is a 3-tensor such that + +.. math:: + + H_{i,j,k} = \frac{\partial^2 ({\mathrm{d}}c/{\mathrm{d}}t)_i}{\partial c_j \,\partial c_k}~, + \qquad 1 \le i,j,k \le N_{\rm var}~. + \label{eqn:Hessian1} + +KPP generates the routine :code:`Hessian`: + +.. _table-hess-fun: + +.. list-table:: Fortran90 functions in ROOT_Hessian + :align: center + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + * - :code:`Hessian` + - ODE Hessian in sparse format + * - :code:`Hess_Vec` + - Hessian action on vectors + * - :code:`HessTR_Vec` + - Transposed Hessian action on vectors + +Using the variable species :code:`V`, the fixed species :code:`F`, and +the rate coefficients :code:`RCT` as input, the subroutine +:code:`Hessian` calculates the Hessian. The Hessian is a very sparse +tensor. The sparsity of the Hessian for our example is visualized in +:ref:`figure-3` + +.. _figure-3: + +.. figure:: ../_static/small_hess1.png + :alt: Figure 3: The Hessian of the small_strato example + :align: center + + Figure 3: The Hessian of the small_strato example. + +KPP computes the number of nonzero Hessian entries and saves it in the +variable :code:`NHESS`. The Hessian itself is represented in +coordinate sparse format. The real vector :code:`HESS` holds the values, and the +integer vectors :code:`IHESS_I`, :code:`IHESS_J`, and :code:`IHESS_K` +hold the indices of nonzero entries as illustrated in :ref:`table-hess`. + +.. _table-hess: + +.. list-table:: Sparse Hessian Data + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Variable + - Represents + * - :code:`HESS(NHESS)` + - Hessian nonzero elements :math:`H_{i,j,k}` + * - :code:`IHESS_I(NHESS)` + - Index :math:`i` of element :math:`H_{i,j,k}` + * - :code:`IHESS_J(NHESS)` + - Index :math:`j` of element :math:`H_{i,j,k}` + * - :code:`IHESS_K(NHESS)` + - Index :math:`k` of element :math:`H_{i,j,k}` + +Since the time derivative function is smooth, these Hessian matrices +are symmetric, :math:`\tt HESS_{i,j,k}`\ =\ :math:`\tt HESS_{i,k,j}`. +KPP stores only those entries :math:`\tt HESS_{i,j,k}` with +:math:`j \le k`. The sparsity coordinate vectors :code:`IHESS_1`, +:code:`IHESS_J` and :code:`IHESS_K` are computed by KPP and +initialized statically. They are constant as the sparsity pattern of +the Hessian does not change during the computation. + +The routines :code:`Hess_Vec` and :code:`HessTR_Vec` compute the +action of the Hessian (or its transpose) on a pair of user-supplied +vectors :code:`U1` and :code:`U2`. Sparse operations are employed to +produce the result vector. + +.. _LinearAlgebra: + +================== +ROOT_LinearAlgebra +================== + +Sparse linear algebra routines are in the file +:file:`ROOT_LinearAlgebra.f90` (or :file:`.F90`). To +numerically solve for the chemical concentrations one must employ an +implicit timestepping technique, as the system is usually stiff. Implicit +integrators solve systems of the form + +.. math:: P\, x = (I - h \gamma J)\, x = b + +where the matrix :math:`P=I - h \gamma J` is refered to as the +“prediction matrix”. :math:`I` the identity matrix, :math:`h` the +integration time step, :math:`\gamma` a scalar parameter depending on +the method, and :math:`J` the system Jacobian. The vector :math:`b` is +the system right hand side and the solution :math:`x` typically +represents an increment to update the solution. + +The chemical Jacobians are typically sparse, i.e. only a relatively +small number of entries are nonzero. The sparsity structure of :math:`P` +is given by the sparsity structure of the Jacobian, and is produced by +KPP (with account for the fill-in) as discussed above. + +KPP generates the sparse linear algebra subroutine :code:`KppDecomp` +(see :ref:`table-la-fun`) which performs an in-place, non-pivoting, +sparse LU decomposition of the prediction matrix :math:`P`. Since the +sparsity structure accounts for fill-in, all elements of the full LU +decomposition are actually stored. The output argument :code:`IER` +returns a value that is nonzero if singularity is detected. + +.. _table-la-fun: + +.. list-table:: Fortran90 functions in ROOT_LinearAlgebra + :align: center + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + * - :code:`KppDecomp` + - Sparse LU decomposition + * - :code:`KppSolve` + - Sparse back substitution + * - :code:`KppSolveTR` + - Transposed sparse back substitution + +The subroutines :code:`KppSolve` and :code:`KppSolveTr` and use the +in-place LU factorization :math:`P` as computed by and perform sparse +backward and forward substitutions (using :math:`P` or its +transpose). The sparse linear algebra routines :code:`KppDecomp` and +:code:`KppSolve` are extremely efficient, as shown by +:cite:t:`Sandu_et_al._1996`. + +.. _Stoichiom-and-StoichiomSP: + +=================================== +ROOT_Stoichiom and ROOT_StoichiomSP +=================================== + +These files contain contain a description of the chemical mechanism in +stoichiometric form. The file :file:`ROOT_Stoichiom.f90` (or +:file:`.F90`) contains the functions for reactant +products and its Jacobian, and derivatives with respect to rate +coefficients. The declaration and initialization of the stoichiometric +matrix and the associated sparse data structures is done in +:file:`ROOT_StochiomSP.f90` (or :file:`.F90`). + +.. tip:: + + Adding :command:`#STOICMAT ON` to the KPP definition file will + create the file :file:`ROOT_Stoichiom.f90` (or :file:`.F90`) + Also, if either :command:`#JACOBIAN SPARSE ROW` or + :command:`#JACOBIAN SPARSE_LU_ROW` are also added to the KPP + definition file, the file :file:`ROOT_StoichiomSP.f90` (or + :file:`.F90`) will also be created. + +The stoichiometric matrix is constant sparse. For our example the matrix +:code:`NSTOICM=22` has 22 nonzero entries out of 50 entries. KPP produces the +stoichiometric matrix in sparse, column-compressed format, as shown in +:ref:`table-sto`. Elements are stored in columnwise order in the +one-dimensional vector of values :code:`STOICM`. Their row and column indices +are stored in :code:`ICOL_STOICM` and :code:`ICOL_STOICM` +respectively. The vector :code:`CCOL_STOICM` contains pointers to +the start of each column. For example column :code:`j` starts in the sparse +vector at position :code:`CCOL_STOICM(j)` and ends at +:code:`CCOL_STOICM(j+1)-1`. The last value :code:`CCOL_STOICM(NVAR)` = +:code:`NSTOICHM+1` simplifies the handling of sparse data structures. + +.. _table-sto: + +.. list-table:: Sparse Stoichiometric Matrix + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Variable + - Represents + * - :code:`STOICM(NSTOICM)` + - Stoichiometric matrix + * - :code:`IROW_STOICM(NSTOICM)` + - Row indices + * - :code:`ICOL_STOICM(NSTOICM)` + - Column indices + * - :code:`CCOL_STOICM(NREACT+1)` + - Start of columns + +.. _table-sto-fun: + +.. list-table:: Fortran90 functions in ROOT_Stoichiom + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Variable + - Represents + * - :code:`dFun_dRcoeff` + - Derivatives of Fun w/r/t rate coefficients + * - :code:`dJac_dRcoeff` + - Derivatives of Jac w/r/t rate coefficients + * - :code:`ReactantProd` + - Reactant products + * - :code:`JacReactantProd` + - Jacobian of reactant products + +The subroutine :code:`ReactantProd` (see :ref:`table-sto-fun`) +computes the reactant products :code:`ARP` for each reaction, and the +subroutine :code:`JacReactantProd` computes the Jacobian of reactant products +vector, i.e.: + +.. math:: + + \begin{aligned} + \tt JVRP = {\partial{\tt ARP}}/{\partial{\tt V}} + \end{aligned} + +The matrix :code:`JVRP` is sparse and is computed and stored in row +compressed sparse format, as shown in :ref:`table-hess-fun`. The +parameter :code:`NJVRP` holds the number of nonzero elements. For our +:program:`small_strato` example: + +.. code-block:: fortran + + NJVRP = 13 + CROW_JVRP = (/ 1,1,2,3,5,6,7,9,11,13,14 /) + ICOL_JVRP = (/ 2,3,2,3,3,1,1,3,3,4,2,5,4 /) + +.. _table-jvrp: + +.. list-table:: Sparse Data for Jacobian of Reactant Products + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Variable + - Represents + * - :code:`JVRP(NJVRP)` + - Nonzero elements of :code:`JVRP` + * - :code:`ICOL_JVRP(NJVRP)` + - Column indices of :code:`JVRP` + * - :code:`IROW_JVRP(NJVRP)` + - Row indices of :code:`JVRP` + * - :code:`CROW_JVRP(NREACT+1)` + - Start of rows in :code:`JVRP` + +If :command:`#STOICMAT` is set to :command:`ON`, the stoichiometric +formulation allows a direct computation of the derivatives with +respect to rate coefficients. + +The subroutine :code:`dFun_dRcoeff` computes the partial derivative +:code:`DFDR` of the ODE function with respect to a subset of +:code:`NCOEFF` reaction coefficients, whose indices are specified in the array + +.. math:: + + \begin{aligned} + \tt DFDR = {\partial{\tt Vdot}}/{\partial{\tt RCT(JCOEFF)}} + \end{aligned} + +Similarly one can obtain the partial derivative of the Jacobian with +respect to a subset of the rate coefficients. More exactly, KPP +generates the subroutine :code:`dJacR_dCoeff`, which calculates +:code:`DJDR`, the product of this partial derivative with a +user-supplied vector :code:`U`: + +.. math:: + + \begin{aligned} + \tt DJDR = [{\partial{\tt JVS}}/{\partial{\tt RCT(JCOEFF)}}] + \times {\tt U} + \end{aligned} + +.. _Stochastic: + +=============== +ROOT_Stochastic +=============== + +If the generation of stochastic functions is switched on (i.e. when +the command :command:`#STOCHASTIC ON` is added to the KPP definition +file), KPP produces the file :code:`ROOT_Stochastic.f90` (or :code:`.F90`), +with the following functions: + +:code:`Propensity` calculates the propensity vector. The propensity +function uses the number of molecules of variable (:code:`Nmlcv`) and +fixed (:code:`Nmlcf`) species, as well as the stochastic rate +coefficients (:code:`SCT`) to calculate the vector of propensity rates +(:code:`Propensity`). The propensity :math:`\tt Prop_j` defines the +probability that the next reaction in the system is the :math:`j^{th}` +reaction. + +:code:`StochasticRates` converts deterministic rates to +stochastic. The stochastic rate coefficients (:code:`SCT`) are +obtained through a scaling of the deterministic rate +coefficients (:code:`RCT`). The scaling depends on the :code:`Volume` +of the reaction container and on the number of molecules which react. + +:code:`MoleculeChange` calculates changes in the number of +molecules. When the reaction with index :code:`IRCT` takes place, the +number of molecules of species involved in that reaction changes. The +total number of molecules is updated by the function. + +These functions are used by the Gillespie numerical integrators (direct +stochastic simulation algorithm). These integrators are provided in both +Fortran90 and C implementations (the template file name is +:file:`gillespie`). Drivers for stochastic simulations are also +implemented (the template file name is :code:`general_stochastic`.). + +.. _Util: + +========= +ROOT_Util +========= + +In addition to the chemical system description routines discussed above, +KPP generates several utility subroutines and functions in the file +:file:`ROOT_Util.f90` (or :file:`.F90`). + +.. _table-util-fun: + +.. list-table:: Fortran90 subroutines and functions in ROOT_Util + :align: center + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + * - :code:`GetMass` + - Check mass balance for selected atoms + * - :code:`Shuffle_kpp2user` + - Shuffle concentration vector + * - :code:`Shuffle_user2kpp` + - Shuffle concentration vector + * - :code:`InitSaveData` + - Utility for :command:`#LOOKAT` command + * - :code:`SaveData` + - Utility for :command:`#LOOKAT` command + * - :code:`CloseSaveData` + - Utility for :command:`#LOOKAT` command + * - :code:`tag2num` + - Calculate reaction number from equation tag + * - :code:`Integrator_Update_Options` + - Choose :code:`Update_RCONST/PHOTO/SUN` + +The subroutines :code:`InitSaveData`, :code:`SaveData`, and +:code:`CloseSaveData` can be used to print the concentration of the +species that were selected with :command:`#LOOKAT` to the file +:file:`ROOT.dat` (cf. :ref:`lookat-and-monitor`). + +.. _Mex-code: + +=================================================== +ROOT_mex_Fun, ROOT_mex_Jac_SP, and ROOT_mex_Hessian +=================================================== + +:program:`Mex` is a Matlab extension. KPP generates the mex +routines for the ODE function, Jacobian, and Hessian, for the target +languages C, Fortran77, and Fortran90. + +.. tip:: + + To generate Mex files, add the command :command:`#MEX ON` to the KPP + definition file. + +After compilation (using +Matlab’s mex compiler) the mex functions can be called instead of the +corresponding Matlab m-functions. Since the calling syntaxes are +identical, the user only has to insert the :program:`mex` string +within the corresponding function name. Replacing m-functions by +mex-functions gives the same numerical results, but the computational +time could be considerably smaller, especially for large kinetic +systems. + +If possible we recommend to build mex files using the C language, as +Matlab offers most mex interface options for the C language. Moreover, +Matlab distributions come with a native C compiler (:program:`lcc`) for +building executable functions from mex files. The mex files built using +Fortran90 may require further platform-specific tuning of the mex +compiler options. diff --git a/docs/source/output/code_matlab.rst b/docs/source/output/code_matlab.rst new file mode 100644 index 0000000..f3fe656 --- /dev/null +++ b/docs/source/output/code_matlab.rst @@ -0,0 +1,116 @@ +.. _matlab-code: + +############### +The Matlab code +############### + +.. important:: + + Some run-time options for Matlab-language integrators (specified in + the :ref:`ICNTRL and RCNTRL arrays `) do not exactly + correspond to the Fortran90 run-time options. We will standardize + run-time integrator options across all target languages in a future + KPP release. + +`Matlab `_ provides a +high-level programming environment that allows algorithm development, +numerical computations, and data analysis and visualization. The +KPP-generated Matlab code allows for a rapid prototyping of chemical +kinetic schemes, and for a convenient analysis and visualization of the +results. Differences between different kinetic mechanisms can be easily +understood. The Matlab code can be used to derive reference numerical +solutions, which are then compared against the results obtained with +user-supplied numerical techniques. KPP/Matlab can also be used to teach +students fundamentals of chemical kinetics and chemical numerical +simulations. + +Each Matlab function has to reside in a separate m-file. Function calls +use the m-function-file names to reference the function. Consequently, +KPP generates one m-function-file for each of the functions discussed in +the sections entitled :ref:`Function` , +:ref:`Jacobian-and-JacobianSP`, :ref:`Hessian-and-HessianSP`, +:ref:`Stoichiom-and-StoichiomSP`, :ref:`Util`. The names of the +m-function-files are the same as the names of the functions (prefixed +by the model name :code:`ROOT`. + +The variables of :ref:`table-par` are defined as Matlab :code:`global` +variables and initialized in the file +:file:`ROOT_parameter_defs.m`. The variables of :ref:`table-glob` are +declared as Matlab :code:`global` variables in the file +:file:`ROOT_global_defs.m`. They can be accessed from within each +Matlab function by using declarations of the variables of interest. + +The sparse data structures for the Jacobian (cf. :ref:`table-jac`), the Hessian +(cf. :ref:`table-hess`), the stoichiometric matrix (cf. :ref:`table-sto`), +and the Jacobian of reaction (see :ref:`table-jvrp`) are declared as +Matlab :code:`global` variables in the file +:file:`ROOT_Sparse_defs.m`. They are initialized in separate m-files, +namely :file:`ROOT_JacobianSP.m`, :file:`ROOT_HessianSP.m`, and +:file:`ROOT_StoichiomSP.m` respectively. + +Two wrappers (:file:`ROOT_Fun_Chem.m` and :file:`ROOT_Jac_SP_Chem.m`) are +provided for interfacing the ODE function and the sparse ODE Jacobian +with Matlab’s suite of ODE integrators. Specifically, the syntax of +the wrapper calls matches the syntax required by Matlab’s integrators +like ode15s. Moreover, the Jacobian wrapper converts the sparse KPP +format into a Matlab sparse matrix. + +.. _table-matlab: + +.. list-table:: List of Matlab model files + :align: center + :widths: 35 65 + :header-rows: 1 + + * - Function + - Description + * - :file:`ROOT.m` + - Driver + * - :file:`ROOT_parameter_defs.m` + - Global parameters + * - :file:`ROOT_global_defs.m` + - Global variables + * - :file:`ROOT_sparse_defs.m` + - Global sparsity data + * - :file:`ROOT_Fun_Chem.m` + - Template for ODE function + * - :file:`ROOT_Fun.m` + - ODE function + * - :file:`ROOT_Jac_Chem.m` + - Template for ODE Jacobian + * - :file:`ROOT_Jac_SP.m` + - Jacobian in sparse format + * - :file:`ROOT_JacobianSP.m` + - Sparsity data structures + * - :file:`ROOT_Hessian.m` + - ODE Hessian in sparse format + * - :file:`ROOT_HessianSP.m` + - Sparsity data structures + * - :file:`ROOT_Hess_Vec.m` + - Hessian action on vectors + * - :file:`ROOT_HessTR_Vec.m` + - Transposed Hessian action on vectors + * - :file:`ROOT_stoichiom.m` + - Derivatives of Fun and Jac w/r/t rate coefficients + * - :file:`ROOT_stoichiomSP.m` + - Sparse data + * - :file:`ROOT_ReactantProd.m` + - Reactant products + * - :file:`ROOT_JacReactantProd.m` + - Jacobian of reactant products + * - :file:`ROOT_Rates.m` + - User-defined rate reaction laws + * - :file:`ROOT_Update_PHOTO.m` + - Update photolysis rate coefficients + * - :file:`ROOT_Update_RCONST.m` + - Update all rate coefficients + * - :file:`ROOT_Update_SUN.m` + - Update sola intensity + * - :file:`ROOT_GetMass.m` + - Check mass balance for selected atoms + * - :file:`ROOT_Initialize.m` + - Set initial values + * - :file:`ROOT_Shuffle_kpp2user.m` + - Shuffle concentration vector + * - :file:`ROOT_Shuffle_user2kpp.m` + - Shuffle concentration vector diff --git a/docs/source/output/log_file.rst b/docs/source/output/log_file.rst new file mode 100644 index 0000000..69019d4 --- /dev/null +++ b/docs/source/output/log_file.rst @@ -0,0 +1,20 @@ +.. _Log: + +============ +The log file +============ + +The log file :file:`ROOT.log` contains a summary of all the functions, +subroutines and data structures defined in the code file, plus a +summary of the numbering and category of the species involved. + +This file contains supplementary information for the user. Several +statistics are listed here, like the total number equations, the total +number of species, the number of variable and fixed species. Each +species from the chemical mechanism is then listed followed by its type +and numbering. + +Furthermore it contains the complete list of all the functions generated +in the target source file. For each function, a brief description of the +computation performed is attached containing also the meaning of the +input and output parameters. diff --git a/docs/source/output/makefile.rst b/docs/source/output/makefile.rst new file mode 100644 index 0000000..bf6e055 --- /dev/null +++ b/docs/source/output/makefile.rst @@ -0,0 +1,114 @@ +.. _Makefile: + +############ +The Makefile +############ + +KPP produces a :program:`Makefile` that allows for an easy compilation of all +KPP-generated source files. The file name is :file:`Makefile_ROOT`. The +Makefile assumes that the selected driver contains the main program. +However, if no driver was selected (i.e. :command:`#DRIVER none`), it is +necessary to add the name of the main program file manually to the +Makefile. + +Use this command to compile KPP-generated source code into an +executable: + +.. code-block:: console + + $ make -f Makefile_ROOT [target] + +Where :code:`[target]` is one of the following optional values: + +.. _Makefile_all: + +==== +all +==== + +Synoymm for :ref:`Makefile_exe`. + +.. _Makefile_gfortran: + +================= +COMPILER=GFORTRAN +================= + +Builds KPP-genereated Fortran-90 code into an executable with the GNU +:program:`gfortran` compiler. + +This is the default setting for when :command:`#LANGUAGE Fortran90` is +specified. + +.. _Makefile_gcc: + +============ +COMPILER=GCC +============ + +Builds KPP-generated C code into an executable with the GNU +:program:`gcc` compiler. + +This is the default setting for when :command:`#LANGUAGE C` is +specified. + +.. _Makefile_intel: + +============== +COMPILER=INTEL +============== + +Compiles Fortran-90 code generated by KPP into an executable with the +GNU :program:`gfortran` compiler. + +Compiles C code generated by KPP into an executable with the Intel +:program:`icc` compiler. + +.. _Makefile_exe: + +==== +exe +==== + +Compiles KPP-generated source code into an executable. This is the +default option. + +.. _Makefile_mex: + +==== +mex +==== + +Compiles Matlab extensions into the executable when :ref:`#MEX ON +` is specified. + + +.. _Makefile_clean: + +===== +clean +===== + +Removes the following files: + +- Object files (:file:`*.o`) +- Fortran90 module files (:file:`*mod`) +- Executable files (:file:`*.exe`) +- :ref:`Log` (:file:`ROOT.log`) +- Species concentrations specified with :ref:`#LOOKAT + ` (:file:`*.dat`) +- Comma-separated variable files generated by :ref:`graph-cmd` (:code:`*.csv`) +- Matlab extensions generated by :ref:`mex-cmd` (:file:`ROOT*.mexglx`) +- Output from the Matlab executable (:file:`results.m`) + +.. _Makefile_distclean: + +========= +distclean +========= + +Removes all of the files removed by :ref:`Makefile_clean`, as well as: + +- KPP-generated C source code (:file:`ROOT*.c`) +- KPP-generated Fortran90 source code (:file:`ROOT*.f90`, :file:`ROOT*.F90`) +- KPP-generated Matlab source code (:file:`ROOT*.m`) diff --git a/docs/source/reference/editing_these_docs.rst b/docs/source/reference/editing_these_docs.rst index 1f8df05..86c34d9 100644 --- a/docs/source/reference/editing_these_docs.rst +++ b/docs/source/reference/editing_these_docs.rst @@ -38,24 +38,24 @@ Sphinx and its dependencies, which are listed in the table below. - Version * - sphinx - Creates online user manual documentation from markup text files - - 7.2.6 + - 8.2.3 * - `sphinx-autobuild `_ - Dynamically builds Sphinx documentation and displays it in a browser - - 2021.3.14 + - 2024.2.4 * - `sphinx_rtd_theme `_ - Sphinx theme for ReadTheDocs - - 2.0.0 + - 3.1.0 * - `sphinxcontrib-bibtex `_ - Inserts LaTeX-style bibliography citations into ReadTheDocs documentation - - 2.6.2 + - 2.6.5 * - `docutils `_ - Processes plaintext documentation into HTML and other formats - - 0.20.1 - * - `recommonmark `_ + - 0.21.2 + * - `myst-parser `_ - Parses text for docutils - - 0.7.1 + - 5.0.0 * - `jinja2 `_ - Replaces tokenized strings with text - 3.1.6 diff --git a/docs/source/tech_info/06_info_for_kpp_developers.rst b/docs/source/tech_info/06_info_for_kpp_developers.rst deleted file mode 100644 index 37cc575..0000000 --- a/docs/source/tech_info/06_info_for_kpp_developers.rst +++ /dev/null @@ -1,586 +0,0 @@ -.. _developer-info: - -############################## -Information for KPP developers -############################## - -This chapter describes the internal architecture of the KPP -preprocessor, the basic modules and their functionalities, and the -preprocessing analysis performed on the input files. KPP can be very -easily configured to suit a broad class of users. - -.. _directory-structure: - -======================= -KPP directory structure -======================= - -The KPP distribution will unfold a directory :envvar:`$KPP_HOME` with the -following subdirectories: - -src/ ----- - -Contains the KPP source code files: - -.. _table-kpp-dirs: - -.. table:: KPP source code files - :align: center - - +-----------------------+-------------------------------------+ - | File | Description | - +=======================+=====================================+ - | :file:`kpp.c` | Main program | - +-----------------------+-------------------------------------+ - | :file:`code.c` | generic code generation functions | - +-----------------------+-------------------------------------+ - | :file:`code.h` | Header file | - +-----------------------+-------------------------------------+ - | :file:`code_c.c` | Generation of C code | - +-----------------------+-------------------------------------+ - | :file:`code_f90.c` | Generation of F90 code | - +-----------------------+-------------------------------------+ - | :file:`code_matlab.c` | Generation of Matlab code | - +-----------------------+-------------------------------------+ - | :file:`debug.c` | Debugging output | - +-----------------------+-------------------------------------+ - | :file:`gdata.h` | Header file | - +-----------------------+-------------------------------------+ - | :file:`gdef.h` | Header file | - +-----------------------+-------------------------------------+ - | :file:`gen.c` | Generic code generation functions | - +-----------------------+-------------------------------------+ - | :file:`lex.yy.c` | Flex generated file | - +-----------------------+-------------------------------------+ - | :file:`scan.h` | Input for Flex and Bison | - +-----------------------+-------------------------------------+ - | :file:`scan.l` | Input for Flex | - +-----------------------+-------------------------------------+ - | :file:`scan.y` | Input for Bison | - +-----------------------+-------------------------------------+ - | :file:`scanner.c` | Evaluate parsed input | - +-----------------------+-------------------------------------+ - | :file:`scanutil.c` | Evaluate parsed input | - +-----------------------+-------------------------------------+ - | :file:`y.tab.c` | Bison generated file | - +-----------------------+-------------------------------------+ - | :file:`y.tab.h` | Bison generated header file | - +-----------------------+-------------------------------------+ - -bin/ ----- - -Contains the KPP executable. This directory should be added to the -:envvar:`PATH` environment variable. - -util/ ------ - -Contains different function templates useful for the simulation. Each -template file has a suffix that matches the appropriate target -language (Fortran90, C, or Matlab). KPP will run the template files -through the substitution preprocessor (cf. -:ref:`list-of-symbols-replaced`). The user can define their own -auxiliary functions by inserting them into the files. - -models/ -------- - -Contains the description of the chemical models. Users -can define their own models by placing the model description files in -this directory. The KPP distribution contains several models from -atmospheric chemistry which can be used as templates for model -definitions. - -drv/ ----- - -Contains driver templates for chemical simulations. Each driver has a -suffix that matches the appropriate target language (Fortran90, C, or -Matlab). KPP will run the appropriate driver through the substitution -preprocessor (cf. :ref:`list-of-symbols-replaced`). Users can also -define their own driver templates here. - -int/ ----- - -Contains numerical solvers (integrators). The :command:`#INTEGRATOR` -command will force KPP to look into this directory for a definition -file with suffix :code:`.def`. This file selects the numerical solver -etc. Each integrator template is found in a file that ends with the -appropriate suffix (:code:`.f90`, :code:`.c`, or :code:`.m`). The -selected template is processed by the substitution preprocessor (cf. -:ref:`list-of-symbols-replaced`). Users can define their own -numerical integration routines in the :code:`user_contributed` -subdirectory. - -examples/ ---------- - -Contains several model description examples (:file:`.kpp` files) -which can be used as templates for building simulations with KPP. - -site-lisp/ ----------- -Contains the file :file:`kpp.el` which provides a KPP mode for emacs -with color highlighting. - -ci-tests/ ---------- - -Contains directories defining several :ref:`ci-tests`. - -.ci-pipelines/ --------------- - -Hidden directory containing a YAML file with settings for automatically -running the continuous integration tests on `Azure DevOps Pipelines -`_ - -Also contains bash scripts (ending in :file:`.sh`) for running the -continuous integration tests either automatically in Azure Dev -Pipelines, or manually from the command line. For more -information, please see :ref:`ci-tests`. - -.github/workflows ------------------ - -Contains configuration files for `GitHub Actions -`_ that will run -automatically when commits are pushed or when pull requests are opened. - -.. _kpp-env-vars: - -========================= -KPP environment variables -========================= - -In order for KPP to find its components, it has to know the path to the -location where the KPP distribution is installed. This is achieved by -setting the :envvar:`$KPP_HOME` environment variable to the path where -KPP is installed. - -The :file:`$KPP_HOME/bin` directory. should be added to the -:envvar:`PATH` variable. - -There are also several optional environment variable that control the places -where KPP looks for module files, integrators, and drivers: - -KPP_HOME --------- - -Required, stores the absolute path to the KPP distribution. - -Default setting: none. - -KPP_FLEX_LIB_DIR ----------------- - -Optional. Use this to specify the path to the :ref:`flex library -file ` (:file:`libfl.so` or :file:`libfl.a`) that are -needed to :ref:`build the KPP executable `. The KPP -build sequence will use the path contained in -:envvar:`KPP_FLEX_LIB_DIR` if the flex library file cannot be found -in :file:`/usr/lib`, :file:`/usr/lib64`, and similar standard -library paths. - -KPP_MODEL ---------- - -Optional, specifies additional places where KPP will look for model -files before searching the default location. - -Default setting: :file:`$KPP_HOME/models`. - -KPP_INT -------- - -Optional, specifies additional places where KPP will look for -integrator files before searching the default. - -Default setting: :file:`$KPP_HOME/int`. - -KPP_DRV -------- - -Optional specifies additional places where KPP will look for driver -files before searching the default directory. - -Default setting: :file:`$KPP_HOME/drv`. - -.. _kpp-internal-modules: - -==================== -KPP internal modules -==================== - -.. _scanner-parser: - -Scanner and parser ------------------- - -This module is responsible for reading the kinetic description files and -extracting the information necessary in the code generation phase. We -make use of the flex and bison generic tools in implementing our own -scanner and parser. Using these tools, this module gathers information -from the input files and fills in the following data structures in -memory: - -- The atom list - -- The species list - -- The left hand side matrix of coefficients - -- The right hand side matrix of coefficients - -- The equation rates - -- The option list - -Error checking is performed at each step in the scanner and the parser. -For each syntax error the exact line and input file, along with an -appropriate error message are produced. Some other errors like mass -balance, and equation duplicates, are tested at the end of this phase. - -.. _species-reordering: - -Species reordering ------------------- - -When parsing the input files, the species list is updated as soon as a -new species is encountered in a chemical equation. Therefore the -ordering of the species is the order in which they appear in the -equation description section. This is not a useful order for subsequent -operations. The species have to be first sorted such that all variable -species and all fixed species are put together. Then if a sparsity -structure of the Jacobian is required, it might be better to reorder the -species in such a way that the factorization of the Jacobian will -preserve the sparsity. This reordering is done using a Markovitz type -algorithm. - -.. _expression-trees: - -Expression trees computation ----------------------------- - -This is the core of the preprocessor. This module generates the -production/destruction functions, the Jacobian and all the data -structure nedeed by these functions. It builds a language-independent -structure of each function and statement in the target source file. -Instead of using an intermediate format for this as some other compilers -do, KPP generates the intermediate format for just one statement at a -time. The vast majority of the statements in the target source file are -assignments. The expression tree for each assignment is incrementally -built by scanning the coefficient matrices and the rate constant vector. -At the end, these expression trees are simplified. Similar approaches are -applied to function declaration and prototypes, data declaration and -initialization. - -.. _code-generation: - -Code generation ---------------- - -There are basically two modules, each dealing with the syntax -particularities of the target language. For example, the C module -includes a function that generates a valid C assignment when given an -expression tree. Similarly there are functions for data declaration, -initializations, comments, function prototypes, etc. Each of these -functions produce the code into an output buffer. A language-specific -routine reads from this buffer and splits the statements into lines to -improve readability of the generated code. - -.. _adding-new-commands: - -======================= -Adding new KPP commands -======================= - -To add a new KPP command, the source code has to be edited at several -locations. A short summary is presented here, using :code:`NEWCMD` as an -example: - -* Add the new command to several files in the :file:`src/` directory: - - - :file:`scan.h`: add :code:`void CmdNEWCMD( char *cmd );` - - - :file:`scan.l`: add :code:`{ "NEWCMD", PRM_STATE, NEWCMD },` - - - :file:`scanner.c`: add :code:`void CmdNEWCMD( char *cmd )` - - - :file:`scan.y`: - - - Add :code:`%token NEWCMD` - - - Add :code:`| NEWCMD PARAMETER` - - - Add :code:`{ CmdNEWCMD( $2 ); }` - -* Add :ref:`ci-tests`: - - - Create a new directory :file:`ci-tests/ros_newcmd/ros_newcmd.kpp` - - - Add new :ref:`ci-tests` to the :file:`ci-tests` directory and - update the scripts in the :file:`.ci-pipelines` directory. - -* Other: - - - Explain in user manual :file:`docs/source/*/*.rst`: - - - Add to Table :ref:`table-cmd-defaults` - - - Add a new subsection to :ref:`kpp-commands` - - - Add to the Table :ref:`bnf-description` - - - Add to :file:`site-lisp/kpp.el` - -.. _ci-tests: - -============================ -Continuous integration tests -============================ - -KPP contains several continuous integration (aka C-I) tests. Each C-I -test calls KPP to generate source code for a given -:ref:`chemical mechanism `, :ref:`integrator -`, and :ref:`target language `, and -then runs a short "box model" simulation with the generated code. C-I -tests help to ensure that new features and updates added to KPP will -not break any existing functionality. - -C-I tests will run automatically as a `GitHub Action -`_ when commits -are pushed to the `KPP Github repository -`_, or when a new pull -requests are opened. You may also run the integration tests -:ref:`locally on your own computer `. - -.. _list-of-ci-tests: - -List of continuous integration tests ------------------------------------- - -.. list-table:: Continuous integration tests - :header-rows: 1 - :align: center - - * - C-I test - - Language - - Model - - Integrator - * - :code:`C_rk` - - C - - small_strato - - runge_kutta - * - :code:`C_rosadj` - - C - - small_strato - - rosenbrock_adj - * - :code:`C_sd` - - C - - small_strato - - sdirk - * - :code:`C_sdadj` - - C - - small_strato - - sdirk_adj - * - :code:`C_small_strato` - - C - - small_strato - - rosenbrock - * - :code:`F90_feuler` - - Fortran90 - - carbon - - feuler - * - :code:`F90_graph` - - Fortran90 - - small_strato - - rosenbrock - * - :code:`F90_lsode` - - Fortran90 - - small_strato - - lsode - * - :code:`F90_mcm` - - Fortran90 - - mcm - - rosenbrock - * - :code:`F90_mcm_h211b` - - Fortran90 - - mcm - - rosenbrock_h211b_qssa - * - :code:`F90_radau` - - Fortran90 - - saprc99 - - radau5 - * - :code:`F90_rk` - - Fortran90 - - small_strato - - runge_kutta - * - :code:`F90_rkadj` - - Fortran90 - - small_strato - - runge_kutta_adj - * - :code:`F90_rktlm` - - Fortran90 - - small_strato - - runge_kutta_tlm - * - :code:`F90_ros` - - Fortran90 - - small_strato - - rosenbrock - * - :code:`F90_rosadj` - - Fortran90 - - small_strato - - rosenbrock_adj - * - :code:`F90_ros_autoreduce` - - Fortran90 - - saprc99 - - rosenbrock_autoreduce - * - :code:`F90_rosenbrock` - - Fortran90 - - saprc99 - - rosenbrock - * - :code:`F90_ros_h211b` - - Fortran90 - - saprc99 - - rosenbrock_h211b_qssa - * - :code:`F90_ros_split` - - Fortran90 - - small_strato - - rosenbrock - * - :code:`F90_rostlm` - - Fortran90 - - small_strato - - rosenbrock_tlm - * - :code:`F90_ros_upcase` - - Fortran90 - - saprc99 - - rosenbrock - * - :code:`F90_saprc_2006` - - Fortran90 - - saprcnov - - rosenbrock - * - :code:`F90_sd4` - - Fortran90 - - small_strato - - sdirk4 - * - :code:`F90_sd` - - Fortran90 - - small_strato - - sdirk - * - :code:`F90_sdadj` - - Fortran90 - - small_strato - - sdirk_adj - * - :code:`F90_sdtlm` - - Fortran90 - - small_strato - - sdirk_tlm - * - :code:`F90_seulex` - - Fortran90 - - saprcnov - - seulex - * - :code:`F90_small_strato` - - Fortran90 - - small_strato - - rosenbrock - * - :code:`X_minver` - - Fortran90 - - small_strato - - runge_kutta - -Notes about C-I tests: - -#. :file:`F90_ros_split` also uses :command:`#FUNCTION SPLIT`. -#. :file:`F90_ros_upcase` also uses :command:`#UPPERCASEF90 ON`. -#. :file:`F90_small_strato` is the example from - :ref:`running-kpp-with-an-example-mechanism`. -#. :file:`X_minver` tests if the :ref:`minversion-cmd` command works - properly. - -Each continuous integration test is contained in a subdirectory of -:file:`$KPP_HOME/ci-tests`. In each subdirectory is a KPP definition -file (ending in :file:`.kpp`). - -.. _running-ci-tests: - -Running continuous integration tests as a GitHub Action -------------------------------------------------------- - -The files needed to run the C-I tests are described below. - -.. _running-ci-tests-action: - -run-ci-tests.yml -~~~~~~~~~~~~~~~~ - -**Path**: :file:`$KPP_HOME/.github/workflows/run-ci-tests.yml` - -**Description:** Configuration file with commands to download KPP, load -libraries, and run the C-I tests as a GitHub Action. - -C-I tests will run automatically when a commit is pushed to any branch -at `https://github.com/KineticPreProcessor/KPP -`_, or when a new pull -request is opened there. This is the recommended setting, but you can -restrict this so that only pushes or pull requests to certain branches -will trigger the C-I tests. - -.. _running-ci-tests-testing: - -ci-testing-script.sh -~~~~~~~~~~~~~~~~~~~~ - -**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-testing-script.sh` - -**Description:** Runs the KPP C-I tests as a GitHub Action, or on a -local computer system. - -.. _running-ci-tests-cleanup: - -ci-cleanup-script.sh -~~~~~~~~~~~~~~~~~~~~ - -**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-cleanup-script.sh` - -**Description:** Removes compiler-generated files (e.g. :file:`*.o`, -:file:`.mod` , and :file:`.exe`) from C-I test folders. - -.. _running-ci-tests-defs: - -ci-common-defs.sh -~~~~~~~~~~~~~~~~~~ - -**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-common-defs.sh` - -**Description** Contains common variable and function definitions needed by -:ref:`running-ci-tests-testing` and :ref:`running-ci-tests-cleanup`. - -.. _running-ci-tests-locally: - -Running continuous integration tests locally --------------------------------------------- - -To run the C-I tests on a local computer system, use this command: - -.. code-block:: console - - $ $KPP_HOME/.ci-pipelines/ci-testing-script.sh | tee ci-tests.log - -This will run all C-I tests on your own computer system and pipe the -results to a log file. This will easily allow you to check if the -results of the C-I tests are identical to C-I tests that were run on a -prior commit or pull request. - -To remove the files generated by the continuous integration tests, use -this command: - -.. code-block :: console - - $ $KPP_HOME/.ci-pipelines/ci-cleanup-script.sh - -If you add new C-I tests, be sure to add the name of the new tests to -the variable :code:`GENERAL_TESTS` in :file:`ci-common-defs.sh`. diff --git a/docs/source/tech_info/about_ci_tests.rst b/docs/source/tech_info/about_ci_tests.rst new file mode 100644 index 0000000..a83f2f3 --- /dev/null +++ b/docs/source/tech_info/about_ci_tests.rst @@ -0,0 +1,286 @@ +.. _ci-tests: + +############################ +Continuous integration tests +############################ + +KPP contains several continuous integration (aka C-I) tests. Each C-I +test calls KPP to generate source code for a given +:ref:`chemical mechanism `, :ref:`integrator +`, and :ref:`target language `, and +then runs a short "box model" simulation with the generated code. C-I +tests help to ensure that new features and updates added to KPP will +not break any existing functionality. + +C-I tests will run automatically as a `GitHub Action +`_ when commits +are pushed to the `KPP Github repository +`_, or when a new pull +requests are opened. You may also run the integration tests +:ref:`locally on your own computer `. + +.. _list-of-ci-tests: + +==================================== +List of continuous integration tests +==================================== + +.. list-table:: Continuous integration tests + :header-rows: 1 + :align: center + + * - C-I test + - Language + - Model + - Integrator + - What it tests + * - :code:`C_rk` + - C + - small_strato + - runge_kutta + - :ref:`Runge-Kutta integrator ` + * - :code:`C_rosadj` + - C + - small_strato + - rosenbrock_adj + - :ref:`Rosenbrock discrete adjoint ` + * - :code:`C_sd` + - C + - small_strato + - sdirk + - :ref:`SDIRK integrator ` + * - :code:`C_sdadj` + - C + - small_strato + - sdirk_adj + - :ref:`SDIRK discrete adjoint ` + * - :code:`C_small_strato` + - C + - small_strato + - rosenbrock + - :ref:`Rosenbrock integrator ` + * - :code:`F90_feuler` + - Fortran90 + - carbon + - feuler + - :ref:`Forward Euler integrator ` + * - :code:`F90_graph` + - Fortran90 + - small_strato + - rosenbrock + - :ref:`#GRAPH command ` + * - :code:`F90_lsode` + - Fortran90 + - small_strato + - lsode + - :ref:`LSODE integrator ` + * - :code:`F90_mcm` + - Fortran90 + - mcm + - rosenbrock + - Master Chemical Mechanism + * - :code:`F90_mcm_h211b` + - Fortran90 + - mcm + - rosenbrock_h211b_qssa + - :ref:`Rosenbrock int. w/ H211b time stepping ` + * - :code:`F90_radau` + - Fortran90 + - saprc99 + - radau5 + - :ref:`RADAU5 integrator ` + * - :code:`F90_rk` + - Fortran90 + - small_strato + - runge_kutta + - :ref:`Runge-Kutta integrator ` + * - :code:`F90_rkadj` + - Fortran90 + - small_strato + - runge_kutta_adj + - :ref:`Runge-Kutta discrete adjoint ` + * - :code:`F90_rktlm` + - Fortran90 + - small_strato + - runge_kutta_tlm + - :ref:`Runge-Kutta tangent linear model ` + * - :code:`F90_ros` + - Fortran90 + - small_strato + - rosenbrock + - :ref:`Rosenbrock integrator ` + * - :code:`F90_rosadj` + - Fortran90 + - small_strato + - rosenbrock_adj + - :ref:`Rosenbrock discrete adjoint ` + * - :code:`F90_ros_autoreduce` + - Fortran90 + - saprc99 + - rosenbrock_autoreduce + - :ref:`Rosenbrock integrator w/ auto-reduction ` + * - :code:`F90_rosenbrock` + - Fortran90 + - saprc99 + - rosenbrock + - :ref:`Rosenbrock integrator ` + * - :code:`F90_ros_h211b` + - Fortran90 + - saprc99 + - rosenbrock_h211b_qssa + - :ref:`Rosenbrock int. w/ H211b time stepping ` + * - :code:`F90_ros_passivespc` + - Fortran90 + - small_strato + - rosenbrock + - Excluding passive species + * - :code:`F90_ros_split` + - Fortran90 + - small_strato + - rosenbrock + - :ref:`#FUNCTION SPLIT ` + * - :code:`F90_rostlm` + - Fortran90 + - small_strato + - rosenbrock_tlm + - :ref:`Rosenbrock tangent linear model ` + * - :code:`F90_ros_upcase` + - Fortran90 + - saprc99 + - rosenbrock + - :ref:`#UPPERCASEF90 ON ` + * - :code:`F90_saprc_2006` + - Fortran90 + - saprcnov + - rosenbrock + - :ref:`Rosenbrock integrator ` + * - :code:`F90_sd4` + - Fortran90 + - small_strato + - sdirk4 + - :ref:`Rosenbrock integrator ` + * - :code:`F90_sd` + - Fortran90 + - small_strato + - sdirk + - :ref:`SDIRK integrator ` + * - :code:`F90_sdadj` + - Fortran90 + - small_strato + - sdirk_adj + - :ref:`SDIRK discrete adjoint ` + * - :code:`F90_sdtlm` + - Fortran90 + - small_strato + - sdirk_tlm + - :ref:`SDIRK tangent linear model ` + * - :code:`F90_seulex` + - Fortran90 + - saprcnov + - seulex + - :ref:`SEULEX integrator ` + * - :code:`F90_small_strato` + - Fortran90 + - small_strato + - rosenbrock + - :ref:`Rosenbrock integrator ` + * - :code:`X_minver` + - Fortran90 + - small_strato + - runge_kutta + - :ref:`#MINVERSION command ` + +Notes about C-I tests: + +#. :file:`F90_ros_split` uses :command:`#FUNCTION SPLIT`. +#. :file:`F90_ros_upcase` uses :command:`#UPPERCASEF90 ON`. +#. :file:`F90_small_strato` is the example from + :ref:`running-kpp-with-an-example-mechanism`. +#. :file:`X_minver` tests if the :ref:`minversion-cmd` command works + properly. + +Each continuous integration test is contained in a subdirectory of +:file:`$KPP_HOME/ci-tests`. In each subdirectory is a KPP definition +file (ending in :file:`.kpp`). + +.. _running-ci-tests: + +======================================================= +Running continuous integration tests as a GitHub Action +======================================================= + +The files needed to run the C-I tests are described below. + +.. _running-ci-tests-action: + +run-ci-tests.yml +---------------- + +**Path**: :file:`$KPP_HOME/.github/workflows/run-ci-tests.yml` + +**Description:** Configuration file with commands to download KPP, load +libraries, and run the C-I tests as a GitHub Action. + +C-I tests will run automatically when a commit is pushed to any branch +at `https://github.com/KineticPreProcessor/KPP +`_, or when a new pull +request is opened there. This is the recommended setting, but you can +restrict this so that only pushes or pull requests to certain branches +will trigger the C-I tests. + +.. _running-ci-tests-testing: + +ci-testing-script.sh +-------------------- + +**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-testing-script.sh` + +**Description:** Runs the KPP C-I tests as a GitHub Action, or on a +local computer system. + +.. _running-ci-tests-cleanup: + +ci-cleanup-script.sh +-------------------- + +**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-cleanup-script.sh` + +**Description:** Removes compiler-generated files (e.g. :file:`*.o`, +:file:`.mod` , and :file:`.exe`) from C-I test folders. + +.. _running-ci-tests-defs: + +ci-common-defs.sh +----------------- + +**Path:** :file:`$KPP_HOME/.ci-pipelines/ci-common-defs.sh` + +**Description** Contains common variable and function definitions needed by +:ref:`running-ci-tests-testing` and :ref:`running-ci-tests-cleanup`. + +.. _running-ci-tests-locally: + +============================================ +Running continuous integration tests locally +============================================ + +To run the C-I tests on a local computer system, use this command: + +.. code-block:: console + + $ $KPP_HOME/.ci-pipelines/ci-testing-script.sh | tee ci-tests.log + +This will run all C-I tests on your own computer system and pipe the +results to a log file. This will easily allow you to check if the +results of the C-I tests are identical to C-I tests that were run on a +prior commit or pull request. + +To remove the files generated by the continuous integration tests, use +this command: + +.. code-block :: console + + $ $KPP_HOME/.ci-pipelines/ci-cleanup-script.sh + +If you add new C-I tests, be sure to add the name of the new tests to +the variable :code:`GENERAL_TESTS` in :file:`ci-common-defs.sh`. diff --git a/docs/source/tech_info/adding_new_commands.rst b/docs/source/tech_info/adding_new_commands.rst new file mode 100644 index 0000000..1a93054 --- /dev/null +++ b/docs/source/tech_info/adding_new_commands.rst @@ -0,0 +1,39 @@ +.. |br| raw:: html + +
+ +.. _adding-new-commands: + +####################### +Adding new KPP commands +####################### + +To add a new KPP command, the source code has to be edited at several +locations. A short summary is presented here, using :code:`NEWCMD` as an +example: + +#. Add the new command to several files in the :file:`src/` directory: + + - :file:`scan.h`: add :code:`void CmdNEWCMD( char *cmd );` + - :file:`scan.l`: add :code:`{ "NEWCMD", PRM_STATE, NEWCMD },` + - :file:`scanner.c`: add :code:`void CmdNEWCMD( char *cmd )` + - :file:`scan.y`: + + - Add :code:`%token NEWCMD` + - Add :code:`| NEWCMD PARAMETER` + - Add :code:`{ CmdNEWCMD( $2 ); }` |br| |br| + + +#. Add :ref:`ci-tests`: + + - Create a new directory :file:`ci-tests/ros_newcmd/ros_newcmd.kpp` + - Add new :ref:`ci-tests` to the :file:`ci-tests` directory and + update the scripts in the :file:`.ci-pipelines` directory. |br| |br| + +#. Add documentation to user manual :file:`docs/source/*/*.rst`: + + - Add to Table :ref:`table-cmd-defaults` + - Add a new subsection to :ref:`kpp-commands` + - Add to the Table :ref:`bnf-description` |br| |br| + +#. Add command to :file:`site-lisp/kpp.el` (Emacs configuration file) diff --git a/docs/source/tech_info/08_bnf_description_of_kpp_lang.rst b/docs/source/tech_info/bnf_description_of_kpp_lang.rst similarity index 98% rename from docs/source/tech_info/08_bnf_description_of_kpp_lang.rst rename to docs/source/tech_info/bnf_description_of_kpp_lang.rst index f87abe2..84eb0d8 100644 --- a/docs/source/tech_info/08_bnf_description_of_kpp_lang.rst +++ b/docs/source/tech_info/bnf_description_of_kpp_lang.rst @@ -31,6 +31,7 @@ Following is the BNF-like specification of the KPP language: #DUMMYINDEX [ ON | OFF ] | #EQNTAGS [ ON | OFF ] | #FUNCTION [ AGGREGATE | SPLIT ] | + #GRAPH [ OFF | STOIC | EDGELIST ] | #HESSIAN [ ON | OFF ] | #INCLUDE file_name | #INTEGRATOR integrator_name | diff --git a/docs/source/tech_info/kpp_dir_structure.rst b/docs/source/tech_info/kpp_dir_structure.rst new file mode 100644 index 0000000..0d10fd1 --- /dev/null +++ b/docs/source/tech_info/kpp_dir_structure.rst @@ -0,0 +1,152 @@ +.. _directory-structure: + +####################### +KPP directory structure +####################### + +The KPP distribution will unfold a directory :envvar:`$KPP_HOME` with the +following subdirectories: + +==== +src/ +==== + +Contains the KPP source code files: + +.. _table-kpp-dirs: + +.. list-table:: KPP source code files + :align: center + :widths: 30 70 + :header-rows: 1 + + * - File + - Description + * - :file:`kpp.c` + - Main program + * - :file:`code.c` + - generic code generation functions + * - :file:`code.h` + - Header file + * - :file:`code_c.c` + - Generation of C code + * - :file:`code_f90.c` + - Generation of F90 code + * - :file:`code_matlab.c` + - Generation of Matlab code + * - :file:`debug.c` + - Debugging output + * - :file:`gdata.h` + - Header file + * - :file:`gdef.h` + - Header file + * - :file:`gen.c` + - Generic code generation functions + * - :file:`lex.yy.c` + - Flex generated file + * - :file:`scan.h` + - Input for Flex and Bison + * - :file:`scan.l` + - Input for Flex + * - :file:`scan.y` + - Input for Bison + * - :file:`scanner.c` + - Evaluate parsed input + * - :file:`scanutil.c` + - Evaluate parsed input + * - :file:`y.tab.c` + - Bison generated file + * - :file:`y.tab.h` + - Bison generated header file + +==== +bin/ +==== + +Contains the KPP executable. This directory should be added to the +:envvar:`PATH` environment variable. + +===== +util/ +===== + +Contains different function templates useful for the simulation. Each +template file has a suffix that matches the appropriate target +language (Fortran90, C, or Matlab). KPP will run the template files +through the substitution preprocessor (cf. +:ref:`list-of-symbols-replaced`). The user can define their own +auxiliary functions by inserting them into the files. + +======= +models/ +======= + +Contains the description of the chemical models. Users +can define their own models by placing the model description files in +this directory. The KPP distribution contains several models from +atmospheric chemistry which can be used as templates for model +definitions. + +==== +drv/ +==== + +Contains driver templates for chemical simulations. Each driver has a +suffix that matches the appropriate target language (Fortran90, C, or +Matlab). KPP will run the appropriate driver through the substitution +preprocessor (cf. :ref:`list-of-symbols-replaced`). Users can also +define their own driver templates here. + +==== +int/ +==== + +Contains numerical solvers (integrators). The :command:`#INTEGRATOR` +command will force KPP to look into this directory for a definition +file with suffix :code:`.def`. This file selects the numerical solver +etc. Each integrator template is found in a file that ends with the +appropriate suffix (:code:`.f90`, :code:`.c`, or :code:`.m`). The +selected template is processed by the substitution preprocessor (cf. +:ref:`list-of-symbols-replaced`). Users can define their own +numerical integration routines in the :code:`user_contributed` +subdirectory. + +========= +examples/ +========= + +Contains several model description examples (:file:`.kpp` files) +which can be used as templates for building simulations with KPP. + +========== +site-lisp/ +========== +Contains the file :file:`kpp.el` which provides a KPP mode for emacs +with color highlighting. + +========= +ci-tests/ +========= + +Contains directories defining several :ref:`ci-tests`. + +============== +.ci-pipelines/ +============== + +Hidden directory containing a YAML file with settings for automatically +running the continuous integration tests on `Azure DevOps Pipelines +`_ + +Also contains bash scripts (ending in :file:`.sh`) for running the +continuous integration tests either automatically in Azure Dev +Pipelines, or manually from the command line. For more +information, please see :ref:`ci-tests`. + +================= +.github/workflows +================= + +Contains configuration files for `GitHub Actions +`_ that will run +automatically when commits are pushed or when pull requests are opened. diff --git a/docs/source/tech_info/kpp_env_vars.rst b/docs/source/tech_info/kpp_env_vars.rst new file mode 100644 index 0000000..f069e7d --- /dev/null +++ b/docs/source/tech_info/kpp_env_vars.rst @@ -0,0 +1,63 @@ +.. _kpp-env-vars: + +######################### +KPP environment variables +######################### + +In order for KPP to find its components, it has to know the path to the +location where the KPP distribution is installed. This is achieved by +setting the :envvar:`$KPP_HOME` environment variable to the path where +KPP is installed. + +The :file:`$KPP_HOME/bin` directory. should be added to the +:envvar:`PATH` variable. + +There are also several optional environment variable that control the places +where KPP looks for module files, integrators, and drivers: + +======== +KPP_HOME +======== + +Required, stores the absolute path to the KPP distribution. + +Default setting: none. + +================ +KPP_FLEX_LIB_DIR +================ + +Optional. Use this to specify the path to the :ref:`flex library +file ` (:file:`libfl.so` or :file:`libfl.a`) that are +needed to :ref:`build the KPP executable `. The KPP +build sequence will use the path contained in +:envvar:`KPP_FLEX_LIB_DIR` if the flex library file cannot be found +in :file:`/usr/lib`, :file:`/usr/lib64`, and similar standard +library paths. + +========= +KPP_MODEL +========= + +Optional, specifies additional places where KPP will look for model +files before searching the default location. + +Default setting: :file:`$KPP_HOME/models`. + +======= +KPP_INT +======= + +Optional, specifies additional places where KPP will look for +integrator files before searching the default. + +Default setting: :file:`$KPP_HOME/int`. + +======= +KPP_DRV +======= + +Optional specifies additional places where KPP will look for driver +files before searching the default directory. + +Default setting: :file:`$KPP_HOME/drv`. diff --git a/docs/source/tech_info/kpp_internal_modules.rst b/docs/source/tech_info/kpp_internal_modules.rst new file mode 100644 index 0000000..31d492d --- /dev/null +++ b/docs/source/tech_info/kpp_internal_modules.rst @@ -0,0 +1,86 @@ +.. _kpp-internal-modules: + +#################### +KPP internal modules +#################### + +.. _scanner-parser: + +================== +Scanner and parser +================== + +This module is responsible for reading the kinetic description files and +extracting the information necessary in the code generation phase. We +make use of the flex and bison generic tools in implementing our own +scanner and parser. Using these tools, this module gathers information +from the input files and fills in the following data structures in +memory: + +- The atom list + +- The species list + +- The left hand side matrix of coefficients + +- The right hand side matrix of coefficients + +- The equation rates + +- The option list + +Error checking is performed at each step in the scanner and the parser. +For each syntax error the exact line and input file, along with an +appropriate error message are produced. Some other errors like mass +balance, and equation duplicates, are tested at the end of this phase. + +.. _species-reordering: + +================== +Species reordering +================== + +When parsing the input files, the species list is updated as soon as a +new species is encountered in a chemical equation. Therefore the +ordering of the species is the order in which they appear in the +equation description section. This is not a useful order for subsequent +operations. The species have to be first sorted such that all variable +species and all fixed species are put together. Then if a sparsity +structure of the Jacobian is required, it might be better to reorder the +species in such a way that the factorization of the Jacobian will +preserve the sparsity. This reordering is done using a Markovitz type +algorithm. + +.. _expression-trees: + +============================ +Expression trees computation +============================ + +This is the core of the preprocessor. This module generates the +production/destruction functions, the Jacobian and all the data +structure nedeed by these functions. It builds a language-independent +structure of each function and statement in the target source file. +Instead of using an intermediate format for this as some other compilers +do, KPP generates the intermediate format for just one statement at a +time. The vast majority of the statements in the target source file are +assignments. The expression tree for each assignment is incrementally +built by scanning the coefficient matrices and the rate constant vector. +At the end, these expression trees are simplified. Similar approaches are +applied to function declaration and prototypes, data declaration and +initialization. + +.. _code-generation: + +=============== +Code generation +=============== + +There are basically two modules, each dealing with the syntax +particularities of the target language. For example, the C module +includes a function that generates a valid C assignment when given an +expression tree. Similarly there are functions for data declaration, +initializations, comments, function prototypes, etc. Each of these +functions produce the code into an output buffer. A language-specific +routine reads from this buffer and splits the statements into lines to +improve readability of the generated code. diff --git a/docs/source/using_kpp/04_input_for_kpp.rst b/docs/source/using_kpp/04_input_for_kpp.rst deleted file mode 100644 index ccc8564..0000000 --- a/docs/source/using_kpp/04_input_for_kpp.rst +++ /dev/null @@ -1,1912 +0,0 @@ -.. _input-for-kpp: - -############# -Input for KPP -############# - -KPP basically handles two types of input files: **Kinetic description -files** and **auxiliary files**. Kinetic description files are in KPP -syntax and described in the following sections. Auxiliary files are -described in the section entitled -:ref:`auxiliary-files-and-the-substitution-preprocessor`. - -KPP kinetic description files specify the chemical equations, the -initial values of each of the species involved, the integration -parameters, and many other options. The KPP preprocessor parses the -kinetic description files and generates several output files. Files -that are written in KPP syntax have one of the suffixes :file:`.kpp`, -:file:`.spc`, :file:`.eqn`, or :file:`def`. - -The following general rules define the structure of a kinetic -description file: - -- A KPP program is composed of :ref:`kpp-sections`, - :ref:`kpp-commands`, and :ref:`inlined-code`. Their syntax is - presented in :ref:`bnf-description`. - -- Comments are either enclosed between the curly braces ":code:`{`" - and ":code:`}`", or written in a line starting with two slashes and - a space "// ". - -- Any name given by the user to denote an atom or a species is - restricted to be less than 32 character in length and can only - contain letters, numbers, or the underscore character. The first - character cannot be a number. All names are case insensitive. - -The kinetic description files contain a detailed specification of the -chemical model, information about the integration method and the desired -type of results. KPP accepts only one of these files as input, but using -the :ref:`include-cmd` command, code from separate files can be -combined. The include files can be nested up to 10 levels. KPP will -parse these files as if they were a single big file. By carefully -splitting the chemical description, KPP can be configured for a broad -range of users. In this way the users can have direct access to that -part of the model that they are interested in, and all the other details -can be hidden inside several include files. Often, the atom definitions -(:file:`atoms.kpp`) are included first, then species definitions -(:file:`*.spc`), and finally the equations of the chemical mechanism -(:file:`*.eqn`). - -.. _kpp-sections: - -============ -KPP sections -============ - -A :literal:`#` sign at the beginning of a line followed by a section -name starts a new KPP section. Then a list of items separated by -semicolons follows. A section ends when another KPP section or command -occurs, i.e. when another :literal:`#` sign occurs at the beginning of -a line. The syntax of an item definition is different for each -particular section. - -.. _atoms: - -#ATOMS ------- - -The atoms that will be further used to specify the components of a -species must be declared in an :command:`#ATOMS` section, e.g.: - -.. code-block:: console - - #ATOMS N; O; Na; Br; - -Usually, the names of the atoms are the ones specified in the periodic -table of elements. For this table there is a predefined file containing -all definitions that can be used by the command: - -.. code-block:: console - - #INCLUDE atoms.kpp - -This should be the first line in a KPP input file, because it allows to -use any atom in the periodic table of elements throughout the kinetic -description file. - -.. _check: - -#CHECK ------- - -KPP is able to do mass balance checks for all equations. Some chemical -equations are not balanced for all atoms, and this might still be -correct from a chemical point of view. To accommodate for this, KPP can -perform mass balance checking only for the list of atoms specified in -the :command:`#CHECK` section, e.g.: - -.. code-block:: console - - #CHECK N; C; O; - -The balance checking for all atoms can be enabled by using the -:command:`#CHECKALL` command. Without :command:`#CHECK` or -:command:`#CHECKALL`, no checking is performed. The :literal:`IGNORE` -atom can also be used to control mass balance checking. - -.. _defvar-and-deffix: - -#DEFVAR and #DEFFIX -------------------- - -There are two ways to declare new species together with their atom -composition: :command:`#DEFVAR` and :command:`#DEFFIX`. These sections -define all the species that will be used in the chemical mechanism. -Species can be variable or fixed. The type is implicitly specified by -defining the species in the appropriate sections. A fixed species does -not vary through chemical reactions. - -For each species the user has to declare the atom composition. This -information is used for mass balance checking. To ignore mass balance -checking for a given species, one can declare the predefined atom -:command:`IGNORE` as being part of the species composition. Examples -for these sections are: - -.. code-block:: console - - #DEFVAR - NO2 = N + 2O; - CH3OOH = C + 4H + 2O; - HSO4m = IGNORE; - RCHO = IGNORE; - #DEFFIX - CO2 = C + 2O; - -.. _equations: - -#EQUATIONS ----------- - -The chemical mechanism is specified in the :command:`#EQUATIONS` -section. Each equation is written in the natural way in which a -chemist would write it: - -.. code-block:: console - - #EQUATIONS - - NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0); - O3P + O2 + AIR = O3 : ARR_ac(5.68e-34, -2.80); - O3P + O3 = 2O2 : ARR_ab(8.00e-12, 2060.0); - O3P + NO + AIR = NO2 : ARR_ac(1.00e-31, -1.60); - //... etc ... - -.. note:: - - The above example is taken from the :command:`saprc99` mechanism - (see :file:`models/saprc99.eqn`), with some whitespace deleted for - clarity. Optional :ref:`equation tags ` are specified - by text within :code:`< >` angle brackets. Functions that compute - **saprc99** equation rates (e.g. :code:`ARR_ac`, - :code:`ARR_ab`) are defined in :file:`util/UserRateLaws.f90` - and :file:`util/UserRateLawsInterfaces.f90`. - -Only the names of already defined species can be used. The rate -coefficient has to be placed at the end of each equation, separated by a -colon. The rate coefficient does not necessarily need to be a numerical -value. Instead, it can be a valid expression (or a call to an -:ref:`inlined rate law function `) in the :ref:`target -language `. If there are several :command:`#EQUATIONS` -sections in the input, their contents will be concatenated. - -A minus sign in an equation shows that a species is consumed in a -reaction but it does not affect the reaction rate. For example, the -oxidation of methane can be written as: - -.. code-block:: console - - CH4 + OH = CH3OO + H2O - O2 : k_CH4_OH; - -However, it should be noted that using negative products may lead to -numerical instabilities. - -Often, the stoichiometric factors are integers. However, it is also -possible to have non-integer yields, which is very useful to -parameterize organic reactions that branch into several side reactions: - -.. code-block:: console - - CH4 + O1D = .75 CH3O2 + .75 OH + .25 HCHO + 0.4 H + .05 H2 : k_CH4_O1D; - -KPP provides two pre-defined dummy species: :literal:`hv` and -:literal:`PROD`. Using dummy species does not affect the numerics of -the integrators. It only serves to improve the readability of the -equations. For photolysis reactions, :literal:`hv` can be specified as -one of the reagents to indicate that light (:math:`h\nu`) is needed for this -reaction, e.g.: - -.. code-block:: console - - NO2 + hv = NO + O : J_NO2; - -When the products of a reaction are not known or not important, the -dummy species :literal:`PROD` should be used as a product. This is -necessary because the KPP syntax does not allow an empty list of -products. For example, the dry deposition of atmospheric ozone to the -surface can be written as: - -.. code-block:: console - - O3 = PROD : v_d_O3; - -The same equation must not occur twice in the :command:`#EQUATIONS` -section. For example, you may have both the gas-phase reaction of -:literal:`N2O5` with water in your mechanism and also the -heterogeneous reaction on aerosols: - -.. code-block:: console - - N2O5 + H2O = 2 HNO3 : k_gas; - N2O5 + H2O = 2 HNO3 : k_aerosol; - -These reactions must be merged by adding the rate coefficients: - -.. code-block:: console - - N2O5 + H2O = 2 HNO3 : k_gas + k_aerosol; - -.. _families: - -#FAMILIES ---------- - -Chemical families (for diagnostic purposes) may be specified in the -:command:`#FAMILIES` section as shown below. Family names beginning -with a :code:`P` denote production, and those beginning with an -:code:`L` denote loss. - -.. code-block:: console - - #FAMILIES - POx : O3 + NO2 + 2NO3 + HNO3 + ... etc. add more species as needed ... - LOx : O3 + NO2 + 2NO3 + HNO3 + ... etc. add more species as needed ... - PCO : CO; - LCO : CO; - PSO4 : SO4; - LCH4 : CH4; - PH2O2 : H2O2; - -KPP will examine the chemical mechanism and create a dummy species for -each defined family. Each dummy species will archive the production -and loss for the family. For example, each molecule of CO that is -produced will be added to the :code:`PCO` dummy species. Likewise, -each molecule of CO that is consumed will be added to the :code:`LCO` -dummy species. This will allow the :code:`PCO` and :code:`LCO` species -to be later archived for diagnostic purposes. Dummy species for chemical -families will not be included as active species in the mechanism. - -.. _initvalues: - -#INITVALUES ------------ - -The initial concentration values for all species can be defined in the -:command:`#INITVALUES` section, e.g.: - -.. code-block:: console - - #INITVALUES - CFACTOR = 2.5E+19; - NO2 = 1.4E-9; - CO2 = MyCO2Func(); - ALL_SPEC = 0.0; - -If no value is specified for a particular species, the default value -zero is used. One can set the default values using the generic species -names: :code:`VAR_SPEC`, :code:`FIX_SPEC`, and :code:`ALL_SPEC`. In order -to use coherent units for concentration and rate coefficients, it is -sometimes necessary to multiply each value by a constant factor. This -factor can be set by using the generic name :code:`CFACTOR`. Each of -the initial values will be multiplied by this factor before being -used. If :code:`CFACTOR` is omitted, it defaults to one. - -The information gathered in this section is used to generate the -:code:`Initialize` subroutine (cf :ref:`Initialize`). In more complex 3D -models, the initial values are usually taken from some input files or -some global data structures. In this case, :command:`#INITVALUES` may -not be needed. - -.. note:: - - If you are building your mechanism in Fortran 90, note that using - floating point constants such as :literal:`2.5E+19` will only give - you a single precision value (which will incur roundoff error after - the 6th or 7th decimal place. - - If you are using double precision, you should use Fortran double - precision exponents (e.g. :literal:`2.5D+19`) instead. This will - give you a true double precision value. - -.. _lookat-and-monitor: - -#LOOKAT and #MONITOR --------------------- - -There are two sections in this category: :command:`#LOOKAT` and -:command:`#MONITOR`. - -The section instructs the preprocessor what are the species for which -the evolution of the concentration, should be saved in a data file. By -default, if no :command:`#LOOKAT` section is present, all the species -are saved. If an atom is specified in the :command:`#LOOKAT` list then -the total mass of the particular atom is reported. This allows to -check how the mass of a specific atom was conserved by the integration -method. The :command:`#LOOKATALL` command can be used to specify all -the species. Output of :command:`#LOOKAT` can be directed to the file -:file:`ROOT.dat` using the utility subroutines described in the -section entitled :ref:`Util`. - -The :command:`#MONITOR` section defines a different list of species -and atoms. This list is used by the driver to display the -concentration of the elements in the list during the integration. This -may give us a feedback of the evolution in time of the selected -species during the integration. The syntax is similar to the -:command:`#LOOKAT` section. With the driver :code:`general`, -output of :command:`#MONITOR` goes to the screen (STDOUT). The order -of the output is: first variable species, then fixed species, finally -atoms. It is not the order in the :command:`MONITOR` command. - -Examples for these sections are: - -.. code-block:: console - - #LOOKAT NO2; CO2; O3; N; - #MONITOR O3; N; - -.. _setvar-and-setfix: - -#SETVAR and #SETFIX -------------------- - -The commands :command:`#SETVAR` and :command:`#SETFIX` change the type of an -already defined species. Then, depending on the integration method, -one may or may not use the initial classification, or can easily move -one species from one category to another. The use of the generic -species :code:`VAR_SPEC`, :code:`FIX_SPEC`, and :code:`ALL_SPEC` is -also allowed. Examples for these sections are: - -.. code-block:: console - - #SETVAR ALL_SPEC; - #SETFIX H2O; CO2; - -.. _kpp-commands: - -============ -KPP commands -============ - -A KPP command begins on a new line with a :code:`#` sign, followed by a -command name and one or more parameters. Details about each command -are given in the following subsections. - -.. _table-cmd-defaults: - -.. list-table:: Default values for KPP commands - :align: center - :header-rows: 1 - - * - KPP command - - default value - - KPP command - - default value - * - :command:`#AUTOREDUCE` - - :code:`OFF` - - :command:`#CHECKALL` - - - * - :command:`#DECLARE` - - :code:`SYMBOL` - - :command:`#DOUBLE` - - :code:`ON` - * - :command:`#DRIVER` - - :code:`none` - - :command:`#DUMMYINDEX` - - :code:`OFF` - * - :command:`#EQNTAGS` - - :code:`OFF` - - :command:`#FUNCTION` - - :code:`AGGREGATE` - * - :command:`#GRAPH` - - :code:`OFF` - - :command:`#HESSIAN` - - :code:`ON` - * - :command:`#INCLUDE` - - - - :command:`#INTEGRATOR` - - - * - :command:`#INTFILE` - - - - :command:`#JACOBIAN` - - :code:`SPARSE_LU_ROW` - * - :command:`#LANGUAGE` - - - - :command:`#LOOKATALL` - - - * - :command:`#MEX` - - :code:`ON` - - :command:`#MINVERSION` - - - * - :command:`#MODEL` - - - - :command:`#REORDER` - - :code:`ON` - * - :command:`#STOCHASTIC` - - :code:`OFF` - - :command:`#STOICMAT` - - :code:`ON` - * - :command:`#UPPERCASEF90` - - :code:`OFF` - - - - - -.. _autoreduce-cmd: - -#AUTOREDUCE ------------ - -The :command:`#AUTOREDUCE ON` command can be used with -:command:`#INTEGRATOR rosenbrock` to enable -:ref:`automatic mechanism reduction ` as -described in :cite:t:`Lin_et_al._2022`. Automatic mechanism reduction -is disabled by default. - -.. _declare-cmd: - -#DECLARE --------- - -The :command:`#DECLARE` command determines how constants like -:code:`dp`, :code:`NSPEC`, :code:`NVAR`, :code:`NFIX`, and -:code:`NREACT` are inserted into the KPP-generated code. -:command:`#DECLARE SYMBOL` (the default) will declare array variables -using parameters from the :ref:`Parameters` file. :command:`#DECLARE VALUE` -will replace each parameter with its value. - -For example, the global array variable :code:`C` is declared in the -:ref:`Global` file generated by KPP. In the :program:`small_strato` -example (described in :ref:`running-kpp-with-an-example-mechanism`), -:code:`C` has dimension :code:`NSPEC=7`. Using :command:`#DECLARE -SYMBOL` will generate the following code in :ref:`Global`: - -.. code-block:: fortran - - ! C - Concentration of all species - REAL(kind=dp), TARGET :: C(NSPEC) - -Whereas :command:`#DECLARE VALUE` will generate this code instead: - -.. code-block:: fortran - - ! C - Concentration of all species - REAL(kind=dp), TARGET :: C(7) - -We recommend using :command:`#DECLARE SYMBOL`, as most modern compilers -will automatically replace each parameter (e.g. :code:`NSPEC`) with its -value (e.g :code:`7`). However, if you are using a very old compiler -that is not as sophisticated, :command:`#DECLARE VALUE` might result in -better-optmized code. - -.. _double-cmd: - -#DOUBLE -------- - -The :command:`#DOUBLE` command selects single or double precision -arithmetic. :command:`ON` (the default) means use double precision, -:command:`OFF` means use single precision (see the section entitled -:ref:`Precision`). - -.. important:: - - We recommend using double precision whenever possible. Using - single precision may lead to integration non-convergence errors - caused by roundoff and/or underflow. - -.. _driver-cmd: - -#DRIVER -------- - -The :command:`#DRIVER` command selects the driver, i.e., the file from -which the main function is to be taken. The parameter is a file name, -without suffix. The appropriate suffix (:code:`.f90`, :code:`.F90`, -:code:`.c`, or :code:`.m`) is automatically appended. - -Normally, KPP tries to find the selected driver file in the directory -:file:`$KPP_HOME/drv/`. However, if the supplied file name contains a slash, -it is assumed to be absolute. To access a driver in the current -directory, the prefix :file:`./` can be used, e.g.: - -.. code-block:: console - - #DRIVER ./mydriver - -It is possible to choose the empty dummy driver :command:`none`, if the -user wants to include the KPP generated modules into a larger model -(e.g. a general circulation or a chemical transport model) instead of -creating a stand-alone version of the chemical integrator. The driver -:command:`none` is also selected when the :command:`#DRIVER` command -is missing. If the command occurs twice, the second replaces the first. - -.. _dummyindex-cmd: - -#DUMMYINDEX ------------ - -It is possible to declare species in the :ref:`defvar-and-deffix` -sections that are not used in the :ref:`equations` section. If your -model needs to check at run-time if a certain species is included in -the current mechanism, you can set to :command:`#DUMMYINDEX ON`. Then, -KPP will set the indices to zero for all species that do not occur in -any reaction. With :command:`#DUMMYINDEX OFF` (the default), those are -undefined variables. For example, if you frequently switch between -mechanisms with and without sulfuric acid, you can use this code: - -.. code-block:: fortran - - IF (ind_H2SO4=0) THEN - PRINT *, 'no H2SO4 in current mechanism' - ELSE - PRINT *, 'c(H2SO4) =', C(ind_H2SO4) - ENDIF - -.. _eqntags-cmd: - -#EQNTAGS --------- - -Each reaction in the :ref:`equations` section may start with an -equation tag which is enclosed in angle brackets, e.g.: - -.. code-block:: console - - NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0); - -With :command:`#EQNTAGS` set to :command:`ON`, this equation tag can be -used to refer to a specific equation (cf. :ref:`monitor`). The default -for :command:`#EQNTAGS` is :command:`OFF`. - -.. _function-cmd: - -#FUNCTION ---------- - -The :command:`#FUNCTION` command controls which functions are generated -to compute the production/destruction terms for variable -species. :command:`AGGREGATE` generates one function that computes the -normal derivatives. :command:`SPLIT` generates two functions -for the derivatives in production and destruction forms. - -.. _graph-cmd: - -#GRAPH ------- - -Off by default, the :command:`#GRAPH` command leverages the -pre-existing parsing of stoichiometric structure to create -graph-based representations of the chemical mechanism. -:command:`#GRAPH` currently supports two options, described below. - -.. _graph-cmd-stoic: - -#GRAPH stoic -~~~~~~~~~~~~ - -This option generates two CSV files describing the structure of the -mechanism based on stoichiometric balances and species composition. - -1. :file:`ROOT_BiadjacencyMatrix.csv`: A sparse matrix of the - the net stoichiometric coefficients for each species in each - reaction. - - .. list-table:: Structure of :file:`ROOT_BiadjacencyMatrix.csv` - :header-rows: 1 - :widths: 10 30 60 - - * - Column - - Header - - Description - * - 1 - - spc_name - - Species name. - * - 2 - - species_index - - Number of the species in the chemical mechanism - * - 3 - - reaction_index - - Number of the reaction in the chemical mechanism - * - 4 - - stoichiometric_coefficient - - The the net, weighted biadjacency matrix of the bipartite - species-reaction graph, useful for automated detection of - system-wide stoichiometric invariants and other mass - conservation enforcing :cite:`Sturm_and_Wexler_2022`. - -2. :file:`ROOT_SpeciesCompositionMatrix.csv`: This is a species - composition dense matrix that for each variable species (row), - records the atom count of each element present (columns). - - .. list-table:: Structure of :file:`ROOT_SpeciesCompositionMatrix.csv` - :header-rows: 1 - :widths: 15 20 65 - - * - Column - - Name - - Description - * - 1 - - species_index - - Number of the species in the chemical mechanism - * - 2 - - species_name - - Species name. - * - 3 - NSPEC - - Species matrix - - One column for each atom present in the mechanism (including - IGNORE if used for some species). This matrix can be used - for automated mass balance checking of mechanism output or - individual reactions :cite:`Sturm_and_Silva_2025`. - -.. _graph-cmd-edgelist: - -#GRAPH edgelist -~~~~~~~~~~~~~~~ - -The :ref:`graph-cmd-stoic` option uses net stoichiometry, which -neglects reciprocal reactions (e.g. when the same species is a -reactant and a product its net stoichiometry is zero). This -:command:`#GRAPH edgelist` option generates a -:file:`ROOT_Edgelist.csv` file listing the edges of the -species-reaction bipartite graph. Each row represents a connection -between a species and a reaction, with direction and stoichiometric -value. - -.. list-table:: - :header-rows: 1 - :widths: 10 20 70 - - * - Column - - Name - - Description - * - 1 - - species_index - - Species index (starts from 1) - * - 2 - - reaction_index - - Reaction index (starts from 1) - * - 3 - - From - - Starting edge - * - 4 - - To - - Ending edge - * - 5 - - Stoichometric value - - Directed stoichiometric value - -.. _hessian-cmd: - -#HESSIAN --------- - -The option :command:`ON` (the default) of the :command:`#HESSIAN` -command turns the Hessian generation on (see section -:ref:`Hessian-and-HessianSP`). With :command:`OFF` it is switched off. - -.. _include-cmd: - -#INCLUDE --------- - -The :command:`#INCLUDE` command instructs KPP to look for the file -specified as a parameter and parse the content of this file before -proceeding to the next line. This allows the atoms definition, the -species definition and the equation definition to be shared between -several models. Moreover this allows for custom configuration of KPP to -accommodate various classes of users. Include files can be either in one -of the KPP directories or in the current directory. - -.. _integrator-cmd: - -#INTEGRATOR ------------ - -The :command:`#INTEGRATOR` command selects the integrator definition -file. The parameter is the file name of an integrator, without -suffix. The effect of - -.. code-block:: console - - #INTEGRATOR integrator_name - -is similar to: - -.. code-block:: console - - #INCLUDE $KPP_HOME/int/integrator_name.def - -The :command:`#INTEGRATOR` command allows the use of different -integration techniques on the same model. If it occurs twice, the second -replaces the first. Normally, KPP tries to find the selected integrator -files in the directory :file:`$KPP_HOME/int/`. However, if the supplied -file name contains a slash, it is assumed to be absolute. To access an -integrator in the current directory, the prefix :file:`./` can be used, -e.g.: - -.. code-block:: console - - #INTEGRATOR ./mydeffile - -.. _intfile-cmd: - -#INTFILE --------- - -.. attention:: - - :command:`#INTFILE` is used internally by KPP but should not be used - by the KPP user. Using :ref:`integrator-cmd` alone suffices to - specify an integrator. - -The integrator definition file selects an integrator file with -:command:`#INTFILE` and also defines some suitable options for it. The -:command:`#INTFILE` command selects the file that contains the integrator -routine. The parameter of the -command is a file name, without suffix. The appropriate suffix -(:code:`.f90`, :code:`.F90`, :code:`.c`, or :code:`.m` is appended and -the result selects the file from which the integrator -is taken. This file will be copied into the code file in the appropriate -place. - -.. _jacobian-cmd: - -#JACOBIAN ---------- - -The :command:`#JACOBIAN` command controls which functions are generated -to compute the Jacobian. The option :command:`OFF` inhibits the -generation of the Jacobian routine. The option :command:`FULL` generates -the Jacobian as a square :code:`NVAR x NVAR` matrix. It should only be -used if the integrator needs the whole Jacobians. The options -:command:`SPARSE_ROW` and :command:`SPARSE_LU_ROW` (the default) both -generate the Jacobian in sparse (compressed on rows) format. They should -be used if the integrator needs the whole Jacobian, but in a sparse -form. The format used is compressed on rows. With -:command:`SPARSE_LU_ROW`, KPP extends the number of nonzeros to account -for the fill-in due to the LU decomposition. - -.. _language-cmd: - -#LANGUAGE ---------- - -.. attention:: - - The :command:`Fortran77` language option is deprecated in - :ref:`kpp250` and later versions. All further KPP development will - only support Fortran90. - -The :command:`#LANGUAGE` command selects the target language in which the -code file is to be generated. Available options are :command:`Fortran90`, -:command:`C`, or :command:`matlab`. - -You can select the suffix (:code:`.F90` or :code:`.f90`) to use for -Fortran90 source code generated by KPP (cf. :ref:`uppercasef90-cmd`). - -.. _mex-cmd: - -#MEX ----- - -:program:`Mex` is a Matlab extension that allows -to call functions written in Fortran and C directly from within the -Matlab environment. KPP generates the mex interface routines for the -ODE function, Jacobian, and Hessian, for the target languages C, -Fortran77, and Fortran90. The default is :command:`#MEX ON`. With -:command:`#MEX OFF`, no Mex files are generated. - -.. _minversion-cmd: - -#MINVERSION ------------ - -You may restrict a chemical mechanism to use a given version of KPP or -later. To do this, add - -.. code-block:: console - - #MINVERSION X.Y.Z - -to the definition file. - -The version number (:code:`X.Y.Z`) adheres to the Semantic -Versioning style (https://semver.org), where :code:`X` is the major -version number, :code:`Y` is the minor version number, and :code:`Z` is the -bugfix (aka “patch”) version number. - -For example, if :command:`#MINVERSION 2.4.0` is specified, then KPP will -quit with an error message unless you are using KPP 2.4.0 or later. - -.. _model-cmd: - -#MODEL ------- - -The chemical model contains the description of the atoms, species, and -chemical equations. It also contains default initial values for the -species and default options including a suitable integrator for the -model. In the simplest case, the main kinetic description file, i.e. the -one passed as parameter to KPP, can contain just a single line selecting -the model. KPP tries to find a file with the name of the model and the -suffix :file:`.def` in the :file:`$KPP_HOME/models` subdirectory. This -file is then parsed. The content of the model definition file is written -in the KPP language. The model definition file points to a species file -and an equation file. The species file includes further the atom -definition file. All default values regarding the model are -automatically selected. For convenience, the best integrator and driver -for the given model are also automatically selected. - -The :command:`#MODEL` command is optional, and intended for using a -predefined model. Users who supply their own reaction mechanism do not -need it. - -.. _reorder-cmd: - -#REORDER --------- - -Reordering of the species is performed in order to minimize the fill-in -during the LU factorization, and therefore preserve the sparsity -structure and increase efficiency. The reordering is done using a -diagonal Markowitz algorithm. The details are explained in -:cite:t:`Sandu_et_al._1996`. The default is :command:`ON`. -:command:`OFF` means that KPP does not reorder the species. The order -of the variables is the order in which the species are -declared in the :command:`#DEFVAR` section. - -.. _stochastic-cmd: - -#STOCHASTIC ------------ - -The option :command:`ON` of the :command:`#STOCHASTIC` command turns -on the generation of code for stochastic kinetic simulations (see the -section entitled :ref:`Stochastic`. The default option is :command:`OFF`. - -.. _stoicmat-cmd: - -#STOICMAT ---------- - -Unless the :command:`#STOICMAT` command is set to :command:`OFF`, KPP -generates code for the stoichiometric matrix, the vector of reactant -products in each reaction, and the partial derivative of the time -derivative function with respect to rate coefficients -(cf. :ref:`Stoichiom-and-StoichiomSP`). - -.. _checkall-lookatall-cmd: - -#CHECKALL, #LOOKATALL ---------------------- - -The shorthand commands :command:`#CHECKALL` and :command:`#LOOKATALL` -apply :command:`#CHECK` and :command:`#LOOKAT`, respectively, to all -species in the mechanism. - -.. _uppercasef90-cmd: - -#UPPERCASEF90 -------------- - -If you have selected :command:`#LANGUAGE Fortran90` option, KPP will -generate source code ending in :code:`.f90` by default. Setting -:command:`#UPPERCASEF90 ON` will tell KPP to generate Fortran90 code -ending in :code:`.F90` instead. - -.. _inlined-code: - -============ -Inlined Code -============ - -In order to offer maximum flexibility, KPP allows the user to include -pieces of code in the kinetic description file. Inlined code begins on a -new line with :command:`#INLINE` and the *inline_type*. Next, one or -more lines of code follow, written in the target language (Fortran90, C, -or Matlab) as specified by the *inline_type*. The inlined code ends with -:command:`#ENDINLINE`. The code is inserted into the KPP output at a -position which is also determined by *inline_type* as shown in -:ref:`table-inl-type`. If two inline commands with the same inline type -are declared, then the contents of the second is appended to the first -one. - -.. _list-of-inlined-types: - -List of inlined types ---------------------- - -In this manual, we show the inline types for Fortran90. The inline -types for the other languages are produced by replacing :code:`F90` -by :code:`C`, or :code:`matlab`, respectively. - -.. _table-inl-type: - -.. list-table:: KPP inlined types - :align: center - :header-rows: 1 - - * - Inline_type - - File - - Placement - - Usage - * - **F90_DATA** - - :ref:`Monitor` - - specification section - - (obsolete) - * - **F90_GLOBAL** - - :ref:`Global` - - specification section - - global variables - * - **F90_INIT** - - :ref:`Initialize` - - subroutine - - integration parameters - * - **F90_RATES** - - :ref:`Rates` - - executable section - - rate law functions - * - **F90_RCONST** - - :ref:`Rates` - - subroutine - - rate coefficient definitions - * - **F90_RCONST_USE** - - :ref:`Rates` - - subroutine - - rate coefficient definitions - * - **F90_UTIL** - - :ref:`Util` - - executable section - - utility functions - -.. _f90-data: - -F90_DATA --------- - -This inline type was introduced in a previous version of KPP to -initialize variables. It is now obsolete but kept for compatibility. For -Fortran90, :command:`F90_GLOBAL` should be used instead. - -.. _f90-global: - -F90_GLOBAL ----------- - -This inline type can be used to declare global variables, e.g. for a -special rate coefficient: - -.. code-block:: fortran - - #INLINE F90_GLOBAL - REAL(dp) :: k_DMS_OH - #ENDINLINE - -Inlining code can be useful to introduce additional state variables -(such as temperature, humidity, etc.) for use by KPP routines, such as -for calculating rate coefficients. - -If a large number of state variables needs to be held in inline code, or -require intermediate computation that may be repeated for many rate -coefficients, a derived type object should be used for efficiency, e.g.: - -.. code-block:: fortran - - #INLINE F90_GLOBAL - TYPE, PUBLIC :: ObjGlobal_t - ! ... add variable fields to this type ... - END TYPE ObjGlobal_t - TYPE(ObjGlobal_t), TARGET, PUBLIC :: ObjGlobal - #ENDINLINE - -This global variable :code:`ObjGlobal` can then be used globally in KPP. - -Another way to avoid cluttering up the KPP input file is to -:code:`#include` a header file with global variables: - -.. code-block:: fortran - - #INLINE F90_GLOBAL - ! Inline common variables into KPP_ROOT_Global.f90 - #include "commonIncludeVars.f90" - #ENDINLINE - -In future versions of KPP, the global state will be reorganized into -derived type objects as well. - -.. _inline-type-f90-init: - -F90_INIT --------- - -This inline type can be used to define initial values before the start of the -integration, e.g.: - -.. code-block:: fortran - - #INLINE F90_INIT - TSTART = (12.*3600.) - TEND = TSTART + (3.*24.*3600.) - DT = 0.25*3600. - TEMP = 270. - #ENDINLINE - -.. _f90-rates: - -F90_RATES ---------- - -This inline type can be used to add new subroutines to calculate rate -coefficients, e.g.: - -.. code-block:: fortran - - #INLINE F90_RATES - REAL FUNCTION k_SIV_H2O2(k_298,tdep,cHp,temp) - ! special rate function for S(IV) + H2O2 - REAL, INTENT(IN) :: k_298, tdep, cHp, temp - k_SIV_H2O2 = k_298 & - * EXP(tdep*(1./temp-3.3540E-3)) & - * cHp / (cHp+0.1) - END FUNCTION k_SIV_H2O2 - #ENDINLINE - -.. _f90-rconst: - -F90_RCONST ----------- - -This inline type can be used to define time-dependent values of rate -coefficients. You may inline variables directly, e.g.: - -.. code-block:: fortran - - #INLINE F90_RCONST - k_DMS_OH = 1.E-9*EXP(5820./temp)*C(ind_O2)/ & - (1.E30+5.*EXP(6280./temp)*C(ind_O2)) - #ENDINLINE - -The inlined code will be placed directly into the subroutines -:code:`UPDATE_RCONST` and :code:`UPDATE_PHOTO` in the :ref:`Rates` file. - -.. _f90-rconst-use: - -F90_RCONST_USE --------------- - -Similar to :ref:`f90-rconst`, but allows you to inline Fortran-90 -:code:`USE` statements referencing modules where rate coefficients are -computed, such as: - -.. code-block:: fortran - - #INLINE F90_RCONST_USE - USE MyRateFunctionModule - #ENDINLINE - -The inlined code will be placed directly into the subroutines -:code:`UPDATE_RCONST` and :code:`UPDATE_PHOTO` in the :ref:`Rates` -file. :code:`USE` statements will be placed before Fortran variable -definitions and executable statements, as is required by the -Fortran-90 language standard. - -.. _f90-util: - -F90_UTIL --------- - -This inline type can be used to define utility subroutines. - -.. _auxiliary-files-and-the-substitution-preprocessor: - -================================================= -Auxiliary files and the substitution preprocessor -================================================= - -The `auxiliary files `_ in the -:file:`$KPP_HOME/util` subdirectory are templates for integrators, -drivers, and utilities. They are inserted into the KPP output after -being run through the substitution preprocessor. This preprocessor -replaces `several placeholder symbols `_ in -the template files with their particular values in the model at hand. -Usually, only :command:`KPP_ROOT` and :command:`KPP_REAL` are needed -because the other values can also be obtained via the variables listed -in :ref:`table-inl-type`. - -:command:`KPP_REAL` is replaced by the appropriate single or double -precision declaration type. Depending on the target language KPP will -select the correct declaration type. For example if one needs to -declare an array BIG of size 1000, a declaration like the following -must be used: - -.. code-block:: fortran - - KPP_REAL :: BIG(1000) - -When used with the command :command:`#DOUBLE ON`, the above line will be -automatically translated into: - -.. code-block:: fortran - - REAL(kind=dp) :: BIG(1000) - -and when used with the command :command:`#DOUBLE OFF`, the same line will -become: - -.. code-block:: fortran - - REAL(kind=sp) :: BIG(1000) - -in the resulting Fortran90 output file. - -:command:`KPP_ROOT` is replaced by the root file name of the main kinetic -description file. In our example where we are processing -:file:`small_strato.kpp`, a line in an auxiliary Fortran90 file like - -.. code-block:: fortran - - USE KPP_ROOT_Monitor - -will be translated into - -.. code-block:: fortran - - USE small_strato_Monitor - -in the generated Fortran90 output file. - -.. _auxiliary-files-for-fortran-90: - -List of auxiliary files for Fortran90 --------------------------------------- - -.. _table-aux-files: - -.. list-table:: Auxiliary files for Fortran90 - :align: center - :header-rows: 1 - - * - File - - Contents - * - :code:`dFun_dRcoeff.f90` - - Derivatives with respect to reaction rates - * - :code:`dJac_dRcoeff.f90` - - Derivatives with respect to reaction rates - * - :code:`Makefile_f90` and :code:`Makefile_upper_F90` - - Makefiles to build Fortran-90 code - * - :code:`Mex_Fun.f90` and :code:`Mex_Jac_SP.f90` - - Mex files. - * - :code:`Mex_Hessian.f90` - - Mex files. - * - :code:`sutil.f90` - - Sparse utility functions. - * - :code:`tag2num.f90` - - Function related to equation tags. - * - :code:`UpdateSun.f90` - - Function related to solar zenith angle. - * - :code:`UserRateLaws.f90` and :code:`UserRateLawsInterfaces.f90` - - User-defined rate-law functions. - * - :code:`util.f90` - - Input/output utilities. - -.. _list-of-symbols-replaced: - -List of symbols replaced by the substitution preprocessor ---------------------------------------------------------- - -.. _table-sym-repl: - -.. list-table:: Symbols and their replacements - :align: center - :header-rows: 1 - - * - Symbol - - Replacement - - Example - * - **KPP_ROOT** - - The :literal:`ROOT` name - - :literal:`small_strato` - * - **KPP_REAL** - - The real data type - - :code:`REAL(kind=dp)` - * - **KPP_NSPEC** - - Number of species - - 7 - * - **KPP_NVAR** - - Number of variable species - - 5 - * - **KPP_NFIX** - - Number of fixed species - - 2 - * - **KPP_NREACT** - - Number of chemical reactopms - - 10 - * - **KPP_NONZERO** - - Number of Jacobian nonzero elements - - 18 - * - **KPP_LU_NONZERO** - - Number of Jacobian nonzero elements, with LU fill0in - - 19 - * - **KPP_LU_NHESS** - - Number of Hessian nonzero elements - - 19 - * - **KPP_FUN_OR_FUN_SPLIT** - - Name of the function to be called - - ``FUN(Y,FIX,RCONST,Ydot)`` - -.. _icntrl-rcntrl: - -================================================================= -Controlling the Integrator with :code:`ICNTRL` and :code:`RCNTRL` -================================================================= - -In order to offer more control over the integrator, KPP provides the -arrays :code:`ICNTRL` (integer) and :code:`RCNTRL` (real). Each of them -is an array of 20 elements that allow the fine-tuning of the integrator. -All integrators (except for :code:`tau_leap` and :code:`gillespie`) use -:code:`ICNTRL` and :code:`RCNTRL`. Details can be found in the comment -lines of the individual integrator files in :code:`$KPP_HOME/int/`. - -ICNTRL ------- - -.. _table-icntrl: - -.. table:: Summary of ICNTRL usage in the f90 integrators. - Here, Y = used, and s = solver-specific usage. - :align: center - - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | ICNTRL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | - +========================+===+===+===+===+===+===+===+===+===+====+====+====+====+====+====+====+====+====+ - | beuler | | Y | Y | Y | Y | Y | s | | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | dvode | | | | | | | | | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | exponential | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | feuler | | | | | | | | | | | | | | | Y | Y | Y | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | gillespie | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | lsode | | Y | | Y | | | | | | s | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | radau5 | | Y | | Y | Y | Y | | | | | Y | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | rosenbrock_adj | Y | Y | Y | Y | | s | s | s | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | rosenbrock | Y | Y | Y | Y | | | | | | | | | | | Y | Y | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | rosenbrock_tlm | Y | Y | Y | Y | | | | | | | | s | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | rosenbrock_autoreduce | Y | Y | Y | Y | | | | | | | | s | s | s | Y | Y | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | rosenbrock_h211b_qssa | Y | Y | Y | Y | | | | | | | | | | | Y | Y | | s | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | runge_kutta_adj | | Y | Y | Y | Y | s | s | s | s | s | Y | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | runge_kutta | | Y | Y | Y | Y | Y | | | | s | Y | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | runge_kutta_tlm | | Y | Y | | Y | Y | s | | s | s | Y | s | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | sdirk4 | | Y | | Y | | | | | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | sdirk_adj | | Y | Y | Y | Y | Y | s | s | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | sdirk | | Y | Y | Y | Y | Y | | | | | | | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | sdirk_tlm | | Y | Y | Y | Y | Y | s | | s | | | s | | | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | seulex | Y | Y | | Y | | | | | | s | s | s | s | s | Y | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - | tau_leap | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+ - -ICNTRL(1) -~~~~~~~~~ - -Specifies the time-dependence of the function :math:`F` to be integrated: - -.. table:: - :align: left - - +------------+----------------------------------------+ - | ICNTRL(1) | Time dependence of :math:`F` | - +============+========================================+ - | 0 | :math:`F = F(t,y)` aka non-autonomous | - +------------+----------------------------------------+ - | 1 | :math:`F = F(y)` aka autonomous | - +------------+----------------------------------------+ - -ICNTRL(2) -~~~~~~~~~ - -Specifies the dimensionality of the absolute (:code:`ATOL`) and -relative (:code:`RTOL`) tolerances. These can be expressed by -either a scalar or individually for each species in a vector. - -.. table:: - :align: left - - +------------+-------------------------------------------+ - | ICNTRL(2) | Dimensionality of ``ATOL`` and ``RTOL`` | - +============+===========================================+ - | 0 | :code:`NVAR` -dimensional vector | - +------------+-------------------------------------------+ - | 1 | scalar | - +------------+-------------------------------------------+ - -ICNTRL(3) -~~~~~~~~~ - -Selects a specific integration method. - -.. table:: - :align: left - - +-----------------------+------------+-----------------------+ - | Integrator | ICNTRL(3) | Method selected | - +=======================+============+=======================+ - | rosenbrock | 0 or 4 | Rodas3 (default) | - | +------------+-----------------------+ - | rosenbrock_adj | 1 | Ros2 | - | +------------+-----------------------+ - | rosenbrock_autoreduce | 2 | Ros3 | - | +------------+-----------------------+ - | rosenbrock_tlm | 3 | Ros4 | - | +------------+-----------------------+ - | | 5 | Rodas4 | - | +------------+-----------------------+ - | | 6 | Rang | - | +------------+-----------------------+ - | | 7 | Rodas3.1 | - +-----------------------+------------+-----------------------+ - | runge_kutta | 0 or 1 | Radau-2A (default) | - | +------------+-----------------------+ - | runge_kutta_adj | 2 | Lobatto-3C | - | +------------+-----------------------+ - | runge_kutta_tlm | 3 | Gauss | - | +------------+-----------------------+ - | | 4 | Radau-1A | - | +------------+-----------------------+ - | | 5 | Lobatto-3A | - +-----------------------+------------+-----------------------+ - | sdirk | 0 or 1 | Sdirk-2A (default) | - | +------------+-----------------------+ - | sdirk_adj | 2 | Sdirk-2B | - | +------------+-----------------------+ - | sdirk_tlm | 3 | Sdirk-3A | - | +------------+-----------------------+ - | | 4 | Sdirk-4A | - | +------------+-----------------------+ - | | 5 | Sdirk-4B | - | +------------+-----------------------+ - | | 6 | Backward Euler | - +-----------------------+------------+-----------------------+ - - -ICNTRL(4) -~~~~~~~~~ - -Specifies the maximum number of integration steps. - -ICNTRL(5) -~~~~~~~~~ - -Specifies the maximum number of Newton iterations. - -ICNTRL(6) -~~~~~~~~~ - -Selects integrator-specific settings. - -.. table:: - :align: left - - +-----------------+------------+-----------------------------------+ - | Integrator | ICNTRL(6) | Option selected | - +=================+============+===================================+ - | rosenbrock_adj | 0 thru 6 | Selection of a particular | - | | | Rosenbrock method for the | - | | | continuous adjoint integration | - | | | (see ``ICNTRL(3)``) | - +-----------------+------------+-----------------------------------+ - | radau5 | 0 | Starting values for Newton | - | | | iterations are interpolated | - | | | (default) | - | runge_kutta_adj +------------+-----------------------------------+ - | | 1 | Starting values for Newton | - | runge_kutta_tlm | | iterations are zero | - | | | | - | sdirk | | | - | | | | - | sdirk_adj | | | - | | | | - | sdirk_tlm | | | - +-----------------+------------+-----------------------------------+ - -ICNTRL(7) -~~~~~~~~~ - -Selects options for adjoint integrators. - -.. table:: Selection of adjoint algorithm - :align: left - - +-----------------+------------+----------------------------------+ - | Integrator | ICNTRL(7) | Adjoint algorithm selected | - +=================+============+==================================+ - | rosenbrock_adj | 0 or 2 | Discrete adjoint with method | - | | | ``ICNTRL(3)`` (default) | - | +------------+----------------------------------+ - | | 1 | No adjoint | - | +------------+----------------------------------+ - | | 3 | Fully adaptive continous adjoint | - | | | with method ``ICNTRL(6)`` | - | +------------+----------------------------------+ - | | 4 | Simplified continuous adjoint | - | | | with method ``ICNTRL(6)`` | - +-----------------+------------+----------------------------------+ - -.. table:: Method to solve the linear Adj equations - :align: left - - +-----------------+------------+----------------------------------+ - | Integrator | ICNTRL(7) | Method selected | - +=================+============+==================================+ - | runge_kutta_adj | 0 or 1 | Modified Newton re-using LU | - | | | (default) | - | +------------+----------------------------------+ - | | 2 | Direct solution (additional one | - | | | LU factorizsation of 3Nx3N | - | | | matrix per step; good for | - | | | debugging | - | +------------+----------------------------------+ - | | 3 | Adaptive solution (if Newton | - | | | does not converge, switch to | - | | | direct) | - +-----------------+------------+----------------------------------+ - | sdirk_adj | 0 | Modified Newton re-using LU | - | | | (default) | - | sdirk_tlm +------------+----------------------------------+ - | | 1 | Direct solution (additional one | - | | | LU factorizsation per stage) | - +-----------------+------------+----------------------------------+ - -ICNTRL(8) -~~~~~~~~~ - -Determines if LU factorization will be checkpointed at each step -(for adjoint integrators only). - -.. table:: - :align: left - - +-----------------+------------+------------------------------------+ - | Integrator | ICNTRL(8) | Option selected | - +=================+============+====================================+ - | rosenbrock_adj | 0 | Do not save LU factorization at | - | | | each step (default) | - | runge_kutta_adj +------------+------------------------------------+ - | | 1 | Save LU factorization at each step | - | sdirk_adj | | | - +-----------------+------------+------------------------------------+ - -ICNTRL(9) -~~~~~~~~~ - -Selects options for adjoint and tangent linear method (TLM) -integrators. - -.. table:: Selection of adjoint algorithm - :align: left - - +-----------------+------------+----------------------------------+ - | Integrator | ICNTRL(9) | Adjoint algorithm selected | - +=================+============+==================================+ - | runge_kutta_adj | 0 or 2 | Discrete adjoint with method | - | | | ``ICNTRL(3)`` (default) | - | +------------+----------------------------------+ - | | 1 | No adjoint | - | +------------+----------------------------------+ - | | 3 | Fully adaptive continous adjoint | - | | | with method ``ICNTRL(6)`` | - | +------------+----------------------------------+ - | | 4 | Simplified continuous adjoint | - | | | with method ``ICNTRL(6)`` | - +-----------------+------------+----------------------------------+ - -.. table:: Selection of tangent linear method (TLM) error - estimation strategy - :align: left - - +-----------------+------------+-----------------------------------+ - | Integrator | ICNTRL(9) | Strategy selected | - +=================+============+===================================+ - | runge_kutta_tlm | 0 | Base number of iterations as | - | | | forward solution | - | sdirk_tlm +------------+-----------------------------------+ - | | 1 | USE ``ATOL_tlm`` and ``RTOL_tlm`` | - | | | to calculate error estimation | - | | | for TLM at Newton stages | - +-----------------+------------+-----------------------------------+ - -ICNTRL(10) -~~~~~~~~~~ - -Selects integrator-specific options. - -.. table:: - :align: left - - +-----------------+------------+-----------------------------------+ - | Integrator | ICNTRL(10) | Option selected | - +=================+============+===================================+ - | lsode | user | Maximum order of the integration | - | | supplied | formula allowed | - +-----------------+------------+-----------------------------------+ - | runge_kutta | 0 | Error estimation strategy: | - | | | one additional stage at ``c=0`` | - | runge_kutta_adj | | (default) | - | +------------+-----------------------------------+ - | runge_kutta_tlm | 1 | Error estimation strategy: | - | | | Two additional stages at ``c=0`` | - | | | and SDIRK at ``c=1``, stiffly | - | | | accurate | - | +------------+-----------------------------------+ - | | | | - +-----------------+------------+-----------------------------------+ - | seulex | 0 | No verbose output | - | +------------+-----------------------------------+ - | | 1 | Dense verbose output | - +-----------------+------------+-----------------------------------+ - -ICNTRL(11) -~~~~~~~~~~ - -Selects integrator-specific settings. - -.. table:: - :align: left - - +-----------------+------------+-----------------------------------+ - | Integrator | ICNTRL(11) | Option selected | - +=================+============+===================================+ - | seulex | user | Maximum number of columns in the | - | | supplied | extrapolation. Default is 12. | - +-----------------+------------+-----------------------------------+ - | radau5 | 0 | Gustaffson step size control | - | +------------+-----------------------------------+ - | | 1 | Classical step size control | - | runge_kutta | | | - | | | | - | runge_kutta_adj | | | - | | | | - | runge_kutta_tlm | | | - | | | | - | | | | - +-----------------+------------+-----------------------------------+ - -ICNTRL(12) -~~~~~~~~~~ - -Selects integrator-specific settings. - -.. table:: - :align: left - - +-----------------------+------------+-----------------------------------+ - | Integrator | ICNTRL(12) | Option selected | - +=======================+============+===================================+ - | rosenbrock_autoreduce | 0 | Disable mechanism auto-reduction | - | | | (i.e. acts in the same way as the | - | | | ``rosenbrock`` integrator) | - | +------------+-----------------------------------+ - | | 1 | Enables mechanism auto-reduction, | - | | | set threshold in ``RCNTRL(`12)`` | - | +------------+-----------------------------------+ - | | | | - +-----------------------+------------+-----------------------------------+ - | rosenbrock_tlm | 0 | TLM truncation error is not used | - | +------------+-----------------------------------+ - | runge_kutta_tlm | 1 | TLM truncation error is computed | - | | | and used | - | sdirk_tlm | | | - | +------------+-----------------------------------+ - | | | | - +-----------------------+------------+-----------------------------------+ - | seulex | 0 | Nsequence = 2 (default) | - | +------------+-----------------------------------+ - | | 1 | Nsequence = | - | | | 1,2,3,4,6,8,12,16,24,32,48,... | - | +------------+-----------------------------------+ - | | 2 | Nsequence = | - | | | 2,3,4,6,8,12,16,24,32,48,64,... | - | +------------+-----------------------------------+ - | | 3 | Nsequence = | - | | | 1,2,3,4,5,6,7,8,9,10,... | - | +------------+-----------------------------------+ - | | 4 | Nsequence = | - | | | 2,3,4,5,6,7,8,9,10,11,... | - +-----------------------+------------+-----------------------------------+ - -ICNTRL(13) -~~~~~~~~~~ - -Selects integrator-specific settings. - -.. table:: - :align: left - - +-----------------------+------------+-----------------------------------+ - | Integrator | ICNTRL(13) | Option selected | - +=======================+============+===================================+ - | rosenbrock_autoreduce | 0 | In auto-reduction, disables | - | | | scanning species P and L rates | - | | | throughout the internal timesteps | - | | | of the integrator. | - | +------------+-----------------------------------+ - | | 1 | In auto-reduction, ensables | - | | | scanning species P and L rates | - | | | throughout the internal timesteps | - | | | of the integrator, for | - | | | repartitioning. | - +-----------------------+------------+-----------------------------------+ - | seulex | 0, 1 | Sets the ``lambda`` parameter | - | | | for verbose output. | - +-----------------------+------------+-----------------------------------+ - -ICNTRL(14) -~~~~~~~~~~ - -(Solver-specific for :code:`rosenbrock_autoreduce`) If set to -:code:`> 0`, then the threshold is calculated based on the max of -production and loss rate of the species ID specified in -:code:`ICNTRL(14)` multiplied by :code:`RCNTRL(14)`. - -ICNTRL(15) -~~~~~~~~~~ - -Determines which :code:`Update_*` subroutines are called within the -integrator. - -.. list-table:: - :align: left - :header-rows: 1 - - * - ICNTRL(15) - - Option selcted - * - -1 - - Do not call any :code:`Update_*` subroutines - * - 0 - - Use the integrator-specific default values - * - 1 - - Call :code:`Update_RCONST` from within the integrator. - * - 2 - - Call :code:`Update_PHOTO` from within the integrator - * - 3 - - Call :code:`Update_RCONST` and :code:`Update_PHOTO` from within - the integrator. - * - 4 - - Call :code:`Update_SUN` from within the integrator - * - 5 - - Call :code:`Update_SUN` and :code:`Update_RCONST` from within - the integrator - * - 6 - - Call :code:`Update_SUN` and :code:`Update_PHOTO` from within - the integrator. - * - 7 - - Call :code:`Update_SUN`, :code:`Update_PHOTO`, and - :code:`Update_RCONST` from within the integrator. - -Calling :code:`Update_RCONST` may be necessary when reaction rate -coefficients depend on the concentration of a specific species, e. -g.: - -.. code-block:: console - - HSO3m + HSO5m + Hp = 2 HSO4m + Hp : k_aqueous( C(ind_Hp) ); - -This ensures that the concentration :code:`C(ind_Hp)` at the specific -integration time is used when the reaction rate coefficient is -updated within the integrator. - -ICNTRL(16) -~~~~~~~~~~ - -Specifies how negative values should be handled. - -.. list-table:: - :align: left - :header-rows: 1 - - * - ICNTRL(16) - - Option selcted - * - 0 - - Leave negative values unchanged - * - 1 - - Set negative values to zero - * - 2 - - Print warning and continue - * - 3 - - Print error message and stop - -ICNTRL(17) -~~~~~~~~~~ - -Selects the amount of verbose output that will be generated. - -.. list-table:: - :align: left - :header-rows: 1 - - * - ICNTRL(17) - - Option selcted - * - 0 - - Only return error number - * - 1 - - Full verbose error output - -ICNTRL(18) -~~~~~~~~~~ - -Currently not used. - -ICNTRL(19) -~~~~~~~~~~ - -Currently not used. - -ICNTRL(20) -~~~~~~~~~~ - -Currently not used. - -RCNTRL ------- - -.. _table-rcntrl: - -.. table:: Summary of RCNTRL usage in the f90 integrators. - Here, Y = used, and s = solver-specific usage. - :align: center - - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | RCNTRL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | - +========================+===+===+===+===+===+===+===+===+===+====+====+====+====+====+====+====+====+====+====+ - | beuler | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | dvode | | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | exponential | | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | feuler | | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | gillespie | | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | lsode | Y | Y | Y | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | radau5 | | Y | | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | rosenbrock_adj | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | rosenbrock | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | rosenbrock_tlm | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | rosenbrock_autoreduce | Y | Y | Y | Y | Y | Y | Y | | | | | s | | s | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | rosenbrock_h211b_qssa | Y | Y | Y | Y | Y | Y | Y | | | | | | | | s | s | s | s | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | runge_kutta_adj | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | runge_kutta | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | runge_kutta_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | sdirk4 | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | sdirk_adj | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | sdirk | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | sdirk_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | seulex | Y | Y | Y | Y | Y | Y | Y | Y | | s | s | s | s | s | s | s | s | s | s | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - | tau_leap | | | | | | | | | | | | | | | | | | | | - +------------------------+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----+----+----+----+ - -RCNTRL(1) -~~~~~~~~~ - -:code:`Hmin`, the lower bound of the integration step size. It is -not recommended to change the default value of zero. - -RCNTRL(2) -~~~~~~~~~ - -:code:`Hmax`, the upper bound of the integration step size. - -RCNTRL(3) -~~~~~~~~~ - -:code:`Hstart`, the starting value of the integration step size. - -RCNTRL(4) -~~~~~~~~~ - -:code:`FacMin`, lower bound on step decrease factor. - -RCNTRL(5) -~~~~~~~~~ - -:code:`FacMax`, upper bound on step increase factor. - -RCNTRL(6) -~~~~~~~~~ - -:code:`FacRej`, step decrease factor after multiple rejections. - -RCNTRL(7) -~~~~~~~~~ - -:code:`FacSafe`, the factor by which the new step is slightly - smaller than the predicted value. - -RCNTRL(8) -~~~~~~~~~ - -:code:`ThetaMin`. If the Newton convergence rate is smaller than -ThetaMin, the Jacobian is not recomputed. - -RCNTRL(9) -~~~~~~~~~ - -:code:`NewtonTol`, the stopping criterion for Newton’s method. - -RCNTRL(10) -~~~~~~~~~~ - -:code:`Qmin` - -Different, solver-specific settings for :code:`seulex`. - -RCNTRL(11) -~~~~~~~~~~ - -:code:`Qmax`. If :code:`Qmin < Hnew/Hold < Qmax`, then the step -size is kept constant and the LU factorization is reused. - -Different, solver-specific settings for :code:`seulex`. - -RCNTRL(12) -~~~~~~~~~~ - -(Solver-specific for :code:`rosenbrock_autoreduce`) Used to specify -the threshold for auto-reduction partitioning, if :code:`ICNTRL(12) = 1`, -and :code:`ICNTRL(14) = 0`. Will be ignored if :code:`ICNTRL(14) > 0`. - -Different, solver-specific settings for :code:`seulex`. - -RCNTRL(13) -~~~~~~~~~~~~~~~~~~~~~~~ - -Solver-specific settings for :code:`seulex`. - -RCNTRL(14) -~~~~~~~~~~ - -(Solver-specific for :code:`rosenbrock_autoreduce`) Used to specify -the multiplier for threshold for auto-reduction partitioning, if -:code:`ICNTRL(12) = 1`, and :code:`ICNTRL(14) > 0`, :code:`RCNTRL(14)` -is multiplied against max of production and loss rates of species -:code:`ICNTRL(14)` to produce the partitioning threshold, ignoring -:code:`RCNTRL(12)`. - -Different, solver-specific settings for :code:`seulex`. - -RCNTRL(15) - RCNTRL(18) -~~~~~~~~~~~~~~~~~~~~~~~ - -Solver-specific settings for :code:`rosenbrock_h211b_qssa`. - -Different, solver-specific settings for :code:`seulex`. - -RCNTRL(19) -~~~~~~~~~~~~~~~~~~~~~~~ - -Solver-specific settings for :code:`seulex`. - -RCNTRL(20) -~~~~~~~~~~ - -Currently not used. diff --git a/docs/source/using_kpp/05_output_from_kpp.rst b/docs/source/using_kpp/05_output_from_kpp.rst deleted file mode 100644 index b364dac..0000000 --- a/docs/source/using_kpp/05_output_from_kpp.rst +++ /dev/null @@ -1,1306 +0,0 @@ -.. _output-from-kpp: - -############### -Output from KPP -############### - -This chapter describes the source code files that are generated by -KPP. - -.. _f90-code: - -================== -The Fortran90 code -================== - -The code generated by KPP is organized in a set of separate files. Each -has a complete description of how it was generated at the begining of -the file. The files associated with root are named with a -corresponding prefix :code:`ROOT_` A short description of each file -is contained in the following sections. - -.. figure:: ../_static/kpp2_use_diagr.png - :align: center - :alt: Figure 1: Interdependencies of the KPP-generated files - - Figure 1: Interdependencies of the KPP-generated files. Each arrow - starts at the module that exports a variable or subroutine and - points to the module that imports it via the Fortran90 :code:`USE` - instruction. The prefix :code:`ROOT_` has been omitted from module - names for better readability. Dotted boxes show optional files that - are only produced under certain circumstances. - -All subroutines and functions, global parameters, variables, and -sparsity data structures are encapsulated in modules. There is exactly -one module in each file, and the name of the module is identical to the -file name but without the suffix :code:`.f90` or :code:`.F90`. `Figure 1 -(above) `_ shows how these modules are related to -each other. The generated code is consistent with the Fortran90 -standard. It may, however, exceed the official maximum number of 39 -continuation lines. - -.. tip:: - - The default Fortran90 file suffix is :code:`.f90`. To have KPP - generate Fortran90 code ending in :file:`.F90` instead, add the - command :command:`#UPPERCASEF90 ON` to the KPP definition file. - -.. _Main: - -ROOT_Main ---------- - -:file:`ROOT_Main.f90` (or :file:`.F90`) root is the main -Fortran90 program. It contains the driver after modifications by the -substitution preprocessor. The name of the file is computed by KPP by -appending the suffix to the root name. - -Using :command:`#DRIVER none` will skip generating this file. - -.. _Model: - -ROOT_Model ----------- - -The file :file:`ROOT_Model.f90` (or :file:`.F90`) unifies all model -definitions in a single module. This simplifies inclusion into -external Fortran programs. - -.. _Initialize: - -ROOT_Initialize ---------------- - -The file :file:`ROOT_Initialize.f90` (or :file:`.F9O`) -contains the subroutine :code:`Initialize`, which defines initial -values of the chemical species. The driver calls the subroutine once -before the time integration loop starts. - -.. _Integrator: - -ROOT_Integrator ---------------- - -The file :file:`ROOT_Integrator.f90` (or :file:`.F90`) -contains the subroutine :code:`Integrate`, which is called every time -step during the integration. The integrator that was chosen with the -:ref:`integrator-cmd` command is also included in this file. In case -of an unsuccessful integration, the module root provides a short error -message in the public variable :code:`IERR_NAME`. - -.. _Monitor: - -ROOT_Monitor ------------- - -The file :file:`ROOT_Monitor.f90` (:file:`.F90`) contains -arrays with information about the chemical mechanism. The names of all -species are included in :code:`SPC_NAMES` and the names of all -equations are included in :code:`EQN_NAMES`. - -It was shown (cf. :ref:`eqntags-cmd`) that each reaction -in the section may start with an equation tag which is enclosed in -angle brackets, e.g.: - -.. code-block:: console - - NO2 + hv = NO + O3P : 6.69e-1*(SUN/60.0e0); - -If the equation tags are switched on, KPP also generates the -:code:`PARAMETER` array :code:`EQN_TAGS`. In combination with -:code:`EQN_NAMES` and the function :code:`tag2num` that converts the -equation tag to the KPP-internal tag number, this can be used to -describe a reaction: - -.. code-block:: none - - PRINT*, ’Reaction 1 is:’, EQN_NAMES( tag2num( ’R1’ ) ) - -.. _Precision: - -ROOT_Precision --------------- - -Fortran90 code uses parameterized real -types. :file:`ROOT_Precision.f90` (or :file:`.F90`) contains the -following real kind definitions: - -.. code-block:: fortran - - ! KPP_SP - Single precision kind - INTEGER, PARAMETER :: & - SP = SELECTED_REAL_KIND(6,30) - ! KPP_DP - Double precision kind - INTEGER, PARAMETER :: & - DP = SELECTED_REAL_KIND(12,300) - -Depending on the choice of the :ref:`double-cmd` command, the real -variables are of type double (:code:`REAL(kind=dp)`) or single -precision (:code:`REAL(kind=sp)`). Changing the parameters of the -:code:`SELECTED_REAL_KIND` function in this module will cause a change -in the working precision for the whole model. - -.. _Rates: - -ROOT_Rates ----------- - -The code to update the rate constants is in :file:`ROOT_Rates.f90` (or -:file:`.F90`). The user defined rate law functions (cf. -:ref:`table-rat-fun`) are also placed here. - -.. _table-rat-fun: - -.. table:: Fortran90 subrotutines in ROOT_Rates - :align: center - - +-----------------------+--------------------------------------+ - | Function | Description | - +=======================+======================================+ - | :code:`Update_PHOTO` | Update photolysis rate coefficients | - +-----------------------+--------------------------------------+ - | :code:`Update_RCONST` | Update all rate coefficients | - +-----------------------+--------------------------------------+ - | :code:`Update_SUN` | Update sun intensity | - +-----------------------+--------------------------------------+ - -.. _Parameters: - -ROOT_Parameters ---------------- - -Global parameters are defined and initialized in -:file:`ROOT_Parameters.f90` (or :file:`.F90`): - -.. _table-par: - -.. table:: Parameters Declared in ROOT_Parameters - :align: center - - +----------------+---------------------------------------------+---------+ - | Parameter | Represents | Example | - +================+=============================================+=========+ - | ``NSPEC`` | No. chemical species (``NVAR`` + ``NFIX``) | 7 | - +----------------+---------------------------------------------+---------+ - | ``NVAR`` | No. variable species | 5 | - +----------------+---------------------------------------------+---------+ - | ``NFIX`` | No. fixed species | 2 | - +----------------+---------------------------------------------+---------+ - | ``NREACT`` | No. reactions | 10 | - +----------------+---------------------------------------------+---------+ - | ``NONZERO`` | No. nonzero entries Jacobian | 18 | - +----------------+---------------------------------------------+---------+ - | ``LU_NONZERO`` | As above, after LU factorization | 19 | - +----------------+---------------------------------------------+---------+ - | ``NHESS`` | Length, sparse Hessian | 10 | - +----------------+---------------------------------------------+---------+ - | ``NJVRP`` | Length, sparse Jacobian JVRP | 13 | - +----------------+---------------------------------------------+---------+ - | ``NSTOICM`` | Length, stoichiometric matrix | 22 | - +----------------+---------------------------------------------+---------+ - | ``ind_spc`` | Index of species *spc* in :code:`C` | | - +----------------+---------------------------------------------+---------+ - | ``indf_spc`` | Index of fixed species *spc* in :code:`FIX` | | - +----------------+---------------------------------------------+---------+ - -Example values listed in the 3rd column are taken from the -:program:`small_strato` mechanism (cf. -:ref:`running-kpp-with-an-example-mechanism`). - -KPP orders the variable species such that the sparsity pattern of the -Jacobian is maintained after an LU decomposition. For our example there -are five variable species (:code:`NVAR = 5`) ordered as - -.. code-block:: fortran - - ind_O1D=1, ind_O=2, ind_O3=3, ind_NO=4, ind_NO2=5 - -and two fixed species (:code:`NFIX = 2`) - -.. code-block:: fortran - - ind_M = 6, ind_O2 = 7. - -KPP defines a complete set of simulation parameters, including the -numbers of variable and fixed species, the number of chemical reactions, -the number of nonzero entries in the sparse Jacobian and in the sparse -Hessian, etc. - -.. _Global: - -ROOT_Global ------------ - -Several global variables are declared in :file:`ROOT_Global.f90` (or -:file:`.F90`): - -.. _table-glob: - -.. table:: Global Variables Declared in ROOT_Global - :align: center - - +-------------------------+---------------------------------------------+ - | Global variable | Represents | - +=========================+=============================================+ - | :code:`C(NSPEC)` | Concentrations, all species | - +-------------------------+---------------------------------------------+ - | :code:`VAR(:)` | Concentrations, variable species (pointer) | - +-------------------------+---------------------------------------------+ - | :code:`FIX(:)` | Concentrations, fixed species (pointer) | - +-------------------------+---------------------------------------------+ - | :code:`RCONST(NREACT)` | Rate coefficient values | - +-------------------------+---------------------------------------------+ - | :code:`TIME` | Current integration time | - +-------------------------+---------------------------------------------+ - | :code:`SUN` | Sun intensity between 0 and 1 | - +-------------------------+---------------------------------------------+ - | :code:`TEMP` | Temperature | - +-------------------------+---------------------------------------------+ - | :code:`TSTART, TEND` | Simulation start/end time | - +-------------------------+---------------------------------------------+ - | :code:`DT` | Simulation time step | - +-------------------------+---------------------------------------------+ - | :code:`ATOL(NSPEC)` | Absolute tolerances | - +-------------------------+---------------------------------------------+ - | :code:`RTOL(NSPEC)` | Relative tolerances | - +-------------------------+---------------------------------------------+ - | :code:`STEPMIN` | Lower bound for time step | - +-------------------------+---------------------------------------------+ - | :code:`STEPMAX` | Upper bound for time step | - +-------------------------+---------------------------------------------+ - | :code:`CFACTOR` | Conversion factor | - +-------------------------+---------------------------------------------+ - -Both variable and fixed species are stored in the one-dimensional -array :code:`C`. The first part (indices from :code:`1` to :code:`NVAR`) -contains the variable species, and the second part (indices from to -:code:`NVAR+1` to :code:`NSPEC`) the fixed species. The total number -of species is the sum of the :code:`NVAR` and :code:`NFIX`. The parts -can also be accessed separately through pointer variables :code:`VAR` and -:code:`FIX`, which point to the proper elements in :code:`C`. - -.. code-block:: fortran - - VAR(1:NVAR) => C(1:NVAR) - FIX(1:NFIX) => C(NVAR+1:NSPEC) - -.. important:: - - In previous versions of KPP, Fortran90 code was generated with - :code:`VAR` and :code:`FIX` being linked to the :code:`C` array - with an :code:`EQUIVALENCE` statement. This construction, however, - is not thread-safe, and it prevents KPP-generated Fortran90 code - from being used within parallel environments (e.g. such as an - `OpenMP `_ parallel loop). - - We have modified :ref:`kpp250` and later versions to make KPP-generated - Fortran90 code thread-safe. :code:`VAR` and - :code:`FIX` are now :code:`POINTER` variables that - point to the proper slices of the :code:`C` array. They are also - nullified when no longer needed. :code:`VAR` and :code:`FIX` are - now also kept internal to the various integrator files located in - the :file:`$KPP_HOME/int` directory. - -.. _Function: - -ROOT_Function -------------- - -The chemical ODE system for our :program:`small_strato` example -(described in :ref:`running-kpp-with-an-example-mechanism`) is: - -.. math:: - - \begin{aligned} - \frac{d[O(^1D)]}{dt} & = & k_{5}\, [O_3] - k_{6}\, [O(^1D)]\, [M] - k_{7}\, [O(^1D)]\, [O_3]\\ - \frac{d[O]}{dt} & = & 2\, k_{1}\, [O_2] - k_{2}\, [O]\, [O_2] + k_{3}\, [O_3]\\ - & & - k_{4}\, [O]\, [O_3]+ k_{6}\, [O(^1D)]\, [M]\\ - & & - k_{9}\, [O]\, [NO_2] + k_{10}\, [NO_2]\\ - \frac{d[O_3]}{dt} & = & k_{2}\, [O]\, [O_2] - k_{3}\, - [O_3] - k_{4}\, [O]\, [O_3] - k_{5}\, [O_3]\\ - & & - k_{7}\, [O(^1D)]\, [O_3] - k_{8}\, [O_3]\, [NO]\\ - \frac{d[NO]}{dt} & = & - k_{8}\, [O_3]\, [NO] + k_{9}\, [O]\, [NO_2] + k_{10}\, [NO_2]\\ - \frac{d[NO_2]}{dt} & = & k_{8}\, [O_3]\, [NO] - k_{9}\, [O]\, [NO_2] - k_{10}\, [NO_2]\\ - \end{aligned} - -where square brackets denote concentrations of the species. The code for -the ODE function is in :code:`ROOT_Function.f90` (or :code:`.F90`) The -chemical reaction mechanism represents a set of ordinary differential -equations (ODEs) of dimension . The concentrations of fixed species -are parameters in the derivative function. The subroutine computes -first the vector :code:`A` of reaction rates and then the vector -:code:`Vdot` of variable species time derivatives. The input arguments -:code:`V`, :code:`F`, :code:`RCT` are the concentrations of variable -species, fixed species, and the rate coefficients, -respectively. :code:`A` and :code:`Vdot` may be returned to the -calling program (for diagnostic purposes) with optional ouptut -argument :code:`Aout`. Below is the Fortran90 -code generated by KPP for the ODE function of our -:program:`small_strato` example. - -.. code-block:: fortran - - SUBROUTINE Fun (V, F, RCT, Vdot, Aout, Vdotout ) - - ! V - Concentrations of variable species (local) - REAL(kind=dp) :: V(NVAR) - ! F - Concentrations of fixed species (local) - REAL(kind=dp) :: F(NVAR) - ! RCT - Rate constants (local) - REAL(kind=dp) :: RCT(NREACT) - ! Vdot - Time derivative of variable species concentrations - REAL(kind=dp) :: Vdot(NVAR) - ! Aout - Optional argument to return equation rate constants - REAL(kind=dp), OPTIONAL :: Aout(NREACT) - - - ! Computation of equation rates - A(1) = RCT(1)*F(2) - A(2) = RCT(2)*V(2)*F(2) - A(3) = RCT(3)*V(3) - A(4) = RCT(4)*V(2)*V(3) - A(5) = RCT(5)*V(3) - A(6) = RCT(6)*V(1)*F(1) - A(7) = RCT(7)*V(1)*V(3) - A(8) = RCT(8)*V(3)*V(4) - A(9) = RCT(9)*V(2)*V(5) - A(10) = RCT(10)*V(5) - - !### Use Aout to return equation rates - IF ( PRESENT( Aout ) ) Aout = A - - ! Aggregate function - Vdot(1) = A(5)-A(6)-A(7) - Vdot(2) = 2*A(1)-A(2)+A(3) & - -A(4)+A(6)-A(9)+A(10) - Vdot(3) = A(2)-A(3)-A(4)-A(5) & - -A(7)-A(8) - Vdot(4) = -A(8)+A(9)+A(10) - Vdot(5) = A(8)-A(9)-A(10) - - END SUBROUTINE Fun - -.. _Jacobian-and-JacobianSP: - -ROOT_Jacobian and ROOT_JacobianSP ---------------------------------- - -The Jacobian matrix for our example contains 18 non-zero elements: - -.. math:: - - \begin{aligned} - \mathbf{J}(1,1) & = & - k_{6}\, [{M}] - k_{7}\, [{O_3}]\\ - \mathbf{J}(1,3) & = & k_{5} - k_{7}\, [{O(^1D)}]\\ - \mathbf{J}(2,1) & = & k_{6}\, [{M}]\\ - \mathbf{J}(2,2) & = & - k_{2}\, [{O_2}] - k_{4}\, [{O_3}] - - k_{9}\, [{NO_2}]\\ - \mathbf{J}(2,3) & = & k_{3} - k_{4}\, [{O}]\\ - \mathbf{J}(2,5) & = & - k_{9}\, [{O}] + k_{10}\\ - \mathbf{J}(3,1) & = & - k_{7}\, [{O_3}]\\ - \mathbf{J}(3,2) & = & k_{2}\, [{O_2}] - k_{4}\, [{O_3}]\\ - \mathbf{J}(3,3) & = & - k_{3} - k_{4}\, [{O}] - k_{5} - k_{7}\, - [{O(^1D)}] - k_{8}\, [{NO}]\\ - \mathbf{J}(3,4) & = & - k_{8}\, [{O_3}]\\ - \mathbf{J}(4,2) & = & k_{9}\, [{NO_2}]\\ - \mathbf{J}(4,3) & = & - k_{8}\, [{NO}]\\ - \mathbf{J}(4,4) & = & - k_{8}\, [{O_3}]\\ - \mathbf{J}(4,5) & = & k_{9}\, [{O}] + k_{10}\\ - \mathbf{J}(5,2) & = & - k_{9}\, [{NO_2}]\\ - \mathbf{J}(5,3) & = & k_{8}\, [{NO}]\\ - \mathbf{J}(5,4) & = & k_{8}\, [{O_3}]\\ - \mathbf{J}(5,5) & = & - k_{9}\, [{O}] - k_{10}\\ - \end{aligned} - -It defines how the temporal change of each chemical species depends on -all other species. For example, :math:`\mathbf{J}(5,2)` shows that :math:`NO_2` -(species number 5) is affected by :math:`O` (species number 2) via -reaction R9. The sparse data structures for the Jacobian are -declared and initialized in :file:`ROOT_JacobianSP.f90` (or -:file:`.F90`). The code for the ODE Jacobian and -sparse multiplications is in :file:`ROOT_Jacobian.f90` (or -:file:`.F90`). - -.. tip:: - - Adding either :command:`#JACOBIAN SPARSE_ROW` or - :command:`#JACOBIAN SPARSE_LU_ROW` to the KPP definition file will - create the file :file:`ROOT_JacobianSP.f90` (or :file:`.F90`). - -The Jacobian of the ODE function is automatically constructed by KPP. -KPP generates the Jacobian subroutine :code:`Jac` or :code:`JacSP` where -the latter is generated when the sparse format is required. Using the -variable species :code:`V`, the fixed species :code:`F`, and the rate -coefficients :code:`RCT` as input, the subroutine calculates the -Jacobian :code:`JVS`. The default data structures for the sparse -compressed on rows Jacobian representation (for the case where the LU -fill-in is accounted for) are: - -.. _table-jac: - -.. table:: Sparse Jacobian Data Structures - :align: center - - +------------------------------+-------------------------------------+ - | Global variable | Represents | - +==============================+=====================================+ - | :code:`JVS(LU_NONZERO)` | Jacobian nonzero elements | - +------------------------------+-------------------------------------+ - | :code:`LU_IROW(LU_NONZERO)` | Row indices | - +------------------------------+-------------------------------------+ - | :code:`LU_ICOL(LU_NONZERO)` | Column indices | - +------------------------------+-------------------------------------+ - | :code:`LU_CROW(NVAR+1)` | Start of rows | - +------------------------------+-------------------------------------+ - | :code:`LU_DIAG(NVAR+1)` | Diagonal entries | - +------------------------------+-------------------------------------+ - -:code:`JVS` stores the :code:`LU_NONZERO` elements of the -Jacobian in row order. Each row :code:`I` starts at position -:code:`LU_CROW(I)`, and :code:`LU_CROW(NVAR+1)` = -:code:`LU_NONZERO+1`. The location of the :code:`I`-th diagonal -element is :code:`LU_DIAG(I)`. The sparse element :code:`JVS(K)` is -the Jacobian entry in row :code:`LU_IROW(K)` and column -:code:`LU_ICOL(K`). For the :program:`small_strato` example KPP -generates the following Jacobian sparse data structure: - -.. code-block:: fortran - - LU_ICOL = (/ 1,3,1,2,3,5,1,2,3,4, & - 5,2,3,4,5,2,3,4,5 /) - LU_IROW = (/ 1,1,2,2,2,2,3,3,3,3, & - 3,4,4,4,4,5,5,5,5 /) - LU_CROW = (/ 1,3,7,12,16,20 /) - LU_DIAG = (/ 1,4,9,14,19,20 /) - -This is visualized in Figure 2 below.. The sparsity coordinate -vectors are computed by KPP and initialized statically. These vectors -are constant as the sparsity pattern of the Jacobian does not change -during the computation. - -.. _figure-2: - -.. figure:: ../_static/small_jac.png - :alt: Figure 2: The sparsity pattern of the Jacobian for the - small_strato example. - :scale: 60% - :align: center - - Figure 2: The sparsity pattern of the Jacobian for the - :program:`small_strato` example. All non-zero elements are marked - with a bullet. Note that even though :math:`\mathbf{J}(3,5)` is - zero, it is also included here because of the fill-in. - -Two other KPP-generated routines, :code:`Jac_SP_Vec` and -:code:`JacTR_SP_Vec` (see :ref:`table-jac-fun`) are useful for direct -and adjoint sensitivity analysis. They perform sparse multiplication of -:code:`JVS` (or its transpose for :code:`JacTR_SP_Vec`) with the -user-supplied vector :code:`UV` without any indirect addressing. - -.. _table-jac-fun: - -.. table:: Fortran90 subroutines in ROOT_Jacobian - :align: center - - +----------------------+----------------------------------------------+ - | Function | Description | - +======================+==============================================+ - | :code:`Jac_SP` | ODE Jacobian in sparse format | - +----------------------+----------------------------------------------+ - | :code:`Jac_SP_Vec` | Sparse multiplication | - +----------------------+----------------------------------------------+ - | :code:`JacTR_SP_Vec` | Sparse multiplication | - +----------------------+----------------------------------------------+ - | :code:`Jac` | ODE Jacobian in full format | - +----------------------+----------------------------------------------+ - -.. _Hessian-and-HessianSP: - -ROOT_Hessian and ROOT_HessianSP -------------------------------- - -The sparse data structures for the Hessian are declared and initialized -in :file:`ROOT_Hessian.f90` (or :file:`.F90`). The Hessian -function and associated sparse multiplications are in -:code:`ROOT_HessianSP.f90` (or :code:`.F90`). - -The Hessian contains the second order derivatives of the time derivative -functions. More exactly, the Hessian is a 3-tensor such that - -.. math:: - - H_{i,j,k} = \frac{\partial^2 ({\mathrm{d}}c/{\mathrm{d}}t)_i}{\partial c_j \,\partial c_k}~, - \qquad 1 \le i,j,k \le N_{\rm var}~. - \label{eqn:Hessian1} - -KPP generates the routine :code:`Hessian`: - -.. _table-hess-fun: - -.. table:: Fortran90 functions in ROOT_Hessian - :align: center - - +--------------------+--------------------------------------+ - | Function | Description | - +====================+======================================+ - | :code:`Hessian` | ODE Hessian in sparse format | - +--------------------+--------------------------------------+ - | :code:`Hess_Vec` | Hessian action on vectors | - +--------------------+--------------------------------------+ - | :code:`HessTR_Vec` | Transposed Hessian action on vectors | - +--------------------+--------------------------------------+ - -Using the variable species :code:`V`, the fixed species :code:`F`, and -the rate coefficients :code:`RCT` as input, the subroutine -:code:`Hessian` calculates the Hessian. The Hessian is a very sparse -tensor. The sparsity of the Hessian for our example is visualized in -:ref:`figure-3` - -.. _figure-3: - -.. figure:: ../_static/small_hess1.png - :alt: Figure 3: The Hessian of the small_strato example - :align: center - - Figure 3: The Hessian of the small_strato example. - -KPP computes the number of nonzero Hessian entries and saves it in the -variable :code:`NHESS`. The Hessian itself is represented in -coordinate sparse format. The real vector :code:`HESS` holds the values, and the -integer vectors :code:`IHESS_I`, :code:`IHESS_J`, and :code:`IHESS_K` -hold the indices of nonzero entries as illustrated in :ref:`table-hess`. - -.. _table-hess: - -.. table:: Sparse Hessian Data - :align: center - - +-------------------------+----------------------------------------------+ - | Variable | Represents | - +=========================+==============================================+ - | :code:`HESS(NHESS)` | Hessian nonzero elements :math:`H_{i,j,k}` | - +-------------------------+----------------------------------------------+ - | :code:`IHESS_I(NHESS)` | Index :math:`i` of element :math:`H_{i,j,k}` | - +-------------------------+----------------------------------------------+ - | :code:`IHESS_J(NHESS)` | Index :math:`j` of element :math:`H_{i,j,k}` | - +-------------------------+----------------------------------------------+ - | :code:`IHESS_J(NHESS)` | Index :math:`k` of element :math:`H_{i,j,k}` | - +-------------------------+----------------------------------------------+ - -Since the time derivative function is smooth, these Hessian matrices -are symmetric, :math:`\tt HESS_{i,j,k}`\ =\ :math:`\tt HESS_{i,k,j}`. -KPP stores only those entries :math:`\tt HESS_{i,j,k}` with -:math:`j \le k`. The sparsity coordinate vectors :code:`IHESS_1`, -:code:`IHESS_J` and :code:`IHESS_K` are computed by KPP and -initialized statically. They are constant as the sparsity pattern of -the Hessian does not change during the computation. - -The routines :code:`Hess_Vec` and :code:`HessTR_Vec` compute the -action of the Hessian (or its transpose) on a pair of user-supplied -vectors :code:`U1` and :code:`U2`. Sparse operations are employed to -produce the result vector. - -.. _LinearAlgebra: - -ROOT_LinearAlgebra ------------------- - -Sparse linear algebra routines are in the file -:file:`ROOT_LinearAlgebra.f90` (or :file:`.F90`). To -numerically solve for the chemical concentrations one must employ an -implicit timestepping technique, as the system is usually stiff. Implicit -integrators solve systems of the form - -.. math:: P\, x = (I - h \gamma J)\, x = b - -where the matrix :math:`P=I - h \gamma J` is refered to as the -“prediction matrix”. :math:`I` the identity matrix, :math:`h` the -integration time step, :math:`\gamma` a scalar parameter depending on -the method, and :math:`J` the system Jacobian. The vector :math:`b` is -the system right hand side and the solution :math:`x` typically -represents an increment to update the solution. - -The chemical Jacobians are typically sparse, i.e. only a relatively -small number of entries are nonzero. The sparsity structure of :math:`P` -is given by the sparsity structure of the Jacobian, and is produced by -KPP (with account for the fill-in) as discussed above. - -KPP generates the sparse linear algebra subroutine :code:`KppDecomp` -(see :ref:`table-la-fun`) which performs an in-place, non-pivoting, -sparse LU decomposition of the prediction matrix :math:`P`. Since the -sparsity structure accounts for fill-in, all elements of the full LU -decomposition are actually stored. The output argument :code:`IER` -returns a value that is nonzero if singularity is detected. - -.. _table-la-fun: - -.. table:: Fortran90 functions in ROOT_LinearAlgebra - :align: center - - +--------------------+--------------------------------------+ - | Function | Description | - +====================+======================================+ - | :code:`KppDecomp` | Sparse LU decomposition | - +--------------------+--------------------------------------+ - | :code:`KppSolve` | Sparse back subsitution | - +--------------------+--------------------------------------+ - | :code:`KppSolveTR` | Transposed sparse back substitution | - +--------------------+--------------------------------------+ - -The subroutines :code:`KppSolve` and :code:`KppSolveTr` and use the -in-place LU factorization :math:`P` as computed by and perform sparse -backward and forward substitutions (using :math:`P` or its -transpose). The sparse linear algebra routines :code:`KppDecomp` and -:code:`KppSolve` are extremely efficient, as shown by -:cite:t:`Sandu_et_al._1996`. - -.. _Stoichiom-and-StoichiomSP: - -ROOT_Stoichiom and ROOT_StoichiomSP ------------------------------------ - -These files contain contain a description of the chemical mechanism in -stoichiometric form. The file :file:`ROOT_Stoichiom.f90` (or -:file:`.F90`) contains the functions for reactant -products and its Jacobian, and derivatives with respect to rate -coefficients. The declaration and initialization of the stoichiometric -matrix and the associated sparse data structures is done in -:file:`ROOT_StochiomSP.f90` (or :file:`.F90`). - -.. tip:: - - Adding :command:`#STOICMAT ON` to the KPP definition file will - create the file :file:`ROOT_Stoichiom.f90` (or :file:`.F90`) - Also, if either :command:`#JACOBIAN SPARSE ROW` or - :command:`#JACOBIAN SPARSE_LU_ROW` are also added to the KPP - definition file, the file :file:`ROOT_StoichiomSP.f90` (or - :file:`.F90`) will also be created. - -The stoichiometric matrix is constant sparse. For our example the matrix -:code:`NSTOICM=22` has 22 nonzero entries out of 50 entries. KPP produces the -stoichiometric matrix in sparse, column-compressed format, as shown in -:ref:`table-sto`. Elements are stored in columnwise order in the -one-dimensional vector of values :code:`STOICM`. Their row and column indices -are stored in :code:`ICOL_STOICM` and :code:`ICOL_STOICM` -respectively. The vector :code:`CCOL_STOICM` contains pointers to -the start of each column. For example column :code:`j` starts in the sparse -vector at position :code:`CCOL_STOICM(j)` and ends at -:code:`CCOL_STOICM(j+1)-1`. The last value :code:`CCOL_STOICM(NVAR)` = -:code:`NSTOICHM+1` simplifies the handling of sparse data structures. - -.. _table-sto: - -.. table:: Sparse Stoichiometric Matrix - :align: center - - +-------------------------------+-----------------------------------------+ - | Variable | Represents | - +===============================+=========================================+ - | :code:`STOICM(NSTOICM)` | Stoichiometric matrix | - +-------------------------------+-----------------------------------------+ - | :code:`IROW_STOICM(NSTOICM)` | Row indices | - +-------------------------------+-----------------------------------------+ - | :code:`ICOL_STOICM(NSTOICM)` | Column indices | - +-------------------------------+-----------------------------------------+ - | :code:`CCOL_STOICM(NREACT+1)` | Start of columns | - +-------------------------------+-----------------------------------------+ - -.. _table-sto-fun: - -.. table:: Fortran90 functions in ROOT_Stoichiom - :align: center - - +-------------------------+--------------------------------------------+ - | Variable | Represents | - +=========================+============================================+ - | :code:`dFun_dRcoeff` | Derivatives of Fun w/r/t rate coefficients | - +-------------------------+--------------------------------------------+ - | :code:`dJac_dRcoeff` | Derivatives of Jac w/r/t rate coefficients | - +-------------------------+--------------------------------------------+ - | :code:`ReactantProd` | Reactant products | - +-------------------------+--------------------------------------------+ - | :code:`JacReactantProd` | Jacobian of reactant products | - +-------------------------+--------------------------------------------+ - -The subroutine :code:`ReactantProd` (see :ref:`table-sto-fun`) -computes the reactant products :code:`ARP` for each reaction, and the -subroutine :code:`JacReactantProd` computes the Jacobian of reactant products -vector, i.e.: - -.. math:: - - \begin{aligned} - \tt JVRP = {\partial{\tt ARP}}/{\partial{\tt V}} - \end{aligned} - -The matrix :code:`JVRP` is sparse and is computed and stored in row -compressed sparse format, as shown in :ref:`table-hess-fun`. The -parameter :code:`NJVRP` holds the number of nonzero elements. For our -:program:`small_strato` example: - -.. code-block:: fortran - - NJVRP = 13 - CROW_JVRP = (/ 1,1,2,3,5,6,7,9,11,13,14 /) - ICOL_JVRP = (/ 2,3,2,3,3,1,1,3,3,4,2,5,4 /) - -.. _table-jvrp: - -.. table:: Sparse Data for Jacobian of Reactant Products - :align: center - - +-------------------------------+-----------------------------------------+ - | Variable | Represents | - +===============================+=========================================+ - | :code:`JVRP(NJVRP)` | Nonzero elements of :code:`JVRP` | - +-------------------------------+-----------------------------------------+ - | :code:`ICOL_JVRP(NJVRP)` | Column indices of :code:`JVRP` | - +-------------------------------+-----------------------------------------+ - | :code:`IROW_JVRP(NJVRP)` | Row indices of :code:`JVRP` | - +-------------------------------+-----------------------------------------+ - | :code:`CROW_JVRP(NREACT+1)` | Start of rows in :code:`JVRP` | - +-------------------------------+-----------------------------------------+ - -If :command:`#STOICMAT` is set to :command:`ON`, the stoichiometric -formulation allows a direct computation of the derivatives with -respect to rate coefficients. - -The subroutine :code:`dFun_dRcoeff` computes the partial derivative -:code:`DFDR` of the ODE function with respect to a subset of -:code:`NCOEFF` reaction coefficients, whose indices are specified in the array - -.. math:: - - \begin{aligned} - \tt DFDR = {\partial{\tt Vdot}}/{\partial{\tt RCT(JCOEFF)}} - \end{aligned} - -Similarly one can obtain the partial derivative of the Jacobian with -respect to a subset of the rate coefficients. More exactly, KPP -generates the subroutine :code:`dJacR_dCoeff`, which calculates -:code:`DJDR`, the product of this partial derivative with a -user-supplied vector :code:`U`: - -.. math:: - - \begin{aligned} - \tt DJDR = [{\partial{\tt JVS}}/{\partial{\tt RCT(JCOEFF)}}] - \times {\tt U} - \end{aligned} - -.. _Stochastic: - -ROOT_Stochastic ---------------- - -If the generation of stochastic functions is switched on (i.e. when -the command :command:`#STOCHASTIC ON` is added to the KPP definition -file), KPP produces the file :code:`ROOT_Stochastic.f90` (or :code:`.F90`), -with the following functions: - -:code:`Propensity` calculates the propensity vector. The propensity -function uses the number of molecules of variable (:code:`Nmlcv`) and -fixed (:code:`Nmlcf`) species, as well as the stochastic rate -coefficients (:code:`SCT`) to calculate the vector of propensity rates -(:code:`Propensity`). The propensity :math:`\tt Prop_j` defines the -probability that the next reaction in the system is the :math:`j^{th}` -reaction. - -:code:`StochasticRates` converts deterministic rates to -stochastic. The stochastic rate coefficients (:code:`SCT`) are -obtained through a scaling of the deterministic rate -coefficients (:code:`RCT`). The scaling depends on the :code:`Volume` -of the reaction container and on the number of molecules which react. - -:code:`MoleculeChange` calculates changes in the number of -molecules. When the reaction with index :code:`IRCT` takes place, the -number of molecules of species involved in that reaction changes. The -total number of molecules is updated by the function. - -These functions are used by the Gillespie numerical integrators (direct -stochastic simulation algorithm). These integrators are provided in both -Fortran90 and C implementations (the template file name is -:file:`gillespie`). Drivers for stochastic simulations are also -implemented (the template file name is :code:`general_stochastic`.). - -.. _Util: - -ROOT_Util ---------- - -In addition to the chemical system description routines discussed above, -KPP generates several utility subroutines and functions in the file -:file:`ROOT_Util.f90` (or :file:`.F90`). - -.. _table-util-fun: - -.. table:: Fortran90 subroutines and functions in ROOT_Util - :align: center - - +-----------------------------------+---------------------------------------------+ - | Function | Description | - +===================================+=============================================+ - | :code:`GetMass` | Check mass balance for selected atoms | - +-----------------------------------+---------------------------------------------+ - | :code:`Shuffle_kpp2user` | Shuffle concentration vector | - +-----------------------------------+---------------------------------------------+ - | :code:`Shuffle_user2kpp` | Shuffle concentration vector | - +-----------------------------------+---------------------------------------------+ - | :code:`InitSaveData` | Utility for :command:`#LOOKAT` command | - +-----------------------------------+---------------------------------------------+ - | :code:`SaveData` | Utility for :command:`#LOOKAT` command | - +-----------------------------------+---------------------------------------------+ - | :code:`CloseSaveData` | Utility for :command:`#LOOKAT` command | - +-----------------------------------+---------------------------------------------+ - | :code:`tag2num` | Calculate reaction number from equation tag | - +-----------------------------------+---------------------------------------------+ - | :code:`Integrator_Update_Options` | Choose :code:`Update_RCONST/PHOTO/SUN` | - +-----------------------------------+---------------------------------------------+ - -The subroutines :code:`InitSaveData`, :code:`SaveData`, and -:code:`CloseSaveData` can be used to print the concentration of the -species that were selected with :command:`#LOOKAT` to the file -:file:`ROOT.dat` (cf. :ref:`lookat-and-monitor`). - -.. _Mex-code: - -ROOT_mex_Fun, ROOT_mex_Jac_SP, and ROOT_mex_Hessian ---------------------------------------------------- - -:program:`Mex` is a Matlab extension. KPP generates the mex -routines for the ODE function, Jacobian, and Hessian, for the target -languages C, Fortran77, and Fortran90. - -.. tip:: - - To generate Mex files, add the command :command:`#MEX ON` to the KPP - definition file. - -After compilation (using -Matlab’s mex compiler) the mex functions can be called instead of the -corresponding Matlab m-functions. Since the calling syntaxes are -identical, the user only has to insert the :program:`mex` string -within the corresponding function name. Replacing m-functions by -mex-functions gives the same numerical results, but the computational -time could be considerably smaller, especially for large kinetic -systems. - -If possible we recommend to build mex files using the C language, as -Matlab offers most mex interface options for the C language. Moreover, -Matlab distributions come with a native C compiler (:program:`lcc`) for -building executable functions from mex files. The mex files built using -Fortran90 may require further platform-specific tuning of the mex -compiler options. - -.. _C-code: - -========== -The C code -========== - -.. important:: - - Some run-time options for C-language integrators (specified in - the :ref:`ICNTRL and RCNTRL arrays `) do not exactly - correspond to the Fortran90 run-time options. We will standardize - run-time integrator options across all target languages in a future - KPP release. - -The driver file :file:`ROOT.c` contains the main (driver) program and -numerical integrator functions, as well as declarations and -initializations of global variables. - -The generated C code includes three header files which are -:code:`#include`-d in other files as appropriate. - -#. The global parameters (cf. :ref:`table-par`) are :code:`#include`-d in - the header file :file:`ROOT_Parameters.h` - -#. The global variables (cf. :ref:`table-glob`) are extern-declared in - :file:`ROOT_Global.h` and declared in the driver file :file:`ROOT.c`. - -#. The header file :file:`ROOT_Sparse.h` contains extern declarations - of sparse data structures for the Jacobian (cf. - :ref:`table-jac`),Hessian (cf. :ref:`table-hess`) and stoichiometric - matrix (cf. :ref:`table-sto`), and the Jacobian of reaction - products (cf. :ref:`table-jvrp`). The actual declarations of each - datastructures is done in the corresponding files. - -The code for the ODE function (see section :ref:`Function`) is in -:file:`ROOT_Function.c`. The code for the ODE Jacobian and sparse -multiplications (cf. :ref:`Jacobian-and-JacobianSP`) is in -:file:`ROOT_Jacobian.c`, and the declaration and initialization of the -Jacobian sparse data structures is in the file -:file:`ROOT_JacobianSP.c`. Similarly, the Hessian function and -associated sparse multiplications (cf. :ref:`Hessian-and-HessianSP`) -are in :file:`ROOT_Hessian.c`, and the declaration and initialization -of Hessian sparse data structures are in :file:`ROOT_HessianSP.c`. - -The file :file:`ROOT_Stoichiom.c` contains the functions for reactant -products and its Jacobian, and derivatives with respect to rate coefficients -(cf. :ref:`Stoichiom-and-StoichiomSP`) . The declaration and -initialization of the stoichiometric matrix and the associated sparse -data structures (cf. :ref:`table-sto`) is done in :file:`ROOT_StoichiomSP.c`. - -Sparse linear algebra routines (cf. :ref:`LinearAlgebra`) are -in the file :file:`ROOT_LinearAlgebra.c`. The code to update the rate -constants and user defined code for rate laws is in :file:`ROOT_Rates.c`. - -Various utility and input/output functions (cf. :ref:`Util`) are in -:file:`ROOT_Util.c` and :file:`ROOT_Monitor.c`. - -Finally, mex gateway routines that allow the C implementation of the ODE -function, Jacobian, and Hessian to be called directly from Matlab -(cf. :ref:`Mex-code`) are also generated (in the files -:file:`ROOT_mex_Fun.c`, :file:`ROOT_mex_Jac_SP.c`, and -:file:`ROOT_mex_Hessian.c`). - -.. _matlab-code: - -=============== -The Matlab code -=============== - -.. important:: - - Some run-time options for Matlab-language integrators (specified in - the :ref:`ICNTRL and RCNTRL arrays `) do not exactly - correspond to the Fortran90 run-time options. We will standardize - run-time integrator options across all target languages in a future - KPP release. - -`Matlab `_ provides a -high-level programming environment that allows algorithm development, -numerical computations, and data analysis and visualization. The -KPP-generated Matlab code allows for a rapid prototyping of chemical -kinetic schemes, and for a convenient analysis and visualization of the -results. Differences between different kinetic mechanisms can be easily -understood. The Matlab code can be used to derive reference numerical -solutions, which are then compared against the results obtained with -user-supplied numerical techniques. KPP/Matlab can also be used to teach -students fundamentals of chemical kinetics and chemical numerical -simulations. - -Each Matlab function has to reside in a separate m-file. Function calls -use the m-function-file names to reference the function. Consequently, -KPP generates one m-function-file for each of the functions discussed in -the sections entitled :ref:`Function` , -:ref:`Jacobian-and-JacobianSP`, :ref:`Hessian-and-HessianSP`, -:ref:`Stoichiom-and-StoichiomSP`, :ref:`Util`. The names of the -m-function-files are the same as the names of the functions (prefixed -by the model name :code:`ROOT`. - -The variables of :ref:`table-par` are defined as Matlab :code:`global` -variables and initialized in the file -:file:`ROOT_parameter_defs.m`. The variables of :ref:`table-glob` are -declared as Matlab :code:`global` variables in the file -:file:`ROOT_global_defs.m`. They can be accessed from within each -Matlab function by using declarations of the variables of interest. - -The sparse data structures for the Jacobian (cf. :ref:`table-jac`), the Hessian -(cf. :ref:`table-hess`), the stoichiometric matrix (cf. :ref:`table-sto`), -and the Jacobian of reaction (see :ref:`table-jvrp`) are declared as -Matlab :code:`global` variables in the file -:file:`ROOT_Sparse_defs.m`. They are initialized in separate m-files, -namely :file:`ROOT_JacobianSP.m`, :file:`ROOT_HessianSP.m`, and -:file:`ROOT_StoichiomSP.m` respectively. - -Two wrappers (:file:`ROOT_Fun_Chem.m` and :file:`ROOT_Jac_SP_Chem.m`) are -provided for interfacing the ODE function and the sparse ODE Jacobian -with Matlab’s suite of ODE integrators. Specifically, the syntax of -the wrapper calls matches the syntax required by Matlab’s integrators -like ode15s. Moreover, the Jacobian wrapper converts the sparse KPP -format into a Matlab sparse matrix. - -.. _table-matlab: - -.. table:: List of Matlab model files - :align: center - - +----------------------------------+-------------------------------------+ - | Function | Description | - +==================================+=====================================+ - | :file:`ROOT.m` | Driver | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_parameter_defs.m` | Global parameters | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_global_defs.m` | Global variables | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_sparse_defs.m` | Global sparsity data | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Fun_Chem.m` | Template for ODE function | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Fun.m` | ODE function | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Jac_Chem.m` | Template for ODE Jacobian | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Jac_SP.m` | Jacobian in sparse format | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_JacobianSP.m` | Sparsity data structures | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Hessian.m` | ODE Hessian in sparse format | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_HessianSP.m` | Sparsity data structures | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Hess_Vec.m` | Hessian action on vectors | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_HessTR_Vec.m` | Transposed Hessian action on | - | | vectors | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_stoichiom.m` | Derivatives of Fun and Jac w/r/t | - | | rate coefficients | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_stochiomSP.m` | Sparse data | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_ReactantProd.m` | Reactant products | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_JacReactantProd.m` | Jacobian of reactant products | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Rates.m` | User-defined rate reaction laws | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Update_PHOTO.m` | Update photolysis rate coefficients | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Update_RCONST.m` | Update all rate coefficients | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Update_SUN.m` | Update sola intensity | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_GetMass.m` | Check mass balance for selected | - | | atoms | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Initialize.m` | Set initial values | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Shuffle_kpp2user.m` | Shuffle concentration vector | - +----------------------------------+-------------------------------------+ - | :file:`ROOT_Shuffle_user2kpp.m` | Shuffle concentration vector | - +----------------------------------+-------------------------------------+ - -.. _Makefile: - -============ -The Makefile -============ - -KPP produces a Makefile that allows for an easy compilation of all -KPP-generated source files. The file name is :file:`Makefile_ROOT`. The -Makefile assumes that the selected driver contains the main program. -However, if no driver was selected (i.e. :command:`#DRIVER none`), it is -necessary to add the name of the main program file manually to the -Makefile. - -.. _Log: - -============ -The log file -============ - -The log file :file:`ROOT.log` contains a summary of all the functions, -subroutines and data structures defined in the code file, plus a -summary of the numbering and category of the species involved. - -This file contains supplementary information for the user. Several -statistics are listed here, like the total number equations, the total -number of species, the number of variable and fixed species. Each -species from the chemical mechanism is then listed followed by its type -and numbering. - -Furthermore it contains the complete list of all the functions generated -in the target source file. For each function, a brief description of the -computation performed is attached containing also the meaning of the -input and output parameters. - -================================================================= -Output from the Integrators (:code:`ISTATUS` and :code:`RSTATUS`) -================================================================= - -In order to obtain more information about the integration, KPP provides -the arrays :code:`ISTATUS` (integer) and :code:`RSTATUS` (real). Each of -them is an array of 20 elements. Array elements not listed here are -currently not used. Details can be found in the comment lines of the -individual integrator files in :code:`$KPP_HOME/int/`. - -ISTATUS -------- - -.. _table-istatus: - -.. table:: Summary of ISTATUS usage in the f90 integrators. - Here, Y = used. - :align: center - - +----------------------------+---+---+---+---+---+---+---+---+---+ - | ISTATUS | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - +============================+===+===+===+===+===+===+===+===+===+ - | beuler | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | dvode | | | | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | exponential | | | | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | feuler | | | | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | gillespie | | | | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | lsode | Y | Y | Y | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | radau5 | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | rosenbrock_adj | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | rosenbrock | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | rosenbrock_tlm | Y | Y | Y | Y | Y | Y | Y | Y | Y | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | rosenbrock_autoreduce | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | runge_kutta_adj | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | runge_kutta | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | runge_kutta_tlm | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | sdirk4 | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | sdirk_adj | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | sdirk | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | sdirk_tlm | Y | Y | Y | Y | Y | Y | Y | Y | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | seulex | Y | Y | Y | Y | Y | Y | Y | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - | tau_leap | | | | | | | | | | - +----------------------------+---+---+---+---+---+---+---+---+---+ - -ISTATUS(1) -~~~~~~~~~~ - -Number of times that the :ref:`function containing the chemical ODE system -` was called. - -ISTATUS(2) -~~~~~~~~~~ - -Number times :ref:`the Jacobian matrix ` was constructed. - -ISTATUS(3) -~~~~~~~~~~ - -Total number of integration timesteps. - -ISTATUS(4) -~~~~~~~~~~ - -Number of accepted timesteps. - -ISTATUS(5) -~~~~~~~~~~ - -Number of rejected timesteps (except at very beginning). - -ISTATUS(6) -~~~~~~~~~~ - -Number of LU decompositions that were performed. - -ISTATUS(7) -~~~~~~~~~~ - -Number of forward/backward substitutions that were performed. - -ISTATUS(8) -~~~~~~~~~~ - -Number of singular matrix decompositions that were performed. - -ISTATUS(9) -~~~~~~~~~~ - -Number of times :ref:`the Hessian matrix ` was evaluated. - -ISTATUS(10) .. ISTATUS(20) -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Currently not used. - -RSTATUS -------- - -.. _table-rstatus: - -.. table:: Summary of RSTATUS usage in the f90 integrators. - Here, Y = used, s = solver specific usage. - :align: center - - +----------------------------+---+---+---+---+ - | RSTATUS | 1 | 2 | 3 | 4 | - +============================+===+===+===+===+ - | beuler | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | dvode | | | | | - +----------------------------+---+---+---+---+ - | exponential | | | | | - +----------------------------+---+---+---+---+ - | feuler | Y | | | | - +----------------------------+---+---+---+---+ - | gillespie | | | | | - +----------------------------+---+---+---+---+ - | lsode | Y | Y | | | - +----------------------------+---+---+---+---+ - | radau5 | | | | | - +----------------------------+---+---+---+---+ - | rosenbrock_adj | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | rosenbrock | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | rosenbrock_tlm | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | rosenbrock_autoreduce | Y | Y | Y | s | - +----------------------------+---+---+---+---+ - | runge_kutta_adj | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | runge_kutta | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | runge_kutta_tlm | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | sdirk4 | Y | Y | | | - +----------------------------+---+---+---+---+ - | sdirk_adj | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | sdirk | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | sdirk_tlm | Y | Y | Y | | - +----------------------------+---+---+---+---+ - | seulex | | | | | - +----------------------------+---+---+---+---+ - | tau_leap | | | | | - +----------------------------+---+---+---+---+ - -RSTATUS(1) -~~~~~~~~~~ - -:code:`Texit`, the time corresponding to the computed :math:`Y` -upon return. - -RSTATUS(2) -~~~~~~~~~~ - -:code:`Hexit`: the last accepted step before exit. - -RSTATUS(3) -~~~~~~~~~~ - -:code:`Hnew`: The last predicted step (not yet taken. For multiple -restarts, use :code:`Hnew` as :code:`Hstart` in the subsequent run. - -RSTATUS(4) -~~~~~~~~~~ - -(Solver-specific for :code:`rosenbrock_autoreduce`) :code:`AR_thr`: -used to output the calculated (used) auto-reduction threshold for -the integration. Useful when :code:`ICNTRL(10) > 0` where the -threshold is dynamically determined based on a given species. - -RSTATUS(5) .. RSTATUS(20) -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Currently not used. diff --git a/docs/source/using_kpp/math.txt b/docs/source/using_kpp/math.txt deleted file mode 100644 index ef2c471..0000000 --- a/docs/source/using_kpp/math.txt +++ /dev/null @@ -1,415 +0,0 @@ - +---------+-----------+----------+-------+-----------+-----------+ - | | Stages | Function | Order | Stability | Method | - +---------+-----------+----------+-------+-----------+-----------+ - | name | (: | calls | | p | coe | - | | math:`s`) | | | roperties | fficients | - +---------+-----------+----------+-------+-----------+-----------+ - | ROS–2 | 2 | 2 | 2(1) | L-stable | :math | - | | | | | | :`\gamma | - | | | | | | = 1 + 1/\ | - | | | | | | sqrt{2}`, | - | | | | | | `a_ | - | | | | | | {2,1} = 1 | - | | | | | | /\gamma`, | - | | | | | | : | - | | | | | | math:`c_{ | - | | | | | | 2,1} = -2 | - | | | | | | /\gamma`, | - | | | | | | `m | - | | | | | | _1 = 3/(2 | - | | | | | | \gamma)`, | - | | | | | | `m | - | | | | | | _2 = 1/(2 | - | | | | | | \gamma)`, | - | | | | | | `e | - | | | | | | _1 = 1/(2 | - | | | | | | \gamma)`, | - | | | | | | `e | - | | | | | | _2 = 1/(2 | - | | | | | | \gamma)`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_1 = 0`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_2 = 1`, | - | | | | | | `\ | - | | | | | | gamma_1 = | - | | | | | | \gamma`, | - | | | | | | `\ | - | | | | | | gamma_2 = | - | | | | | | -\gamma` | - +---------+-----------+----------+-------+-----------+-----------+ - | ROS–3 | 3 | 2 | 3(2) | L-stable | :m | - | | | | | | ath:`a_{2 | - | | | | | | ,1} = 1`, | - | | | | | | :m | - | | | | | | ath:`a_{3 | - | | | | | | ,1} = 1`, | - | | | | | | :m | - | | | | | | ath:`a_{3 | - | | | | | | ,2} = 0`, | - | | | | | | ` | - | | | | | | c_{2,1} = | - | | | | | | -1.015`, | - | | | | | | | - | | | | | | `c_{3,1} | - | | | | | | = 4.075`, | - | | | | | | | - | | | | | | `c_{3,2} | - | | | | | | = 9.207`, | - | | | | | | ` | - | | | | | | m_1 = 1`, | - | | | | | | :m | - | | | | | | ath:`m_2 | - | | | | | | = 6.169`, | - | | | | | | :ma | - | | | | | | th:`m_3 = | - | | | | | | -0.427`, | - | | | | | | `e_ | - | | | | | | 1 = 0.5`, | - | | | | | | :ma | - | | | | | | th:`e_2 = | - | | | | | | -2.908`, | - | | | | | | :m | - | | | | | | ath:`e_3 | - | | | | | | = 0.223`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_1 = 0`, | - | | | | | | ` | - | | | | | | \alpha_2 | - | | | | | | = 0.436`, | - | | | | | | ` | - | | | | | | \alpha_3 | - | | | | | | = 0.436`, | - | | | | | | ` | - | | | | | | \gamma_1 | - | | | | | | = 0.436`, | - | | | | | | ` | - | | | | | | \gamma_2 | - | | | | | | = 0.243`, | - | | | | | | | - | | | | | | `\gamma_3 | - | | | | | | = 2.185` | - +---------+-----------+----------+-------+-----------+-----------+ - | ROS–4 | 4 | 3 | 4(3) | L-stable | :m | - | | | | | | ath:`a_{2 | - | | | | | | ,1} = 2`, | - | | | | | | | - | | | | | | `a_{3,1} | - | | | | | | = 1.868`, | - | | | | | | | - | | | | | | `a_{3,2} | - | | | | | | = 0.234`, | - | | | | | | `a | - | | | | | | _{4,1} = | - | | | | | | a_{3,1}`, | - | | | | | | `a | - | | | | | | _{4,2} = | - | | | | | | a_{3,2}`, | - | | | | | | :m | - | | | | | | ath:`a_{4 | - | | | | | | ,3} = 0`, | - | | | | | | ` | - | | | | | | c_{2,1} = | - | | | | | | -7.137`, | - | | | | | | | - | | | | | | `c_{3,1} | - | | | | | | = 2.581`, | - | | | | | | | - | | | | | | `c_{3,2} | - | | | | | | = 0.652`, | - | | | | | | ` | - | | | | | | c_{4,1} = | - | | | | | | -2.137`, | - | | | | | | ` | - | | | | | | c_{4,2} = | - | | | | | | -0.321`, | - | | | | | | ` | - | | | | | | c_{4,3} = | - | | | | | | -0.695`, | - | | | | | | :m | - | | | | | | ath:`m_1 | - | | | | | | = 2.256`, | - | | | | | | :m | - | | | | | | ath:`m_2 | - | | | | | | = 0.287`, | - | | | | | | :m | - | | | | | | ath:`m_3 | - | | | | | | = 0.435`, | - | | | | | | :m | - | | | | | | ath:`m_4 | - | | | | | | = 1.094`, | - | | | | | | :ma | - | | | | | | th:`e_1 = | - | | | | | | -0.282`, | - | | | | | | :ma | - | | | | | | th:`e_2 = | - | | | | | | -0.073`, | - | | | | | | :ma | - | | | | | | th:`e_3 = | - | | | | | | -0.108`, | - | | | | | | :ma | - | | | | | | th:`e_4 = | - | | | | | | -1.093`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_1 = 0`, | - | | | | | | ` | - | | | | | | \alpha_2 | - | | | | | | = 1.146`, | - | | | | | | ` | - | | | | | | \alpha_3 | - | | | | | | = 0.655`, | - | | | | | | : | - | | | | | | math:`\al | - | | | | | | pha_4 = \ | - | | | | | | alpha_3`, | - | | | | | | ` | - | | | | | | \gamma_1 | - | | | | | | = 0.573`, | - | | | | | | `\ | - | | | | | | gamma_2 = | - | | | | | | -1.769`, | - | | | | | | ` | - | | | | | | \gamma_3 | - | | | | | | = 0.759`, | - | | | | | | ` | - | | | | | | \gamma_4 | - | | | | | | = -0.104` | - +---------+-----------+----------+-------+-----------+-----------+ - | RODAS–3 | 4 | 3 | 3(2) | Stiffly | :m | - | | | | | | ath:`a_{2 | - | | | | | accurate | ,1} = 0`, | - | | | | | | :m | - | | | | | | ath:`a_{3 | - | | | | | | ,1} = 2`, | - | | | | | | :m | - | | | | | | ath:`a_{3 | - | | | | | | ,2} = 0`, | - | | | | | | :m | - | | | | | | ath:`a_{4 | - | | | | | | ,1} = 2`, | - | | | | | | :m | - | | | | | | ath:`a_{4 | - | | | | | | ,2} = 0`, | - | | | | | | :m | - | | | | | | ath:`a_{4 | - | | | | | | ,3} = 1`, | - | | | | | | :m | - | | | | | | ath:`c_{2 | - | | | | | | ,1} = 4`, | - | | | | | | :m | - | | | | | | ath:`c_{3 | - | | | | | | ,1} = 1`, | - | | | | | | :ma | - | | | | | | th:`c_{3, | - | | | | | | 2} = -1`, | - | | | | | | :m | - | | | | | | ath:`c_{4 | - | | | | | | ,1} = 1`, | - | | | | | | :ma | - | | | | | | th:`c_{4, | - | | | | | | 2} = -1`, | - | | | | | | :math | - | | | | | | :`c_{4,3} | - | | | | | | = -8/3`, | - | | | | | | ` | - | | | | | | m_1 = 2`, | - | | | | | | ` | - | | | | | | m_2 = 0`, | - | | | | | | ` | - | | | | | | m_3 = 1`, | - | | | | | | ` | - | | | | | | m_4 = 1`, | - | | | | | | ` | - | | | | | | e_1 = 0`, | - | | | | | | ` | - | | | | | | e_2 = 0`, | - | | | | | | ` | - | | | | | | e_3 = 0`, | - | | | | | | ` | - | | | | | | e_4 = 1`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_1 = 0`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_2 = 0`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_3 = 1`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_4 = 1`, | - | | | | | | :math | - | | | | | | :`\gamma_ | - | | | | | | 1 = 0.5`, | - | | | | | | :math | - | | | | | | :`\gamma_ | - | | | | | | 2 = 1.5`, | - | | | | | | :ma | - | | | | | | th:`\gamm | - | | | | | | a_3 = 0`, | - | | | | | | :m | - | | | | | | ath:`\gam | - | | | | | | ma_4 = 0` | - +---------+-----------+----------+-------+-----------+-----------+ - | RODAS–4 | 6 | 5 | 4(3) | Stiffly | :ma | - | | | | | | th:`\alph | - | | | | | accurate | a_1 = 0`, | - | | | | | | ` | - | | | | | | \alpha_2 | - | | | | | | = 0.386`, | - | | | | | | ` | - | | | | | | \alpha_3 | - | | | | | | = 0.210`, | - | | | | | | ` | - | | | | | | \alpha_4 | - | | | | | | = 0.630`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_5 = 1`, | - | | | | | | :ma | - | | | | | | th:`\alph | - | | | | | | a_6 = 1`, | - | | | | | | | - | | | | | | `\gamma_1 | - | | | | | | = 0.25`, | - | | | | | | `\ | - | | | | | | gamma_2 = | - | | | | | | -0.104`, | - | | | | | | ` | - | | | | | | \gamma_3 | - | | | | | | = 0.104`, | - | | | | | | `\ | - | | | | | | gamma_4 = | - | | | | | | -0.036`, | - | | | | | | :ma | - | | | | | | th:`\gamm | - | | | | | | a_5 = 0`, | - | | | | | | :ma | - | | | | | | th:`\gamm | - | | | | | | a_6 = 0`, | - | | | | | | | - | | | | | | `a_{2,1} | - | | | | | | = 1.544`, | - | | | | | | | - | | | | | | `a_{3,1} | - | | | | | | = 0.946`, | - | | | | | | | - | | | | | | `a_{3,2} | - | | | | | | = 0.255`, | - | | | | | | | - | | | | | | `a_{4,1} | - | | | | | | = 3.314`, | - | | | | | | | - | | | | | | `a_{4,2} | - | | | | | | = 2.896`, | - | | | | | | | - | | | | | | `a_{4,3} | - | | | | | | = 0.998`, | - | | | | | | | - | | | | | | `a_{5,1} | - | | | | | | = 1.221`, | - | | | | | | | - | | | | | | `a_{5,2} | - | | | | | | = 6.019`, | - | | | | | | ` | - | | | | | | a_{5,3} = | - | | | | | | 12.537`, | - | | | | | | ` | - | | | | | | a_{5,4} = | - | | | | | | -0.687`, | - | | | | | | `a | - | | | | | | _{6,1} = | - | | | | | | a_{5,1}`, | - | | | | | | `a | - | | | | | | _{6,2} = | - | | | | | | a_{5,2}`, | - | | | | | | `a | - | | | | | | _{6,3} = | - | | | | | | a_{5,3}`, | - | | | | | | `a | - | | | | | | _{6,4} = | - | | | | | | a_{5,4}`, | - | | | | | | :m | - | | | | | | ath:`a_{6 | - | | | | | | ,5} = 1`, | - | | | | | | ` | - | | | | | | c_{2,1} = | - | | | | | | -5.668`, | - | | | | | | ` | - | | | | | | c_{3,1} = | - | | | | | | -2.430`, | - | | | | | | ` | - | | | | | | c_{3,2} = | - | | | | | | -0.206`, | - | | | | | | ` | - | | | | | | c_{4,1} = | - | | | | | | -0.107`, | - | | | | | | ` | - | | | | | | c_{4,2} = | - | | | | | | -9.594`, | - | | | | | | ` | - | | | | | | c_{4,3} = | - | | | | | | -20.47`, | - | | | | | | | - | | | | | | `c_{5,1} | - | | | | | | = 7.496`, | - | | | | | | ` | - | | | | | | c_{5,2} = | - | | | | | | -0.124`, | - | | | | | | :mat | - | | | | | | h:`c_{5,3 | - | | | | | | } = -34`, | - | | | | | | ` | - | | | | | | c_{5,4} = | - | | | | | | 11.708`, | - | | | | | | | - | | | | | | `c_{6,1} | - | | | | | | = 8.083`, | - | | | | | | ` | - | | | | | | c_{6,2} = | - | | | | | | -7.981`, | - | | | | | | `c | - | | | | | | _{6,3} = | - | | | | | | -31.521`, | - | | | | | | ` | - | | | | | | c_{6,4} = | - | | | | | | 16.319`, | - | | | | | | ` | - | | | | | | c_{6,5} = | - | | | | | | -6.058`, | - | | | | | | :mat | - | | | | | | h:`m_1 = | - | | | | | | a_{5,1}`, | - | | | | | | :mat | - | | | | | | h:`m_2 = | - | | | | | | a_{5,2}`, | - | | | | | | :mat | - | | | | | | h:`m_3 = | - | | | | | | a_{5,3}`, | - | | | | | | :mat | - | | | | | | h:`m_4 = | - | | | | | | a_{5,4}`, | - | | | | | | ` | - | | | | | | m_5 = 1`, | - | | | | | | ` | - | | | | | | m_6 = 1`, | - | | | | | | ` | - | | | | | | e_1 = 0`, | - | | | | | | ` | - | | | | | | e_2 = 0`, | - | | | | | | ` | - | | | | | | e_3 = 0`, | - | | | | | | ` | - | | | | | | e_4 = 0`, | - | | | | | | ` | - | | | | | | e_5 = 0`, | - | | | | | | | - | | | | | | `e_6 = 1` | - +---------+-----------+----------+-------+-----------+-----------+ - | | | | | | | - +---------+-----------+----------+-------+-----------+-----------+ diff --git a/drv/general_passivespc.f90 b/drv/general_passivespc.f90 new file mode 100644 index 0000000..cb85c16 --- /dev/null +++ b/drv/general_passivespc.f90 @@ -0,0 +1,78 @@ +PROGRAM KPP_ROOT_Driver + +!~~~> Global variables and routines + USE KPP_ROOT_Model + USE KPP_ROOT_Initialize, ONLY: Initialize + +!~~~> Local variables + KPP_REAL :: T, DVAL(NSPEC) + KPP_REAL :: RSTATE(20) + INTEGER :: i + +!~~~> Control (in) arguments for the integration +!~~~> These are set to zero by default, which will invoke default behavior + INTEGER :: ICNTRL(20) + KPP_REAL :: RCNTRL(20) + + ICNTRL = 0 + RCNTRL = 0.d0 + +!~~~> Initialization + STEPMIN = 0.0d0 + STEPMAX = 0.0d0 + + DO i=1,NVAR + RTOL(i) = 1.0d-4 + ATOL(i) = 1.0d-3 + END DO + +!~~~> Set default species concentrations +!~~~> Species having a greater ATOL than PassiveSpc_ATOL_Threshold +!~~~> will be considered passive and not be included in certain +!~~~> calculations (such as the Rosenbrock error norm) + CALL Initialize( PassiveSpc_ATOL_Threshold = 1.0d25 ) + +!~~~> Open log file for write + CALL InitSaveData() + +!~~~> Time loop + T = TSTART +kron: DO WHILE (T < TEND) + + TIME = T + +!~~~> Write values of monitored species at each iteration + CALL GetMass( C, DVAL ) + WRITE(6,991) (T-TSTART)/(TEND-TSTART)*100, T, & + ( TRIM(SPC_NAMES(MONITOR(i))), & + C(MONITOR(i))/CFACTOR, i=1,NMONITOR ) + CALL SaveData() + +!~~~> Update sunlight intensity and reaction rates +!~~~> before calling the integrator. + CALL Update_SUN() + CALL Update_RCONST() + +!~~~> Call the integrator + CALL INTEGRATE( TIN = T, & + TOUT = T+DT, & + ICNTRL_U = ICNTRL, & + RCNTRL_U = RCNTRL, & + RSTATUS_U = RSTATE ) + T = RSTATE(1) + + END DO kron +!~~~> End Time loop + +!~~~> Write final values of monitored species and close log file + CALL GetMass( C, DVAL ) + WRITE(6,991) (T-TSTART)/(TEND-TSTART)*100, T, & + ( TRIM(SPC_NAMES(MONITOR(i))), & + C(MONITOR(i))/CFACTOR, i=1,NMONITOR ) + TIME = T + CALL SaveData() + CALL CloseSaveData() + +991 FORMAT(F6.1,'%. T=',E9.3,2X,200(A,'=',E11.4,'; ')) + +END PROGRAM KPP_ROOT_Driver diff --git a/int/dvode.f b/int/dvode.f index e120543..2a2811a 100644 --- a/int/dvode.f +++ b/int/dvode.f @@ -1178,7 +1178,7 @@ SUBROUTINE DVODE (F, NEQ, Y, T, TOUT, ITOL, RelTol, AbsTol, ITASK, C On return, DVSTEP sets JSTART = 1. C JSV = Integer flag for Jacobian saving, = sign(MF). C KFLAG = A completion code from DVSTEP with the following meanings.. -C 0 the step was succesful. +C 0 the step was successful. C -1 the requested error could not be achieved. C -2 corrector convergence could not be achieved. C -3, -4 fatal error in VNLS (can not occur here). diff --git a/int/feuler.f90 b/int/feuler.f90 index 73ba093..0e1ac59 100644 --- a/int/feuler.f90 +++ b/int/feuler.f90 @@ -178,7 +178,7 @@ SUBROUTINE ForwardEuler( N, Y, Tstart, Tend, ICNTRL, IERR ) ! Return updated concentrations Y = Ynew - ! Succesful exit + ! Successful exit IERR = 1 END SUBROUTINE ForwardEuler diff --git a/int/rosenbrock.f b/int/rosenbrock.f index 5ea0090..a40eb91 100644 --- a/int/rosenbrock.f +++ b/int/rosenbrock.f @@ -601,7 +601,7 @@ SUBROUTINE RosenbrockIntegrator(Y,Tstart,Tend,T, END DO ! Time loop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful RETURN diff --git a/int/rosenbrock.f90 b/int/rosenbrock.f90 index 477aac7..baf1ef6 100644 --- a/int/rosenbrock.f90 +++ b/int/rosenbrock.f90 @@ -166,7 +166,7 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & !- RCNTRL(1:20) = real inputs parameters !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! -!~~~> OUTPUT ARGUMENTS: +!~~~> OUTPUT ARGUMENTS: ! !- Y(N) -> vector of final states (at T->Tend) !- ISTATUS(1:20) -> integer output parameters @@ -176,56 +176,66 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & ! failure (negative value) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! -!~~~> INPUT PARAMETERS: +!~~~> INPUT PARAMETERS: ! ! Note: For input parameters equal to zero the default values of the -! corresponding variables are used. +! corresponding variables are used. ! -! ICNTRL(1) = 1: F = F(y) Independent of T (AUTONOMOUS) -! = 0: F = F(t,y) Depends on T (NON-AUTONOMOUS) +! ICNTRL(1) -> Specify time-dependence of the function to be integrated +! = 0 : F = F(t,y) Depends on T (NON-AUTONOMOUS) +! = 1 : F = F(y) Independent of T (AUTONOMOUS) ! -! ICNTRL(2) = 0: AbsTol, RelTol are N-dimensional vectors -! = 1: AbsTol, RelTol are scalars +! ICNTRL(2) -> Specify vector or scalar tolerances +! = 0 : AbsTol, RelTol are N-dimensional vectors +! = 1 : AbsTol, RelTol are scalars ! -! ICNTRL(3) -> selection of a particular Rosenbrock method -! = 0 : Rodas3 (default) -! = 1 : Ros2 -! = 2 : Ros3 -! = 3 : Ros4 -! = 4 : Rodas3 -! = 5 : Rodas4 -! = 6 : Rang3 -! = 7 : Rodas3.1 +! ICNTRL(3) -> Select a particular Rosenbrock method +! = 0 : Rodas3 (default) +! = 1 : Ros2 +! = 2 : Ros3 +! = 3 : Ros4 +! = 4 : Rodas3 +! = 5 : Rodas4 +! = 6 : Rang3 +! = 7 : Rodas3.1 ! -! ICNTRL(4) -> maximum number of integration steps -! For ICNTRL(4)=0) the default value of 200000 is used +! ICNTRL(4) -> Specify maximum number of integration steps +! = 0 : Use up to 20000 integration steps (default) +! = X : Use up to X integration steps (X = any integer) ! -! ICNTRL(15) -> Toggles calling of Update_* functions w/in the integrator -! = -1 : Do not call Update_* functions within the integrator -! = 0 : Status quo -! = 1 : Call Update_RCONST from within the integrator -! = 2 : Call Update_PHOTO from within the integrator -! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. -! = 4 : Call Update_SUN from within the integrator -! = 5 : Call Update_SUN and Update_RCONST from within the int. -! = 6 : Call Update_SUN and Update_PHOTO from within the int. -! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. +! ICNTRL(15) -> Toggle calling of Update_* functions w/in the integrator +! = -1 : Do not call Update_* functions within the integrator +! = 0 : Status quo +! = 1 : Call Update_RCONST from within the integrator +! = 2 : Call Update_PHOTO from within the integrator +! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. +! = 4 : Call Update_SUN from within the integrator +! = 5 : Call Update_SUN and Update_RCONST from within the int. +! = 6 : Call Update_SUN and Update_PHOTO from within the int. +! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. ! -! ICNTRL(16) -> -! = 0 : allow negative concentrations (default) -! = 1 : set negative concentrations to zero +! ICNTRL(16) -> Specify how negative concentrations are handled +! = 0 : Allow negative concentrations (default) +! = 1 : Aet negative concentrations to zero +! +! RCNTRL(1) -> Hmin, lower bound for the integration step size. +! It is strongly recommended to keep Hmin = ZERO ! -! RCNTRL(1) -> Hmin, lower bound for the integration step size -! It is strongly recommended to keep Hmin = ZERO ! RCNTRL(2) -> Hmax, upper bound for the integration step size +! ! RCNTRL(3) -> Hstart, starting value for the integration step size ! -! RCNTRL(4) -> FacMin, lower bound on step decrease factor (default=0.2) -! RCNTRL(5) -> FacMax, upper bound on step increase factor (default=6) +! RCNTRL(4) -> FacMin, lower bound on step decrease factor +! (default = 0.2) +! +! RCNTRL(5) -> FacMax, upper bound on step increase factor +! (default = 6) +! ! RCNTRL(6) -> FacRej, step decrease factor after multiple rejections -! (default=0.1) +! (default = 0.1) +! ! RCNTRL(7) -> FacSafe, by which the new step is slightly smaller -! than the predicted value (default=0.9) +! than the predicted value (default = 0.9) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! ! @@ -284,7 +294,7 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & KPP_REAL :: Roundoff, FacMin, FacMax, FacRej, FacSafe KPP_REAL :: Hmin, Hmax, Hstart KPP_REAL :: Texit - INTEGER :: i, UplimTol, Max_no_steps + INTEGER :: i, UplimTol, Max_no_steps, ErrNormSpcCount LOGICAL :: Autonomous, VectorTol !~~~> Parameters KPP_REAL, PARAMETER :: ZERO = 0.0_dp, ONE = 1.0_dp @@ -297,8 +307,8 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & !~~~> Autonomous (1) or time dependent ODE (0). Default is time dependent. Autonomous = .NOT.(ICNTRL(1) == 0) -!~~~> For Scalar tolerances (ICNTRL(2).NE.0) the code uses AbsTol(1) and RelTol(1) -! For Vector tolerances (ICNTRL(2) == 0) the code uses AbsTol(1:N) and RelTol(1:N) +!~~~> For Scalar tolerances (ICNTRL(2).NE.0), use AbsTol(1) and RelTol(1) +!~~~> For Vector tolerances (ICNTRL(2) == 0), use AbsTol(1:N) and RelTol(1:N) IF (ICNTRL(2) == 0) THEN VectorTol = .TRUE. UplimTol = N @@ -329,7 +339,7 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & RETURN END SELECT -!~~~> The maximum number of steps admitted +!~~~> The maximum number of steps admitted IF (ICNTRL(4) == 0) THEN Max_no_steps = 200000 ELSEIF (ICNTRL(4) > 0) THEN @@ -670,7 +680,7 @@ SUBROUTINE ros_Integrator (Y, Tstart, Tend, T, & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_Integrator @@ -681,31 +691,59 @@ KPP_REAL FUNCTION ros_ErrorNorm ( Y, Ynew, Yerr, & AbsTol, RelTol, VectorTol ) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !~~~> Computes the "scaled norm" of the error vector Yerr +!~~~> +!~~~> Now uses separate loops for scalar and vector tolerances, +!~~~> as this facilitates loop vectorization for better performance. +!~~~> +!~~~> Also uses NonPassiveSpc_Count and NonPassiveSpc_Indices (constructed +!~~~> in Initialize), so that we can exclude "passive" (e.g. prod/loss) +!~~~> species from the error norm computation. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPLICIT NONE ! Input arguments - KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), & - Yerr(N), AbsTol(N), RelTol(N) + KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), Yerr(N), AbsTol(N), RelTol(N) LOGICAL, INTENT(IN) :: VectorTol ! Local variables KPP_REAL :: Err, Scale, Ymax - INTEGER :: i - KPP_REAL, PARAMETER :: ZERO = 0.0_dp + INTEGER :: I, IDX Err = ZERO - DO i=1,N - Ymax = MAX(ABS(Y(i)),ABS(Ynew(i))) - IF (VectorTol) THEN - Scale = AbsTol(i)+RelTol(i)*Ymax - ELSE - Scale = AbsTol(1)+RelTol(1)*Ymax - END IF - Err = Err+(Yerr(i)/Scale)**2 - END DO - Err = SQRT(Err/N) - ros_ErrorNorm = MAX(Err,1.0d-10) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Vector Tolerances (per-species AbsTol & RelTol) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IF ( VectorTol ) THEN + + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(I) + RelTol(I) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) + RETURN + + ENDIF + + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Scalar Tolerance (same AbsTol & RelTol for all species) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(1) + RelTol(1) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) END FUNCTION ros_ErrorNorm diff --git a/int/rosenbrock.m b/int/rosenbrock.m index 25e73e6..4bfde12 100644 --- a/int/rosenbrock.m +++ b/int/rosenbrock.m @@ -510,7 +510,7 @@ end % TimeLoop -%~~~> Succesful exit +%~~~> Successful exit IERR = 1; %~~~> The integration was successful return diff --git a/int/rosenbrock_adj.c b/int/rosenbrock_adj.c index cf0db61..246f223 100644 --- a/int/rosenbrock_adj.c +++ b/int/rosenbrock_adj.c @@ -1173,7 +1173,7 @@ int ros_FwdInt ( KPP_REAL Y[], KPP_REAL Tstart, KPP_REAL Tend, KPP_REAL T, free(Ystage); } -/*~~~> Succesful exit */ +/*~~~> Successful exit */ return 1; /*~~~> The integration was successful */ } /* End of ros_FwdInt */ @@ -1316,7 +1316,7 @@ int ros_DadjInt ( int NADJ, KPP_REAL Lambda[][NVAR], KPP_REAL Tstart, } /* End of TimeLoop */ /*~~~> Save last state */ - /*~~~> Succesful exit */ + /*~~~> Successful exit */ return 1; /*~~~> The integration was successful */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ @@ -1557,7 +1557,7 @@ int ros_CadjInt ( int NADJ, KPP_REAL Y[][NVAR], KPP_REAL Tstart, KPP_REAL Tend, } /* End of TimeLoop */ - /*~~~> Succesful exit */ + /*~~~> Successful exit */ return 1; /*~~~> The integration was successful */ } /* End of ros_CadjInt */ @@ -1738,7 +1738,7 @@ int ros_SimpleCadjInt ( int NADJ, KPP_REAL Y[][NVAR], KPP_REAL Tstart, } } /* End of TimeLoop */ -/*~~~> Succesful exit */ +/*~~~> Successful exit */ return 1; /*~~~> The integration was successful */ } /* End of ros_SimpleCadjInt */ diff --git a/int/rosenbrock_adj.f90 b/int/rosenbrock_adj.f90 index 28c2997..9e05eeb 100644 --- a/int/rosenbrock_adj.f90 +++ b/int/rosenbrock_adj.f90 @@ -232,76 +232,84 @@ SUBROUTINE RosenbrockADJ( Y, NADJ, Lambda, & !~~~> INPUT PARAMETERS: ! ! Note: For input parameters equal to zero the default values of the -! corresponding variables are used. +! corresponding variables are used. ! -! ICNTRL(1) = 1: F = F(y) Independent of T (AUTONOMOUS) -! = 0: F = F(t,y) Depends on T (NON-AUTONOMOUS) +! ICNTRL(1) -> Specify time-dependence of the function to be integrated +! = 0 : F = F(t,y) Depends on T (NON-AUTONOMOUS) +! = 1 : F = F(y) Independent of T (AUTONOMOUS) ! -! ICNTRL(2) = 0: AbsTol, RelTol are NVAR-dimensional vectors -! = 1: AbsTol, RelTol are scalars +! ICNTRL(2) -> Specify vector or scalar tolerances +! = 0 : AbsTol, RelTol are N-dimensional vectors +! = 1 : AbsTol, RelTol are scalars ! -! ICNTRL(3) -> selection of a particular Rosenbrock method -! = 0 : default method is Rodas3 -! = 1 : method is Ros2 -! = 2 : method is Ros3 -! = 3 : method is Ros4 -! = 4 : method is Rodas3 -! = 5 : method is Rodas4 -! = 7 : method is Rodas3.1 +! ICNTRL(3) -> Select a particular Rosenbrock method +! = 0 : Rodas3 (default) +! = 1 : Ros2 +! = 2 : Ros3 +! = 3 : Ros4 +! = 4 : Rodas3 +! = 5 : Rodas4 +! = 6 : Rang3 +! = 7 : Rodas3.1 ! -! ICNTRL(4) -> maximum number of integration steps -! For ICNTRL(4)=0) the default value of BUFSIZE is used +! ICNTRL(4) -> Specify maximum number of integration steps +! = 0 : Use up to BUFSIZE integration steps (default=200000) +! = X : Use up to X integration steps (X = any integer) ! -! ICNTRL(6) -> selection of a particular Rosenbrock method for the -! continuous adjoint integration - for cts adjoint it -! can be different than the forward method ICNTRL(3) -! Note 1: to avoid interpolation errors (which can be huge!) -! it is recommended to use only ICNTRL(7) = 2 or 4 -! Note 2: the performance of the full continuous adjoint -! strongly depends on the forward solution accuracy Abs/RelTol +! ICNTRL(6) -> Selection of a particular Rosenbrock method for the continuous +! adjoint integration; this may be different than the forward +! method specified in ICNTRL(3). ! -! ICNTRL(7) -> Type of adjoint algorithm -! = 0 : default is discrete adjoint ( of method ICNTRL(3) ) -! = 1 : no adjoint -! = 2 : discrete adjoint ( of method ICNTRL(3) ) -! = 3 : fully adaptive continuous adjoint ( with method ICNTRL(6) ) -! = 4 : simplified continuous adjoint ( with method ICNTRL(6) ) +! Note 1: to avoid interpolation errors (which can be huge!) +! it is recommended to use only ICNTRL(7) = 2 or 4 ! -! ICNTRL(8) -> checkpointing the LU factorization at each step: -! ICNTRL(8)=0 : do *not* save LU factorization (the default) -! ICNTRL(8)=1 : save LU factorization -! Note: if ICNTRL(7)=1 the LU factorization is *not* saved +! Note 2: the performance of the full continuous adjoint +! strongly depends on the forward solution accuracy Abs/RelTol ! -! ICNTRL(15) -> Toggles calling of Update_* functions w/in the integrator -! = -1 : Do not call Update_* functions within the integrator -! = 0 : Status quo -! = 1 : Call Update_RCONST from within the integrator -! = 2 : Call Update_PHOTO from within the integrator -! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. -! = 4 : Call Update_SUN from within the integrator -! = 5 : Call Update_SUN and Update_RCONST from within the int. -! = 6 : Call Update_SUN and Update_PHOTO from within the int. -! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. +! ICNTRL(7) -> Type of adjoint algorithm +! = 0 : default is discrete adjoint ( of method ICNTRL(3) ) +! = 1 : no adjoint +! = 2 : discrete adjoint ( of method ICNTRL(3) ) +! = 3 : fully adaptive continuous adjoint ( with method ICNTRL(6) ) +! = 4 : simplified continuous adjoint ( with method ICNTRL(6) ) +! +! ICNTRL(8) -> Checkpoint the LU factorization at each step? +! = 0 : Do *not* save LU factorization (the default) +! = 1 : Save LU factorization at each step +! +! Note: if ICNTRL(7)=1 the LU factorization is *not* saved +! +! ICNTRL(15) -> Toggle calling of Update_* functions w/in the integrator +! = -1 : Do not call Update_* functions within the integrator +! = 0 : Status quo +! = 1 : Call Update_RCONST from within the integrator +! = 2 : Call Update_PHOTO from within the integrator +! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. +! = 4 : Call Update_SUN from within the integrator +! = 5 : Call Update_SUN and Update_RCONST from within the int. +! = 6 : Call Update_SUN and Update_PHOTO from within the int. +! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. ! !~~~> Real input parameters: ! -! RCNTRL(1) -> Hmin, lower bound for the integration step size -! It is strongly recommended to keep Hmin = ZERO +! RCNTRL(1) -> Hmin, lower bound for the integration step size. +! It is strongly recommended to keep Hmin = ZERO ! ! RCNTRL(2) -> Hmax, upper bound for the integration step size ! ! RCNTRL(3) -> Hstart, starting value for the integration step size ! -! RCNTRL(4) -> FacMin, lower bound on step decrease factor (default=0.2) +! RCNTRL(4) -> FacMin, lower bound on step decrease factor +! (default = 0.2) ! -! RCNTRL(5) -> FacMax, upper bound on step increase factor (default=6) +! RCNTRL(5) -> FacMax, upper bound on step increase factor +! (default = 6) ! ! RCNTRL(6) -> FacRej, step decrease factor after multiple rejections -! (default=0.1) +! (default = 0.1) ! ! RCNTRL(7) -> FacSafe, by which the new step is slightly smaller -! than the predicted value (default=0.9) -! +! than the predicted value (default = 0.9) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! !~~~> OUTPUT PARAMETERS: @@ -1133,7 +1141,7 @@ SUBROUTINE ros_FwdInt ( Y, & END IF END IF -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_FwdInt @@ -1300,7 +1308,7 @@ SUBROUTINE ros_DadjInt ( NADJ, Lambda, & !~~~> Save last state -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1554,7 +1562,7 @@ SUBROUTINE ros_CadjInt ( & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_CadjInt @@ -1739,40 +1747,71 @@ SUBROUTINE ros_SimpleCadjInt ( & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_SimpleCadjInt + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ KPP_REAL FUNCTION ros_ErrorNorm ( Y, Ynew, Yerr, & - AbsTol, RelTol, VectorTol ) + AbsTol, RelTol, VectorTol ) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !~~~> Computes the "scaled norm" of the error vector Yerr +!~~~> +!~~~> Now uses separate loops for scalar and vector tolerances, +!~~~> as this facilitates loop vectorization for better performance. +!~~~> +!~~~> Also uses NonPassiveSpc_Count and NonPassiveSpc_Indices (constructed +!~~~> in Initialize), so that we can exclude "passive" (e.g. prod/loss) +!~~~> species from the error norm computation. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPLICIT NONE ! Input arguments - KPP_REAL, INTENT(IN) :: Y(NVAR), Ynew(NVAR), & - Yerr(NVAR), AbsTol(NVAR), RelTol(NVAR) + KPP_REAL, INTENT(IN) :: Y(NVAR), Ynew(NVAR), Yerr(NVAR) + KPP_REAL, INTENT(IN) :: AbsTol(NVAR), RelTol(NVAR) LOGICAL, INTENT(IN) :: VectorTol ! Local variables KPP_REAL :: Err, Scale, Ymax - INTEGER :: i + INTEGER :: I, IDX Err = ZERO - DO i=1,NVAR - Ymax = MAX(ABS(Y(i)),ABS(Ynew(i))) - IF (VectorTol) THEN - Scale = AbsTol(i)+RelTol(i)*Ymax - ELSE - Scale = AbsTol(1)+RelTol(1)*Ymax - END IF - Err = Err+(Yerr(i)/Scale)**2 - END DO - Err = SQRT(Err/NVAR) - ros_ErrorNorm = MAX(Err,1.0d-10) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Vector Tolerances (per-species AbsTol & RelTol) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IF ( VectorTol ) THEN + + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(I) + RelTol(I) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) + RETURN + + ENDIF + + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Scalar Tolerance (same AbsTol & RelTol for all species) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(1) + RelTol(1) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) END FUNCTION ros_ErrorNorm diff --git a/int/rosenbrock_autoreduce.f90 b/int/rosenbrock_autoreduce.f90 index 6b0805b..5736529 100644 --- a/int/rosenbrock_autoreduce.f90 +++ b/int/rosenbrock_autoreduce.f90 @@ -184,60 +184,78 @@ SUBROUTINE Rosenbrock(N,Y,Tstart,Tend, & !~~~> INPUT PARAMETERS: ! ! Note: For input parameters equal to zero the default values of the -! corresponding variables are used. +! corresponding variables are used. ! -! ICNTRL(1) = 1: F = F(y) Independent of T (AUTONOMOUS) -! = 0: F = F(t,y) Depends on T (NON-AUTONOMOUS) +! ICNTRL(1) -> Specify time-dependence of the function to be integrated +! = 0 : F = F(t,y) Depends on T (NON-AUTONOMOUS) +! = 1 : F = F(y) Independent of T (AUTONOMOUS) ! -! ICNTRL(2) = 0: AbsTol, RelTol are N-dimensional vectors -! = 1: AbsTol, RelTol are scalars +! ICNTRL(2) -> Specify vector or scalar tolerances +! = 0 : AbsTol, RelTol are N-dimensional vectors +! = 1 : AbsTol, RelTol are scalars ! -! ICNTRL(3) -> selection of a particular Rosenbrock method -! = 0 : Rodas3 (default) -! = 1 : Ros2 -! = 2 : Ros3 -! = 3 : Ros4 -! = 4 : Rodas3 -! = 5 : Rodas4 -! = 6 : Rang3 -! = 7 : Rodas3.1 +! ICNTRL(3) -> Select a particular Rosenbrock method +! = 0 : Rodas3 (default) +! = 1 : Ros2 +! = 2 : Ros3 +! = 3 : Ros4 +! = 4 : Rodas3 +! = 5 : Rodas4 +! = 6 : Rang3 +! = 7 : Rodas3.1 ! -! ICNTRL(4) -> maximum number of integration steps -! For ICNTRL(4)=0) the default value of 200000 is used +! ICNTRL(4) -> Specify maximum number of integration steps +! = 0 : Use up to 20000 integration steps (default) +! = X : Use up to X integration steps (X = any integer)! +! +! ICNTRL(12) -> Use auto-reduce solver? +! = 0 : Do not use the auto-reduction solver +! = 1 : Use the auto reduction solver. Set the threshold in RCNTRL(12) +! +! ICNTRL(13) -> Append slow species when auto-reducing? +! = 0 : Do not append slow species +! = 1 : Append slow species ! -! ICNTRL(12) -> use auto-reduce solver? set threshold in RCNTRL(12) -! ICNTRL(13) -> ... append slow species when auto-reducing? ! ICNTRL(14) -> choose a target species instead for determining threshold? ! if yes, specify idx. then RCNTRL(12) is obsolete. ! -! ICNTRL(15) -> Toggles calling of Update_* functions w/in the integrator -! = -1 : Do not call Update_* functions within the integrator -! = 0 : Status quo -! = 1 : Call Update_RCONST from within the integrator -! = 2 : Call Update_PHOTO from within the integrator -! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. -! = 4 : Call Update_SUN from within the integrator -! = 5 : Call Update_SUN and Update_RCONST from within the int. -! = 6 : Call Update_SUN and Update_PHOTO from within the int. -! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. +! ICNTRL(15) -> Toggle calling of Update_* functions w/in the integrator +! = -1 : Do not call Update_* functions within the integrator +! = 0 : Status quo +! = 1 : Call Update_RCONST from within the integrator +! = 2 : Call Update_PHOTO from within the integrator +! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. +! = 4 : Call Update_SUN from within the integrator +! = 5 : Call Update_SUN and Update_RCONST from within the int. +! = 6 : Call Update_SUN and Update_PHOTO from within the int. +! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. +! +! ICNTRL(16) -> Specify how negative concentrations are handled +! = 0 : Allow negative concentrations (default) +! = 1 : Aet negative concentrations to zero ! -! ICNTRL(16) -> -! = 0 : allow negative concentrations (default) -! = 1 : set negative concentrations to zero +! RCNTRL(1) -> Hmin, lower bound for the integration step size. +! It is strongly recommended to keep Hmin = ZERO ! -! RCNTRL(1) -> Hmin, lower bound for the integration step size -! It is strongly recommended to keep Hmin = ZERO ! RCNTRL(2) -> Hmax, upper bound for the integration step size +! ! RCNTRL(3) -> Hstart, starting value for the integration step size ! -! RCNTRL(4) -> FacMin, lower bound on step decrease factor (default=0.2) -! RCNTRL(5) -> FacMax, upper bound on step increase factor (default=6) +! RCNTRL(4) -> FacMin, lower bound on step decrease factor +! (default = 0.2) +! +! RCNTRL(5) -> FacMax, upper bound on step increase factor +! (default = 6) +! ! RCNTRL(6) -> FacRej, step decrease factor after multiple rejections -! (default=0.1) +! (default = 0.1) +! ! RCNTRL(7) -> FacSafe, by which the new step is slightly smaller -! than the predicted value (default=0.9) +! than the predicted value (default = 0.9) +! +! RCNTRL(12) -> Threshold for auto-reduction, when ICNTRL(12) is set +! (default=100) ! -! RCNTRL(12) -> threshold for auto-reduction (req. ICNTRL(12)) (default=100) ! RCNTRL(14) -> AR threshold ratio (default=0.01) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! @@ -745,7 +763,7 @@ SUBROUTINE ros_Integrator (Y, Tstart, Tend, T, & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_Integrator @@ -1674,36 +1692,65 @@ SUBROUTINE AutoReduce_1stOrder(i,Y,P,k,Ti,Tf) Y = term+(Y-term)*exp(-k*(Tf-Ti)) END SUBROUTINE AutoReduce_1stOrder + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ KPP_REAL FUNCTION ros_ErrorNorm ( Y, Ynew, Yerr, & AbsTol, RelTol, VectorTol ) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !~~~> Computes the "scaled norm" of the error vector Yerr +!~~~> +!~~~> Now uses separate loops for scalar and vector tolerances, +!~~~> as this facilitates loop vectorization for better performance. +!~~~> +!~~~> Also uses NonPassiveSpc_Count and NonPassiveSpc_Indices (constructed +!~~~> in Initialize), so that we can exclude "passive" (e.g. prod/loss) +!~~~> species from the error norm computation. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPLICIT NONE ! Input arguments - KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), & - Yerr(N), AbsTol(N), RelTol(N) + KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), Yerr(N), AbsTol(N), RelTol(N) LOGICAL, INTENT(IN) :: VectorTol ! Local variables KPP_REAL :: Err, Scale, Ymax - INTEGER :: i - KPP_REAL, PARAMETER :: ZERO = 0.0_dp + INTEGER :: I, IDX Err = ZERO - DO i=1,N - Ymax = MAX(ABS(Y(i)),ABS(Ynew(i))) - IF (VectorTol) THEN - Scale = AbsTol(i)+RelTol(i)*Ymax - ELSE - Scale = AbsTol(1)+RelTol(1)*Ymax - END IF - Err = Err+(Yerr(i)/Scale)**2 - END DO - Err = SQRT(Err/N) - ros_ErrorNorm = MAX(Err,1.0d-10) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Vector Tolerances (per-species AbsTol & RelTol) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IF ( VectorTol ) THEN + + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(I) + RelTol(I) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) + RETURN + + ENDIF + + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Scalar Tolerance (same AbsTol & RelTol for all species) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(1) + RelTol(1) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) END FUNCTION ros_ErrorNorm diff --git a/int/rosenbrock_h211b_qssa.f90 b/int/rosenbrock_h211b_qssa.f90 index 48ae8fe..f349dbd 100644 --- a/int/rosenbrock_h211b_qssa.f90 +++ b/int/rosenbrock_h211b_qssa.f90 @@ -929,7 +929,7 @@ SUBROUTINE ros_Integrator (Y, Tstart, Tend, T, & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_Integrator diff --git a/int/rosenbrock_tlm.f90 b/int/rosenbrock_tlm.f90 index 6cebbde..00e5654 100644 --- a/int/rosenbrock_tlm.f90 +++ b/int/rosenbrock_tlm.f90 @@ -219,52 +219,63 @@ SUBROUTINE RosenbrockTLM(N,Y,NTLM,Y_tlm, & !~~~> INPUT PARAMETERS: ! ! Note: For input parameters equal to zero the default values of the -! corresponding variables are used. +! corresponding variables are used. ! -! ICNTRL(1) = 1: F = F(y) Independent of T (AUTONOMOUS) -! = 0: F = F(t,y) Depends on T (NON-AUTONOMOUS) +! ICNTRL(1) -> Specify time-dependence of the function to be integrated +! = 0 : F = F(t,y) Depends on T (NON-AUTONOMOUS) +! = 1 : F = F(y) Independent of T (AUTONOMOUS) ! -! ICNTRL(2) = 0: AbsTol, RelTol are N-dimensional vectors -! = 1: AbsTol, RelTol are scalars +! ICNTRL(2) -> Specify vector or scalar tolerances +! = 0 : AbsTol, RelTol are N-dimensional vectors +! = 1 : AbsTol, RelTol are scalars ! -! ICNTRL(3) -> selection of a particular Rosenbrock method -! = 0 : default method is Rodas3 -! = 1 : method is Ros2 -! = 2 : method is Ros3 -! = 3 : method is Ros4 -! = 4 : method is Rodas3 -! = 5 : method is Rodas4 -! = 7 : method is Rodas3.1 +! ICNTRL(3) -> Select a particular Rosenbrock method +! = 0 : Rodas3 (default) +! = 1 : Ros2 +! = 2 : Ros3 +! = 3 : Ros4 +! = 4 : Rodas3 +! = 5 : Rodas4 +! = 6 : Rang3 +! = 7 : Rodas3.1 ! -! ICNTRL(4) -> maximum number of integration steps -! For ICNTRL(4)=0) the default value of 200000 is used +! ICNTRL(4) -> Specify maximum number of integration steps +! = 0 : Use up to 20000 integration steps (default) +! = X : Use up to X integration steps (X = any integer) ! -! ICNTRL(12) -> switch for TLM truncation error control -! ICNTRL(12) = 0: TLM error is not used -! ICNTRL(12) = 1: TLM error is computed and used +! ICNTRL(12) -> Switch for TLM truncation error control +! = 0 : TLM error is not used +! = 1 : TLM error is computed and used +! +! ICNTRL(15) -> Toggle calling of Update_* functions w/in the integrator +! = -1 : Do not call Update_* functions within the integrator +! = 0 : Status quo +! = 1 : Call Update_RCONST from within the integrator +! = 2 : Call Update_PHOTO from within the integrator +! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. +! = 4 : Call Update_SUN from within the integrator +! = 5 : Call Update_SUN and Update_RCONST from within the int. +! = 6 : Call Update_SUN and Update_PHOTO from within the int. +! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. + +! RCNTRL(1) -> Hmin, lower bound for the integration step size. +! It is strongly recommended to keep Hmin = ZERO ! -! ICNTRL(15) -> Toggles calling of Update_* functions w/in the integrator -! = -1 : Do not call Update_* functions within the integrator -! = 0 : Status quo -! = 1 : Call Update_RCONST from within the integrator -! = 2 : Call Update_PHOTO from within the integrator -! = 3 : Call Update_RCONST and Update_PHOTO from w/in the int. -! = 4 : Call Update_SUN from within the integrator -! = 5 : Call Update_SUN and Update_RCONST from within the int. -! = 6 : Call Update_SUN and Update_PHOTO from within the int. -! = 7 : Call Update_SUN, Update_PHOTO, Update_RCONST w/in the int. - -! RCNTRL(1) -> Hmin, lower bound for the integration step size -! It is strongly recommended to keep Hmin = ZERO ! RCNTRL(2) -> Hmax, upper bound for the integration step size +! ! RCNTRL(3) -> Hstart, starting value for the integration step size ! -! RCNTRL(4) -> FacMin, lower bound on step decrease factor (default=0.2) -! RCNTRL(5) -> FacMin,upper bound on step increase factor (default=6) +! RCNTRL(4) -> FacMin, lower bound on step decrease factor +! (default = 0.2) +! +! RCNTRL(5) -> FacMax, upper bound on step increase factor +! (default = 6) +! ! RCNTRL(6) -> FacRej, step decrease factor after multiple rejections -! (default=0.1) +! (default = 0.1) +! ! RCNTRL(7) -> FacSafe, by which the new step is slightly smaller -! than the predicted value (default=0.9) +! than the predicted value (default=0.9) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ! !~~~> OUTPUT PARAMETERS: @@ -756,7 +767,7 @@ SUBROUTINE ros_TLM_Int ( Y, NTLM, Y_tlm, & END DO TimeLoop -!~~~> Succesful exit +!~~~> Successful exit IERR = 1 !~~~> The integration was successful END SUBROUTINE ros_TLM_Int @@ -764,37 +775,66 @@ END SUBROUTINE ros_TLM_Int !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ KPP_REAL FUNCTION ros_ErrorNorm ( Y, Ynew, Yerr, & - AbsTol, RelTol, VectorTol ) + AbsTol, RelTol, VectorTol ) !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !~~~> Computes the "scaled norm" of the error vector Yerr +!~~~> +!~~~> Now uses separate loops for scalar and vector tolerances, +!~~~> as this facilitates loop vectorization for better performance. +!~~~> +!~~~> Also uses NonPassiveSpc_Count and NonPassiveSpc_Indices (constructed +!~~~> in Initialize), so that we can exclude "passive" (e.g. prod/loss) +!~~~> species from the error norm computation. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPLICIT NONE ! Input arguments - KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), & - Yerr(N), AbsTol(N), RelTol(N) + KPP_REAL, INTENT(IN) :: Y(N), Ynew(N), Yerr(N), AbsTol(N), RelTol(N) LOGICAL, INTENT(IN) :: VectorTol ! Local variables KPP_REAL :: Err, Scale, Ymax - INTEGER :: i - KPP_REAL, PARAMETER :: ZERO = 0.0d0 + INTEGER :: I, IDX Err = ZERO - DO i=1,N - Ymax = MAX(ABS(Y(i)),ABS(Ynew(i))) - IF (VectorTol) THEN - Scale = AbsTol(i)+RelTol(i)*Ymax - ELSE - Scale = AbsTol(1)+RelTol(1)*Ymax - END IF - Err = Err+(Yerr(i)/Scale)**2 - END DO - Err = SQRT(Err/N) - ros_ErrorNorm = MAX(Err,1.0d-10) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Vector Tolerances (per-species AbsTol & RelTol) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IF ( VectorTol ) THEN + + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(I) + RelTol(I) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) + RETURN + + ENDIF + + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !~~~> Scalar Tolerance (same AbsTol & RelTol for all species) + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DO IDX = 1, NonPassiveSpc_Count + I = NonPassiveSpc_Indices(IDX) + Ymax = MAX( ABS( Y(I) ), ABS( Ynew(I) ) ) + Scale = AbsTol(1) + RelTol(1) * Ymax + Err = Err + ( Yerr(I) / Scale )**2 + ENDDO + + ! Normalize the error norm by the number of non-dummy species + ! and prevent it from getting smaller than 1e-10 + Err = SQRT( Err / NonPassiveSpc_Count ) + ros_ErrorNorm = MAX( Err, 1.0d-10 ) END FUNCTION ros_ErrorNorm + !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ KPP_REAL FUNCTION ros_ErrorNorm_tlm ( Y_tlm, Ynew_tlm, Yerr_tlm, & AbsTol_tlm, RelTol_tlm, Fwd_Err, VectorTol ) diff --git a/int/runge_kutta.c b/int/runge_kutta.c index 9059fd0..7cd9935 100644 --- a/int/runge_kutta.c +++ b/int/runge_kutta.c @@ -673,6 +673,11 @@ void RK_Integrator( int N, /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + // Initialize variables to avoid compiler warnings + // -- Bob Yantosca (06 Jul 2026) + Hacc = ZERO; + ErrOld = ZERO; + /*~~~> INITIAL setting */ Tdirection = SIGN(ONE, Tend-*T); H = MIN( MAX(ABS(Hmin), ABS(Hstart)), Hmax ); diff --git a/site-lisp/kpp.el b/site-lisp/kpp.el index c7afc45..bd4c972 100644 --- a/site-lisp/kpp.el +++ b/site-lisp/kpp.el @@ -1,130 +1,257 @@ -;; kpp.el --- kpp mode for GNU Emacs -;; (c) Rolf Sander +;;; kpp.el --- Major mode for KPP (Kinetic PreProcessor) files -*- lexical-binding: t; -*- -;; To activate it, copy kpp.el to a place where emacs can find it and -;; then add "(require 'kpp)" to your .emacs startup file. - -;; Known problem: -;; ":" inside comments between reaction products confuses font-lock +;; Authors: Rolf Sander +;; Bob Yantosca (used AI to "lint") +;; Version: 1.2 +;; Keywords: languages, kpp, chemistry ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. +;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. -;; auto-start kpp-mode when loading a *.def, *.eqn, *.kpp, or *.spc file -(setq auto-mode-alist - (cons '("\\.def\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.eqn\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.kpp\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.spc\\'" . kpp-mode) auto-mode-alist)) - -;; Turn on font-lock-mode for KPP -(add-hook 'kpp-mode-hook 'font-lock-mode) - -(setq kpp-font-lock-keywords - (list - '("^\\([^=\n]*=[^:\n]*\\):[^;\n]*;" 1 font-lock-constant-face) ; reaction - ;; alternatively, use another color for rate constant: - ;; '("^\\([^=\n]*=[^:\n]*\\):\\([^;\n]*\\);" - ;; (1 font-lock-constant-face) (2 font-lock-keyword-face)) - '("<[A-z0-9_#]+>" 0 font-lock-variable-name-face t) ; equation tag - '("{[^}\n]*}" 0 font-lock-comment-face t) ; comment - '("!.*" 0 font-lock-comment-face t) ; f90 comment - '("{@[^}]+}" 0 font-lock-doc-face t) ; alternative LaTeX text - '("{$[^}]+}" 0 font-lock-string-face t) ; alternative LaTeX text - '("{&[^}]+}" 0 font-lock-builtin-face t) ; BibTeX reference - '("{%[A-z0-9#]+}" 0 font-lock-type-face t) ; marker - ;; KPP sections (Tab. 3 in thesis), commands (Tab. 13 in thesis), and - ;; fragments (Tab. 17 in thesis) - (cons (concat - "\\(#ATOMS\\|#AUTOREDUCE\\|#CHECKALL\\|#CHECK\\|#DECLARE" - "\\|#DEFFIX\\|#DEFVAR\\|#DOUBLE\\|#DRIVER\\|#DUMMYINDEX" - "\\|#ENDINLINE\\|#EQNTAGS\\|#EQUATIONS\\|#FAMILIES\\|#FUNCTION" - "\\|#GRAPH\\|#HESSIAN\\|#INCLUDE\\|#INITVALUES\\|#INLINE\\|#INTEGRATOR" - "\\|#INTFILE\\|#JACOBIAN\\|#LANGUAGE\\|#LOOKATALL\\|#LOOKAT" - "\\|#MEX\\|#MINVERSION\\|#MODEL\\|#MONITOR\\|#REORDER" - "\\|#SETFIX\\|#SETVAR\\|#STOCHASTIC\\|#STOICMAT\\|#UPPERCASEF90" - "\\|#WRITE_ATM\\|#WRITE_MAT\\|#WRITE_SPC" - ) 'font-lock-keyword-face) - '("^//.*" 0 font-lock-comment-face t) ; comment - ) -) - -; comment a region (adopted from wave-comment-region) - -(defvar kpp-comment-region "// " - "*String inserted by \\[kpp-comment-region] at start of each line in region.") +;;; Commentary: +;; +;; This package provides a major mode for editing KPP (Kinetic PreProcessor) +;; files. KPP is a software tool that assists in developing and solving +;; chemical kinetics problems. +;; +;; Installation: +;; Copy kpp.el to a directory in `load-path' and add +;; (require 'kpp) +;; to your Emacs init file (~/.emacs or ~/.emacs.d/init.el). +;; +;; File extensions automatically associated with kpp-mode: +;; .def, .eqn, .kpp, .spc + +;;; Code: + +;; --------------------------------------------------------------------------- +;; Customization group +;; --------------------------------------------------------------------------- + +(defgroup kpp nil + "Major mode for editing KPP (Kinetic PreProcessor) files." + :group 'languages + :prefix "kpp-") + +;; --------------------------------------------------------------------------- +;; User-configurable variables +;; --------------------------------------------------------------------------- + +(defcustom kpp-comment-prefix "// " + ;; Fix #10: renamed from `kpp-comment-region' to avoid collision with the + ;; function of the same name. + ;; Fix #13: changed from `defvar' with leading `*' to `defcustom'. + "String inserted by \\[kpp-comment-region] at the start of each line." + :type 'string + :group 'kpp) + +;; --------------------------------------------------------------------------- +;; Syntax table (defined once at load time; shared by all kpp buffers) +;; --------------------------------------------------------------------------- + +(defvar kpp-mode-syntax-table + ;; Fix #11: was recreated (and re-allocated) inside `kpp-mode' on every + ;; buffer visit. + (let ((st (copy-syntax-table))) + (modify-syntax-entry ?_ "w" st) ; underscore is part of a word + st) + "Syntax table for `kpp-mode'.") + +;; --------------------------------------------------------------------------- +;; Font-lock keyword specification +;; --------------------------------------------------------------------------- + +(defconst kpp-font-lock-keywords + ;; Fix #9: was a bare `setq' on an unbound symbol; `defconst' documents + ;; intent and prevents inadvertent modification. + (list + ;; Reaction: "species = products : rate_constant ;" + ;; Highlight the LHS + products (group 1) as a constant. + '("^\\([^=\n]*=[^:\n]*\\):[^;\n]*;" 1 font-lock-constant-face) + + ;; Equation tag, e.g. or + ;; Fix #2: [A-z] spans ASCII 65-122 and accidentally includes the + ;; characters [\]^_` (91-96). Use [A-Za-z] instead. + '("<[A-Za-z0-9_#]+>" 0 font-lock-variable-name-face t) + + ;; Curly-brace block comment: {comment text} + '("{[^}\n]*}" 0 font-lock-comment-face t) + + ;; Fortran-90 / KPP inline comment: ! comment to end of line + '("!.*" 0 font-lock-comment-face t) + + ;; {@...} – alternative LaTeX text + ;; '("{@[^}]+}" 0 font-lock-doc-face t) + + ;; uncertainty of rate coefficient + ;; '("{§[^}]*}" 0 font-lock-builtin-face t) + + ;; {$...} – alternative LaTeX text + ;; '("{\\$[^}]+}" 0 font-lock-doc-face t) + + ;; {&...} – BibTeX reference + ;; '("{&[^}]+}" 0 font-lock-function-name-face t) + + ;; {%...} – marker tag, e.g. {%TrG} + ;; Fix #2: same [A-z] → [A-Za-z] correction as above. + ;; '("{%[A-Za-z0-9#]+}" 0 font-lock-type-face t) + + ;; KPP sections and commands + ;; + ;; ORDERING RULE: in Emacs regex alternation (\|) the leftmost match + ;; wins. Any keyword that is a strict prefix of another must therefore + ;; appear AFTER the longer form. + ;; + ;; \> (end-of-word boundary) prevents a short keyword from matching + ;; as a prefix of an unknown longer token. + (cons (concat + "\\(" + "#ATOMS\\|#AUTOREDUCE" + "\\|#CHECKALL\\|#CHECK" ; CHECKALL before CHECK + "\\|#DEFFIX\\|#DEFVAR\\|#DOUBLE\\|#DRIVER\\|#DUMMYINDEX" + "\\|#ENDINLINE\\|#EQNTAGS\\|#EQUATIONS" + "\\|#FAMILIES\\|#FUNCTION" + "\\|#GRAPH" + "\\|#HESSIAN" + "\\|#INCLUDE\\|#INITVALUES\\|#INLINE\\|#INTEGRATOR\\|#INTFILE" + "\\|#JACOBIAN" + "\\|#LANGUAGE\\|#LOOKATALL\\|#LOOKAT" ; LOOKATALL before LOOKAT + "\\|#MEX\\|#MINVERSION\\|#MODEL\\|#MONITOR" + "\\|#REORDER" + "\\|#SETFIX\\|#SETVAR\\|#STOCHASTIC\\|#STOICMAT" + "\\|#UPPERCASEF90" + "\\)\\>") + 'font-lock-keyword-face) + + ;; LaTeX note + ;; '("//.*" 0 font-lock-string-face t) + + ;; C++-style line comment: // comment + '("^//.*" 0 font-lock-comment-face t) + + ;; Fixme + ;; '("qqq" 0 font-lock-warning-face t) + + ) + "Font-lock keyword specification for `kpp-mode'.") + +;; --------------------------------------------------------------------------- +;; Keymap +;; (defined before `define-derived-mode'; the macro detects and reuses it) +;; --------------------------------------------------------------------------- + +(defvar kpp-mode-map + (let ((map (make-sparse-keymap))) + ;; C-c ; → comment / uncomment region + (define-key map "\C-c;" #'kpp-comment-region) + ;; Fix #14: original hard-coded 8 spaces and had no docstring. + ;; Using `tab-width' respects the user/project preference and updates + ;; automatically when `tab-width' is changed locally. + (define-key map (kbd "TAB") + (lambda () + "Insert `tab-width' spaces (never a literal TAB character)." + (interactive) + (insert-char ?\s tab-width))) + map) + "Keymap for `kpp-mode'.") + +;; --------------------------------------------------------------------------- +;; Comment / uncomment a region (adapted from wave-comment-region) +;; --------------------------------------------------------------------------- (defun kpp-comment-region (beg-region end-region arg) - "Comments every line in the region. -Puts kpp-comment-region at the beginning of every line in the region. -BEG-REGION and END-REGION are args which specify the region boundaries. -With non-nil ARG, uncomments the region." + ;; Fix #10: the variable formerly named `kpp-comment-region' clashed with + ;; this function name. The variable is now `kpp-comment-prefix'. + "Comment every line in the region. +Inserts `kpp-comment-prefix' at the start of every line between +BEG-REGION and END-REGION. With non-nil ARG, uncomment instead." (interactive "*r\nP") - (let ((end-region-mark (make-marker)) (save-point (point-marker))) + (let ((end-region-mark (make-marker)) + (save-point (point-marker))) (set-marker end-region-mark end-region) (goto-char beg-region) (beginning-of-line) - (if (not arg) ;comment the region - (progn (insert kpp-comment-region) - (while (and (= (forward-line 1) 0) - (< (point) end-region-mark)) - (insert kpp-comment-region))) - (let ((com (regexp-quote kpp-comment-region))) ;uncomment the region - (if (looking-at com) - (delete-region (point) (match-end 0))) - (while (and (= (forward-line 1) 0) - (< (point) end-region-mark)) - (if (looking-at com) - (delete-region (point) (match-end 0)))))) + (if (not arg) + ;; --- comment the region --- + (progn + (insert kpp-comment-prefix) + (while (and (= (forward-line 1) 0) + (< (point) end-region-mark)) + (insert kpp-comment-prefix))) + ;; --- uncomment the region --- + (let ((com (regexp-quote kpp-comment-prefix))) + (when (looking-at com) + (delete-region (point) (match-end 0))) + (while (and (= (forward-line 1) 0) + (< (point) end-region-mark)) + (when (looking-at com) + (delete-region (point) (match-end 0)))))) (goto-char save-point) (set-marker end-region-mark nil) (set-marker save-point nil))) -(defvar kpp-mode-map () - "Keymap used in kpp mode.") +;; --------------------------------------------------------------------------- +;; Major mode definition +;; --------------------------------------------------------------------------- + +;;;###autoload +(define-derived-mode kpp-mode fundamental-mode "KPP" + ;; Fix #8: `define-derived-mode' replaces the manual boilerplate that + ;; was in the original: + ;; • calls `kill-all-local-variables' (Fix #4) + ;; • sets `major-mode' and `mode-name' + ;; • calls `use-local-map' with kpp-mode-map + ;; • calls `run-mode-hooks' + ;; • installs :syntax-table automatically + "Major mode for editing KPP (Kinetic PreProcessor) files. -(if kpp-mode-map - () - (setq kpp-mode-map (make-sparse-keymap)) - (define-key kpp-mode-map "\C-c;" 'kpp-comment-region) - ;; TAB inserts 8 spaces, not the TAB character - (define-key kpp-mode-map (kbd "TAB") - (lambda () (interactive) (insert " "))) -) +Turning on `kpp-mode' runs the hook `kpp-mode-hook'. -(defun kpp-mode () - "Major mode for editing kpp code. -Turning on kpp mode calls the value of the variable `kpp-mode-hook' -with no args, if that value is non-nil. +Known issue: `:' inside KPP inline comments (between reaction products +and the rate constant) may confuse font-lock. -Command Table: \\{kpp-mode-map}" - (interactive) - (make-local-variable 'font-lock-defaults) - (setq font-lock-defaults '((kpp-font-lock-keywords) t t)) - (make-local-variable 'comment-start) - (setq comment-start "{") - (make-local-variable 'comment-end) - (setq comment-end "}") - (use-local-map kpp-mode-map) - (setq mode-name "kpp") - (setq major-mode 'kpp-mode) - (turn-on-font-lock) - (set-syntax-table (copy-syntax-table)) - (modify-syntax-entry ?_ "w") ; the underscore can be part of a word - (auto-fill-mode 0) ; no automatic line breaks - (run-hooks 'kpp-mode-hook) -) + :syntax-table kpp-mode-syntax-table ; Fix #11: reuse pre-built table + ;; Fix #12: `setq-local' replaces the two-step + ;; `(make-local-variable ...) (setq ...)' pattern. + (setq-local font-lock-defaults '((kpp-font-lock-keywords) t t)) + ;; KPP uses { } as block-comment delimiters. + (setq-local comment-start "{ ") + (setq-local comment-end " }") + (setq-local comment-start-skip "{+\\s-*") ; added: needed by comment cmds + ;; Disable automatic line wrapping. + (auto-fill-mode 0) + ;; Fix #1 + #5: the original called `(turn-on-font-lock)' (deprecated) + ;; and also registered `font-lock-mode' (a toggle!) on `kpp-mode-hook'. + ;; With the hook in place, `turn-on-font-lock' ran first (enabling it), + ;; then the hook ran `font-lock-mode' with no argument (toggling it OFF). + ;; Net result: font-lock ended up disabled. Fix: call `font-lock-mode' + ;; with explicit argument 1 here; do NOT add it to `kpp-mode-hook'. + (font-lock-mode 1)) + +;; --------------------------------------------------------------------------- +;; Auto-mode associations +;; --------------------------------------------------------------------------- + +;; Fix #7: `add-to-list' is idempotent; the original `(setq … (cons …))' +;; pattern appended duplicate entries every time the file was reloaded. + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.def\\'" . kpp-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.eqn\\'" . kpp-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.kpp\\'" . kpp-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.spc\\'" . kpp-mode)) (provide 'kpp) -;; kpp.el ends here +;;; kpp.el ends here diff --git a/site-lisp/kpp_mecca.el b/site-lisp/kpp_mecca.el deleted file mode 100644 index 3297154..0000000 --- a/site-lisp/kpp_mecca.el +++ /dev/null @@ -1,134 +0,0 @@ -;; kpp.el --- kpp mode for GNU Emacs -;; (c) Rolf Sander - -;; To activate it, copy kpp.el to a place where emacs can find it and -;; then add "(require 'kpp)" to your .emacs startup file. - -;; Known problem: -;; ":" inside comments between reaction products confuses font-lock - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2 of the License, or -;; (at your option) any later version. -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; auto-start kpp-mode when loading a *.def, *.eqn, *.kpp, or *.spc file -(setq auto-mode-alist - (cons '("\\.def\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.eqn\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.kpp\\'" . kpp-mode) auto-mode-alist)) -(setq auto-mode-alist - (cons '("\\.spc\\'" . kpp-mode) auto-mode-alist)) - -;; Turn on font-lock-mode for KPP -(add-hook 'kpp-mode-hook 'font-lock-mode) - -(setq kpp-font-lock-keywords - (list - '("^\\([^=\n]*=[^:\n]*\\):[^;\n]*;" 1 font-lock-constant-face) ; reaction - ;; alternatively, use another color for rate constant: - ;; '("^\\([^=\n]*=[^:\n]*\\):\\([^;\n]*\\);" - ;; (1 font-lock-constant-face) (2 font-lock-keyword-face)) - '("<[A-z0-9_#]+>" 0 font-lock-variable-name-face t) ; equation tag - '("{[^}\n]*}" 0 font-lock-comment-face t) ; comment - '("!.*" 0 font-lock-comment-face t) ; f90 comment - '("{@[^}]+}" 0 font-lock-doc-face t) ; alternative LaTeX text - '("{§[^}]*}" 0 font-lock-builtin-face t) ; uncertainty of rate coefficient - '("{$[^}]+}" 0 font-lock-doc-face t) ; alternative LaTeX text - '("{&[^}]+}" 0 font-lock-function-name-face t) ; BibTeX reference - '("{%[A-z0-9#]+}" 0 font-lock-type-face t) ; marker - ;; KPP sections (Tab. 3 in thesis), commands (Tab. 13 in thesis), and - ;; fragments (Tab. 17 in thesis) - (cons (concat - "\\(#ATOMS\\|#AUTOREDUCE\\|#CHECKALL\\|#CHECK\\|#DECLARE" - "\\|#DEFFIX\\|#DEFVAR\\|#DOUBLE\\|#DRIVER\\|#DUMMYINDEX" - "\\|#ENDINLINE\\|#EQNTAGS\\|#EQUATIONS\\|#FAMILIES\\|#FUNCTION" - "\\|#GRAPH\\|#HESSIAN\\|#INCLUDE\\|#INITVALUES\\|#INLINE\\|#INTEGRATOR" - "\\|#INTFILE\\|#JACOBIAN\\|#LANGUAGE\\|#LOOKATALL\\|#LOOKAT" - "\\|#MEX\\|#MINVERSION\\|#MODEL\\|#MONITOR\\|#REORDER" - "\\|#SETFIX\\|#SETVAR\\|#STOCHASTIC\\|#STOICMAT\\|#UPPERCASEF90" - "\\|#WRITE_ATM\\|#WRITE_MAT\\|#WRITE_SPC" - "\\|#REPLACE\\|#ENDREPLACE" - ) 'font-lock-keyword-face) - '("//.*" 0 font-lock-string-face t) ; LaTeX note - '("^//.*" 0 font-lock-comment-face t) ; comment - '("qqq" 0 font-lock-warning-face t) ; - ) -) - -; comment a region (adopted from wave-comment-region) - -(defvar kpp-comment-region "// " - "*String inserted by \\[kpp-comment-region] at start of each line in region.") - -(defun kpp-comment-region (beg-region end-region arg) - "Comments every line in the region. -Puts kpp-comment-region at the beginning of every line in the region. -BEG-REGION and END-REGION are args which specify the region boundaries. -With non-nil ARG, uncomments the region." - (interactive "*r\nP") - (let ((end-region-mark (make-marker)) (save-point (point-marker))) - (set-marker end-region-mark end-region) - (goto-char beg-region) - (beginning-of-line) - (if (not arg) ;comment the region - (progn (insert kpp-comment-region) - (while (and (= (forward-line 1) 0) - (< (point) end-region-mark)) - (insert kpp-comment-region))) - (let ((com (regexp-quote kpp-comment-region))) ;uncomment the region - (if (looking-at com) - (delete-region (point) (match-end 0))) - (while (and (= (forward-line 1) 0) - (< (point) end-region-mark)) - (if (looking-at com) - (delete-region (point) (match-end 0)))))) - (goto-char save-point) - (set-marker end-region-mark nil) - (set-marker save-point nil))) - -(defvar kpp-mode-map () - "Keymap used in kpp mode.") - -(if kpp-mode-map - () - (setq kpp-mode-map (make-sparse-keymap)) - (define-key kpp-mode-map "\C-c;" 'kpp-comment-region) - ;; TAB inserts 8 spaces, not the TAB character - (define-key kpp-mode-map (kbd "TAB") - (lambda () (interactive) (insert " "))) -) - -(defun kpp-mode () - "Major mode for editing kpp code. -Turning on kpp mode calls the value of the variable `kpp-mode-hook' -with no args, if that value is non-nil. - -Command Table: -\\{kpp-mode-map}" - (interactive) - (make-local-variable 'font-lock-defaults) - (setq font-lock-defaults '((kpp-font-lock-keywords) t t)) - (make-local-variable 'comment-start) - (setq comment-start "{") - (make-local-variable 'comment-end) - (setq comment-end "}") - (use-local-map kpp-mode-map) - (setq mode-name "kpp") - (setq major-mode 'kpp-mode) - (turn-on-font-lock) - (set-syntax-table (copy-syntax-table)) - (modify-syntax-entry ?_ "w") ; the underscore can be part of a word - (auto-fill-mode 0) ; no automatic line breaks - (run-hooks 'kpp-mode-hook) -) - -(provide 'kpp) - -;; kpp.el ends here diff --git a/src/Makefile.defs b/src/Makefile.defs index 2199256..fad0d63 100644 --- a/src/Makefile.defs +++ b/src/Makefile.defs @@ -28,9 +28,9 @@ # E-mail: sandu@cs.vt.edu # ############################################################################## - +# # In order to compile KPP you have to provide the following information: - +# # 1. CC # The name of the compiler you want to use. Normally this # is either GNU C compiler (gcc) or the native compiler (cc) @@ -52,7 +52,7 @@ # # 4. FLEX_LIB_DIR # The complete pathname of the FLEX library (libfl.a). -# On many systems this is either: +# On many systems this is: # /usr/lib, /usr/lib64, /usr/local/util/lib/flex # # 5. BISON @@ -62,12 +62,12 @@ # Path to include additional directories # Typically: /usr/include on Linux # /usr/include/sys on Mac OS X - +# ############################################################ ### Default settings ### ############################################################ -CC := gcc +CC ?= gcc CC_FLAGS := -g -Wall -Wno-unused-function FLEX := flex FLEX_LIB_DIR := /usr/lib @@ -80,11 +80,6 @@ HOST := $(shell hostname) # name of machine ############################################################ ### Keep looking for the flex library until found ### ### Otherwise use the path specified in KPP_FLEX_LIB_DIR ### -### ### -### NOTE for MacOS X: IF you have installed flex with ### -### HomeBrew, then flex will be installed to a path such ### -### as /usr/local/Cellar/flex/X.Y.Z/lib, where X.Y.Z is ### -### the version number. -- Bob Yantosca (01 Nov 2021) ### ############################################################ # Try /usr/lib64 @@ -112,6 +107,18 @@ ifeq ($(wildcard $(FLEX_LIB_DIR)/libfl.*),) FLEX_LIB_DIR := /usr/lib/$(firstword $(SYSTEM_M))-linux-gnu endif +# Homebrew macOS: "brew --prefix" flex resolves to the correct lib +# path on both Apple Silicon (/opt/homebrew/opt/flex/lib) and Intel +# (/usr/local/opt/flex/lib) without any architecture branching. +# This block is safe on any non-MacOSX system. +# It will also execute if the user has Homebrew on Linux. +ifeq ($(wildcard $(FLEX_LIB_DIR)/libfl.*),) + _BREW_FLEX := $(shell brew --prefix flex 2>/dev/null) + ifneq ($(_BREW_FLEX),) + FLEX_LIB_DIR := $(_BREW_FLEX)/lib + endif +endif + # If we can't find the flex library path, then specify it # from the user's environment variable KPP_FLEX_LIB_DIR. ifneq ($(KPP_FLEX_LIB_DIR),) @@ -129,17 +136,50 @@ endif # Settings for MacOS ifeq ($(strip $(SYSTEM)),Darwin) - CC_FLAGS += -DMACOS -O + + # NOTE: We intentionally do NOT define -DMACOS here. The MACOS branch in + # gdata.h clamps MAX_EQN=2000 and MAX_SPECIES=1000 to fit the default + # 8 MB Darwin stack, but full MECCA mechanisms blow past 1000 species. + # Instead we rely on the user raising the soft stack limit + # (`ulimit -s 65520` -- the macOS hard limit) before invoking KPP, and + # we also enlarge the linker stack reservation of the kpp binary below. + CC_FLAGS += -O + + # Increase the executable's stack reservation so the large static + # arrays in gen.c (snames[8000], strans[8000], ...) fit. The default + # macOS stack reservation is 8 MB; bump it to ~64 MB. + CC_FLAGS += -Wl,-stack_size,0x4000000 + + # Tell the compiler if we are on x86_64 or arm64 architecture ifeq ($(strip $(SYSTEM_M)),x86_64) - # Build for Intel x86_64 chipsets CC_FLAGS += -arch x86_64 + else ifeq ($(strip $(SYSTEM_M)),arm64) + CC_FLAGS += -arch arm64 else - ifeq ($(strip $(SYSTEM_M)),arm64) - # Build for Apple Silicon chipsets - CC_FLAGS += -arch arm64 - else - $(warning Unknown architecture: $(strip $(SYSTEM_M))) + $(warning Unknown architecture: $(strip $(SYSTEM_M))) + endif + + # brew --prefix returns /usr/local (Intel) or /opt/homebrew (Apple Silicon) + # automatically — no architecture branching required. + BREW_PREFIX ?= $(shell brew --prefix 2>/dev/null) + + # Apple ships an ancient bison (2.3) and a flex without libfl in the + # system path. Prefer Homebrew's modern flex/bison when present so the + # scanner and parser actually build on macOS. + ifneq ($(BREW_PREFIX),) + ifneq ($(wildcard $(BREW_PREFIX)/opt/flex/bin/flex),) + FLEX := $(BREW_PREFIX)/opt/flex/bin/flex + endif + ifneq ($(wildcard $(BREW_PREFIX)/opt/bison/bin/bison),) + BISON := $(BREW_PREFIX)/opt/bison/bin/bison endif endif + + # Use the active Xcode/CLT SDK for system headers rather than the + # non-existent /usr/include directory. + SDK_PATH := $(shell xcrun --show-sdk-path 2>/dev/null) + ifneq ($(SDK_PATH),) + INCLUDE_DIR := $(SDK_PATH)/usr/include + endif endif ############################################################# diff --git a/src/code.c b/src/code.c index 950dcd3..c11b9dd 100644 --- a/src/code.c +++ b/src/code.c @@ -52,6 +52,7 @@ void (*DeclareConstant)( int v, char *val ); void (*FunctionStart)( int f, int *vars ); void (*FunctionPrototipe)( int f, ... ); void (*FunctionBegin)( int f, ... ); +void (*FunctionBeginNoArgDecl)( int f, ... ); void (*FunctionEnd)( int f ); // Local definitions of function prototypes just for code.c diff --git a/src/code.h b/src/code.h index 6a04194..57143c0 100644 --- a/src/code.h +++ b/src/code.h @@ -133,6 +133,7 @@ void FreeVariable( int n ); #define DefConst( name, bt, cmt ) DefineVariable( name, CONST, bt, 0, 0, cmt, 0 ) #define DefElm( name, bt, cmt ) DefineVariable( name, ELM, bt, 0, 0, cmt, 0 ) +#define DefElmO( name, bt, cmt ) DefineVariable( name, ELM, bt, 0, 0, cmt, ATTR_F90_OPT ) #define DefvElm( name, bt, n, cmt ) DefineVariable( name, VELM, bt, n, 0, cmt, 0 ) #define DefmElm( name, bt, m, n, cmt ) DefineVariable( name, MELM, bt, m, n, cmt, 0) #define DefeElm( name, cmt ) DefineVariable( name, EELM, 0, 0, 0, cmt, 0 ) @@ -208,6 +209,7 @@ extern void (*DeclareConstant)( int v, char *val ); extern void (*FunctionStart)( int f, int *vars ); extern void (*FunctionPrototipe)( int f, ... ); extern void (*FunctionBegin)( int f, ... ); +extern void (*FunctionBeginNoArgDecl)( int f, ... ); extern void (*FunctionEnd)( int f ); void WriteDelim(); diff --git a/src/code_c.c b/src/code_c.c index 81b91dd..d7f469e 100644 --- a/src/code_c.c +++ b/src/code_c.c @@ -531,6 +531,9 @@ void Use_C( char* rootFileName ) FunctionBegin = C_FunctionBegin; FunctionEnd = C_FunctionEnd; + // FunctionBeginNoArgDecl is only defined for Fortran-90 + FunctionBeginNoArgDecl = NULL; + OpenFile( ¶m_headerFile, rootFileName, "_Parameters.h", "Parameter Header File" ); OpenFile( &initFile, rootFileName, "_Initialize.c", "Initialization File" ); OpenFile( &driverFile, rootFileName, "_Main.c", "Main Program File" ); diff --git a/src/code_f77.c b/src/code_f77.c index f0cf699..e42d536 100644 --- a/src/code_f77.c +++ b/src/code_f77.c @@ -554,6 +554,9 @@ void Use_F( char* rootFileName ) FunctionBegin = F77_FunctionBegin; FunctionEnd = F77_FunctionEnd; + // FunctionBeginNoArgDecl is only defined for Fortran-90 + FunctionBeginNoArgDecl = NULL; + OpenFile( ¶m_headerFile, rootFileName, "_Parameters.h", "Parameter Header File" ); OpenFile( &initFile, rootFileName, "_Initialize.f", "Initialization File" ); OpenFile( &driverFile, rootFileName, "_Main.f", "Main Program File" ); diff --git a/src/code_f90.c b/src/code_f90.c index 45d31d7..fa78aeb 100644 --- a/src/code_f90.c +++ b/src/code_f90.c @@ -241,8 +241,16 @@ char maxj[20]; *buf = 0; switch( var->type ) { - case ELM: - sprintf( buf, "%s :: %s", baseType, var->name ); + case ELM: // + // Modify the IF block so that F90 scalar variables + // can be declared with the OPTIONAL attribute. + // -- Bob Yantosca (02 Jul 2026) + // + if ( var->attr == ATTR_F90_OPT ) { + sprintf( buf, "%s, OPTIONAL :: %s", baseType, var->name ); + } else { + sprintf( buf, "%s :: %s", baseType, var->name ); + } break; case VELM: if( var->maxi > 0 ) sprintf( maxi, "%d", var->maxi ); @@ -257,12 +265,12 @@ char maxj[20]; sprintf( maxi, "%d", (varTable[-var->maxi]->value)==0? 1:varTable[-var->maxi]->value ); } - - //============================================================= + // // MODIFICATION by Bob Yantosca (28 Apr 2022) // // Modify the IF block so that F90 variables can be declared // with either the POINTER, TARGET, or OPTIONAL attribute. + // -- Bob Yantosca (28 Apr 2022) // if ( var->attr == ATTR_F90_PTR ) sprintf( buf, "%s, POINTER :: %s(:)", baseType, @@ -281,7 +289,6 @@ char maxj[20]; maxi ); else sprintf( buf, "%s :: %s(%s)", baseType, var->name, maxi ); - //============================================================= break; case MELM: @@ -383,10 +390,9 @@ int maxCols = MAX_COLS; strcat( maxi, "+1"); bprintf( " %s, " , baseType); if( n>0 ) bprintf( "PARAMETER, " ); /* if values are assigned now */ - //==================================================================== - // MODIFICATION by Bob Yantosca (28 Apr 2022) // // Add the POINTER, TARGET, or OPTIONAL attributes to F90 variables. + // - Bob Yantosca (28 Apr 2022) // if ( var->attr == ATTR_F90_PTR ) { bprintf( ", POINTER :: %s(:)", var->name ) ; @@ -404,7 +410,7 @@ int maxCols = MAX_COLS; bprintf( ", OPTIONAL, POINTER :: %s(%s)", var->name, maxi ) ; if( n<=0 ) break; } - //==================================================================== + // if ( maxi_div==0 ) { /* define array in one piece */ bprintf( "DIMENSION(%s) :: %s", maxi, var->name) ; @@ -722,6 +728,38 @@ int narg; LogFunctionComment( f, vars ); } +/*************************************************************************************************/ +void F90_FunctionBeginNoArgDecl( int f, ... ) +{ +// +// FunctionBeginNoArgDecl is similar to FunctionBegin, except that function +// arguments are not declared. This allows the user to manually declare +// F90 function arguments lower down in the code, following any F90 USE +// statements. This will help to avoid compilation errors. +// -- Bob Yantosca (02 Jul 2026) +// +Va_list args; +int i; +int vars[20]; +int narg; + + narg = varTable[ f ]->maxi; + + Va_start( args, f ); + for( i = 0; i < narg; i++ ) + vars[ i ] = va_arg( args, int ); + va_end( args ); + + CommentFncBegin( f, vars ); + F90_FunctionStart( f, vars ); + NewLines(1); + + bprintf("\n"); + FlushBuf(); + + LogFunctionComment( f, vars ); +} + /*************************************************************************************************/ void F90_FunctionEnd( int f ) { @@ -769,6 +807,7 @@ void Use_F90( char* rootFileName ) FunctionStart = F90_FunctionStart; FunctionPrototipe = F90_FunctionPrototipe; FunctionBegin = F90_FunctionBegin; + FunctionBeginNoArgDecl= F90_FunctionBeginNoArgDecl; FunctionEnd = F90_FunctionEnd; // Parameters diff --git a/src/code_matlab.c b/src/code_matlab.c index e157abc..61df945 100644 --- a/src/code_matlab.c +++ b/src/code_matlab.c @@ -677,6 +677,9 @@ void Use_MATLAB( char *rootFileName ) FunctionBegin = MATLAB_FunctionBegin; FunctionEnd = MATLAB_FunctionEnd; + // FunctionBeginNoArgDecl is only defined for Fortran-90 + FunctionBeginNoArgDecl = NULL; + OpenFile( ¶m_headerFile, rootFileName, "_Parameters.m","Parameter Definition File" ); OpenFile( &driverFile, rootFileName, "_Main.m", "Main Program File" ); OpenFile( &rateFile, rootFileName, "_Rates.m", diff --git a/src/gdata.h b/src/gdata.h index b64e692..f50377a 100644 --- a/src/gdata.h +++ b/src/gdata.h @@ -31,7 +31,7 @@ // Version numbers must be synchronized in CHANGELOG.md, src/gdata.h, // docs/source/conf.py and https://en.wikipedia.org/wiki/Kinetic_PreProcessor -#define KPP_VERSION "3.4.0" +#define KPP_VERSION "3.5.0" #ifndef _GDATA_H_ #define _GDATA_H_ diff --git a/src/gen.c b/src/gen.c index 34db199..4ab4af6 100644 --- a/src/gen.c +++ b/src/gen.c @@ -147,12 +147,11 @@ int i,j; /* PI = DefConst( "PI", real, "Value of pi" ); */ -//============================================================================ -// MODIFICATION by Bob Yantosca (25 Apr 2022) -// -// For Fortran-90, declare VAR and FIX as POINTER variables, which will -// allow us to remove the non-threadsafe EQUIVALENCE statements. -// + // + // For Fortran-90, declare VAR and FIX as POINTER variables, which will + // allow us to remove the non-threadsafe EQUIVALENCE statements. + // -- Bob Yantosca (25 Apr 2022) + // if ( useLang == F90_LANG ) { VAR = DefvElmP( "VAR", real, "Concentrations of variable species (global)" ); @@ -163,8 +162,8 @@ int i,j; "Concentrations of variable species (global)" ); FIX = DefvElm( "FIX", real, -NFIX, "Concentrations of fixed species (global)" ); -} -//============================================================================ + } + V = DefvElm( "V", real, -NVAR, "Concentrations of variable species (local)" ); F = DefvElm( "F", real, -NFIX, "Concentrations of fixed species (local)" ); @@ -245,18 +244,18 @@ int i,j; IV = DefeElm( "IV", 0 ); C_DEFAULT = DefvElm( "C_DEFAULT", real, -NSPEC, "Default concentration for all species" ); -//============================================================================ -// MODIFICATION by Bob Yantosca (25 Apr 2002) -// For Fortran-90, declare C with the TARGET attribute. This will allow -// VAR and FIX to point to C, which will let us remove the non-threadsafe -// EQUIVALENCE statements. -// + // + // For Fortran-90, declare C with the TARGET attribute. This will allow + // VAR and FIX to point to C, which will let us remove the non-threadsafe + // EQUIVALENCE statements. + // -- Bob Yantosca (25 Apr 2022) + // if ( useLang == F90_LANG ) { C = DefvElmT( "C", real, -NSPEC, "Concentration of all species" ); } else { C = DefvElm( "C", real, -NSPEC, "Concentration of all species" ); } -//============================================================================ + CL = DefvElm( "CL", real, -NSPEC, "Concentration of all species (local)" ); ATOL = DefvElm( "ATOL", real, -NVAR, "Absolute tolerance" ); RTOL = DefvElm( "RTOL", real, -NVAR, "Relative tolerance" ); @@ -279,8 +278,9 @@ int i,j; FAM_NAMES = DefvElm( "FAM_NAMES", STRING, -NFAM, "Names of chemical familes" ); CFACTOR = DefElm( "CFACTOR", real, "Conversion factor for concentration units"); - - /* Autoreduction structures */ + // + // Autoreduction structures + // NVARP1 = DefConst( "NVAR+1", INT, "Number of Variable species + 1" ); DO_JVS = DefvElm("DO_JVS", LOGICAL, -LU_NONZERO, ""); DO_SLV = DefvElm("DO_SLV", LOGICAL, -NVARP1 , ""); @@ -300,8 +300,9 @@ int i,j; Aout = DefvElmO( "Aout", real, -NREACT, "Optional argument to return equation rate constants" ); - - /* Elements of Stochastic simulation*/ + // + // Elements of Stochastic simulation + // NMLCV = DefvElm( "NmlcV", INT, -NVAR, "No. molecules of variable species" ); NMLCF = DefvElm( "NmlcF", INT, -NFIX, "No. molecules of fixed species" ); SCT = DefvElm( "SCT", real, -NREACT, "Stochastic rate constants" ); @@ -312,8 +313,9 @@ int i,j; for ( i=0; i value = max(SpcNr,1); varTable[ NVAR ] -> value = max(VarNr,1); @@ -648,13 +650,14 @@ int F_VAR, FSPLIT_VAR; if (useLang != MATLAB_LANG) /* Matlab generates an additional file per function */ UseFile( functionFile ); - + // // Note: When changing the FunctionBegin declarations below, // the number of arguments minus one must be changed in DefFnc here // as well. (hplin, 7/6/22) // // For F90, add an extra argument to Fun and Fun_Split to return // the Aout array. (hplin, bmy, 30 Apr 2024) + // if (useLang == F90_LANG) { F_VAR = DefFnc("Fun", 5, "time derivatives of variables - Aggregate form"); @@ -666,7 +669,7 @@ int F_VAR, FSPLIT_VAR; FSPLIT_VAR = DefFnc("Fun_SPLIT", 6, "time derivatives of variables - Split form"); } - + // // We have added the capability to return equation rates and the // time derivative of variable species from Fun via optional arguments // Aout and VdotOut (when z_useAggregate=1) @@ -675,6 +678,7 @@ int F_VAR, FSPLIT_VAR; // Vdotout functionality can be accomplished using Vdot (hplin, 7/6/22) // // F90 needs Fun to have an extra argument for Aout (hplin, bmy, 30 Apr 2024) + // if( z_useAggregate ) { if (useLang == F90_LANG) { FunctionBegin( F_VAR, V, F, RCT, Vdot, Aout );\ @@ -733,9 +737,10 @@ int F_VAR, FSPLIT_VAR; Assign( Elm( A, j ), prod ); } } - + // // Add code to return equation rates via optional argument Aout // -- Bob Yantosca (29 Apr 2022) + // NewLines(1); if ( useLang == F90_LANG ) { fprintf(functionFile, " !### Use Aout to return equation rates\n"); @@ -789,8 +794,9 @@ int F_VAR, FSPLIT_VAR; if( doAutoReduce ) F90_Inline("IF (DO_FUN(%d)) &",i+1); Assign( Elm( D_VAR, i ), sum ); } - + // // Add code to calculate Vdot also for split function: + // NewLines(1); if ( useLang == F90_LANG ) { // For F90, we can do operations on arrays: @@ -813,8 +819,11 @@ int F_VAR, FSPLIT_VAR; FreeVariable( F_VAR ); FreeVariable( FSPLIT_VAR ); - - /** hplin 4/10/22 add FUN_Split2 which overrides DO_FUN. only used for 1st order-autoreduce **/ + // + // hplin 4/10/22 + // add FUN_Split2 which overrides DO_FUN. + // only used for 1st order-autoreduce + // if(!z_useAggregate && doAutoReduce) { /* add a copy of FSPLIT that does not react to DO_FUN() */ fprintf(functionFile, "! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); @@ -2339,23 +2348,25 @@ int YIN, Y; UseFile( rateFile ); - if (useLang==F90_LANG) { + if ( useLang==F90_LANG ) { // - // SPECIAL HANDLING FOR F90: - // ------------------------- - // Manually write the "SUBROUTINE RCONST ( YIN )" line instead of - // using the FunctionBegin( UPDATE_RCONST ). This will allow us - // to add any inlined F90 use statements immediately afterwards. - // Recall that F90 "USE" statements must precede variable - // declarations or any other executable statements, or else a - // compilation error will be generated. + // SPECIAL HANDLING FOR FORTRAN-90 + // ------------------------------- + // Use FunctionBeginNoArgDecl to create the subroutine interface. + // Then manually declare subroutine arguments after inlining USE + // statements from the F90_RCONST_USE section. This will avoid + // compile-time errors caused by variable declarations preceding + // USE statements. + // -- Bob Yantosca (02 Jul 2026) // - // -- Bob Yantosca (19 Dec 2024) + UPDATE_RCONST = DefFnc( "Update_RCONST", 1, + "function to update rate constants"); + YIN = DefvElmO( "YIN", real, -NVAR, + "Optional input concentrations of variable species" ); + FunctionBeginNoArgDecl( UPDATE_RCONST, YIN ); + // + // Inline USE statements immediately following the subroutine interface // - bprintf("SUBROUTINE Update_RCONST ( YIN )"); - NewLines(2); - - // Inline USE statements right after the subroutine declaration WriteComment("Begin inlined code from F90_RCONST_USE"); NewLines(1); bprintf( InlineCode[ F90_RCONST_USE ].code ); @@ -2363,33 +2374,41 @@ int YIN, Y; NewLines(1); WriteComment("End inlined code from F90_RCONST_USE"); NewLines(1); - - // Declare optional YIN argument - YIN = DefvElmO( "YIN", real, -NVAR, "Optional input concentrations of variable species" ); + // + // Declare optional YIN argument after USE statements are inlined + // Declare(YIN); NewLines(1); - + // // Declare local Y variable + // Y = DefvElm( "Y", real, -NSPEC, "Concentrations of species (local)" ); Declare(Y); NewLines(1); - + // // Copy values of YIN to Y if YIN is present + // WriteComment("Ensure local Y array is filled with variable and constant concentrations"); - bprintf(" Y(1:NSPEC) = C(1:NSPEC)\n"); + F90_Inline(" Y(1:NSPEC) = C(1:NSPEC)"); NewLines(1); WriteComment("Update local Y array if variable concentrations are provided"); - bprintf(" if (present(YIN)) Y(1:NVAR) = YIN(1:NVAR)\n"); + F90_Inline(" if (present(YIN)) Y(1:NVAR) = YIN(1:NVAR)\n"); NewLines(1); - } else { // - // For other languages, declare function w/o any arguments + // C, FORTRAN-77, MATLAB + // --------------------- + // Declare UPDATE_RCONST function without any arguments // - UPDATE_RCONST = DefFnc( "Update_RCONST", 0, "function to update rate constants"); + UPDATE_RCONST = DefFnc( "Update_RCONST", 0, + "function to update rate constants"); FunctionBegin( UPDATE_RCONST ); - } - + YIN = 0; + Y = 0; + } + // + // Inline F77 and MATLAB include files + // F77_Inline(" INCLUDE '%s_Global.h'", rootFileName); MATLAB_Inline("global SUN TEMP RCONST"); @@ -2397,28 +2416,31 @@ int YIN, Y; IncludeCode( "%s/util/UserRateLaws_FcnHeader", Home ); NewLines(1); - + // // Inline code from {C,F77,F90_MATLAB}_RCONST inline keys + // NewLines(1); WriteComment("Begin inlined code from F90_RCONST"); NewLines(1); switch( useLang ) { - case C_LANG: bprintf( InlineCode[ C_RCONST ].code ); - break; - case F77_LANG: bprintf( InlineCode[ F77_RCONST ].code ); - break; - case F90_LANG: bprintf( InlineCode[ F90_RCONST ].code ); - break; + case C_LANG: bprintf( InlineCode[ C_RCONST ].code ); + break; + case F77_LANG: bprintf( InlineCode[ F77_RCONST ].code ); + break; + case F90_LANG: bprintf( InlineCode[ F90_RCONST ].code ); + break; case MATLAB_LANG: bprintf( InlineCode[ MATLAB_RCONST ].code ); - break; + break; } FlushBuf(); NewLines(1); WriteComment("End inlined code from F90_RCONST"); NewLines(1); - + // + // Inline the reaction rate coefficients + // for( i = 0; i < EqnNr; i++) { /* mz_rs_20220701+ */ if (useEqntags==1) { @@ -2438,20 +2460,13 @@ int YIN, Y; MATLAB_Inline(" RCONST = RCONST(:);"); // - // SPECIAL HANDLING FOR F90: - // ------------------------- - // Manually write the "END SUBROUTINE UPDATE_RCONST" line when - // generating F90 output. But if generating C, F77, MatLab output, - // then close the UPDATE_RCONST routine as we normally would. - // -- Bob Yantosca (19 Dec 2024) + // Cleanup // - if (useLang == F90_LANG) { - NewLines(1); - bprintf("END SUBROUTINE UPDATE_RCONST"); - NewLines(1); - } else { - FunctionEnd( UPDATE_RCONST ); - FreeVariable( UPDATE_RCONST ); + FunctionEnd( UPDATE_RCONST ); + FreeVariable( UPDATE_RCONST ); + if ( useLang == F90_LANG ) { + FreeVariable( YIN ); + FreeVariable( Y ); } } @@ -2474,6 +2489,7 @@ int UPDATE_PHOTO; // SPECIAL HANDLING FOR F90: // ------------------------- // Inline USE statements right after the subroutine declaration + // WriteComment("Begin inlined code from F90_RCONST_USE"); NewLines(1); bprintf( InlineCode[ F90_RCONST_USE ].code ); @@ -2706,26 +2722,42 @@ int j,dummy_species; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ void GenerateGlobalHeader() { + // + // Modify code to inline the F77/F90 THREADPRIVATE declarations, and also + // declare extra arrays and scalars. These declarations begin with a + // comment character and will be ignored unless the Fortran-90 code is + // compiled with OpenMP. + // -- Bob Yantosca (26 Mar 2021) + // + // Define a flag to denote if we are using Fortran (either F90 or F77) + // int useFortran; - -//=========================================================================== -// MODIFICATION: Bob Yantosca (26 Mar 2021) -// -// Modify code to inline the F77/F90 THREADPRIVATE declarations, and also -// declare extra arrays and scalars. These declarations begin with a -// comment character and will be ignored unless the Fortran-90 code is -// compiled with OpenMP. -//=========================================================================== - - /*** Define a flag to denote if we are using F90 or F77 ***/ if ( useLang == F90_LANG || useLang == F77_LANG ) { useFortran = 1; } else { useFortran = 0; } - + // + // Define variables that will allow us to exclude "passive" species (those + // added to reactions for diagnostic purposes), for Fortran90 only. + // -- Bob Yantosca (02 Jul 2026) + // + int NON_PASV_SPC_CT, NON_PASV_SPC_IND; + if ( useLang == F90_LANG ) { + NON_PASV_SPC_CT = DefElm( "NonPassiveSpc_Count", INT, + "Number of non-passive species in mechanism" ); + NON_PASV_SPC_IND = DefvElm( "NonPassiveSpc_Indices", INT, -NVAR, + "Indices of non-passive species in mechanism" ); + } else { + NON_PASV_SPC_CT = 0; + NON_PASV_SPC_IND = 0; + } + // + // Initialize + // UseFile( global_dataFile ); CommonName = "GDATA"; - - /*** Write comment header ***/ + // + // Write comment header + // NewLines(1); WriteComment("Declaration of global variables"); if ( useFortran ) { @@ -2751,12 +2783,14 @@ void GenerateGlobalHeader() "~~~ with OpenMP parallelization turned on."); } NewLines(1); - - /*** Declare C, concentration array ***/ + // + // Declare C, concentration array + // ExternDeclare( C ); if ( useFortran ) { WriteOMPThreadPrivate("C"); } - - /*** Declare VAR and FIX for F90 (these are now pointers!) ***/ + // + // Declare VAR and FIX for F90 (these are now pointers!) + // if ( useLang == F90_LANG ) { ExternDeclare( VAR ); WriteOMPThreadPrivate("VAR"); @@ -2764,9 +2798,10 @@ void GenerateGlobalHeader() ExternDeclare( FIX ); WriteOMPThreadPrivate("FIX"); } - - /*** Declare VAR and fix for F77 ***/ - /*** We need to keep the EQUIVALENCE statement for F77 only! ***/ + // + // Declare VAR and fix for F77 + // We need to keep the EQUIVALENCE statement for F77 only! + // if ( useLang == F77_LANG ) { Declare( VAR ); WriteOMPThreadPrivate("VAR"); @@ -2781,20 +2816,23 @@ void GenerateGlobalHeader() varTable[C]->name, VarNr+1, varTable[FIX]->name ); } } - - /*** Declare VAR and FIX for MatLab ***/ + // + // Declare VAR and FIX for MatLab + // if ( useLang == MATLAB_LANG ) { ExternDeclare( VAR ); ExternDeclare( FIX ); } - - /*** Declare VAR and FIX for C with the extern property ***/ + // + // Declare VAR and FIX for C with the extern property + // if ( useLang == C_LANG ) { C_Inline(" extern %s * %s;", C_types[real], varTable[VAR]->name ); C_Inline(" extern %s * %s;", C_types[real], varTable[FIX]->name ); } - - /*** Declare all other threadprivate variables ***/ + // + // Declare all other threadprivate variables + // ExternDeclare( RCONST ); if ( useFortran ) { WriteOMPThreadPrivate("RCONST"); } @@ -2806,8 +2844,9 @@ void GenerateGlobalHeader() ExternDeclare( TEMP ); if ( useFortran ) { WriteOMPThreadPrivate("TEMP"); } - - /*** Declare non-threadprivate variables ***/ + // + // Declare non-threadprivate variables + // NewLines(1); if ( useFortran ) { WriteComment( @@ -2824,26 +2863,18 @@ void GenerateGlobalHeader() ExternDeclare( RTOL ); ExternDeclare( STEPMIN ); ExternDeclare( STEPMAX ); - if (doAutoReduce) { - ExternDeclare(DO_JVS); - ExternDeclare(DO_SLV); - ExternDeclare(DO_FUN); - ExternDeclare(cLU_IROW); - ExternDeclare(cLU_ICOL); - ExternDeclare(cLU_CROW); - ExternDeclare(cLU_DIAG); - ExternDeclare(JVS_MAP); - ExternDeclare(SPC_MAP); - ExternDeclare(iSPC_MAP); - ExternDeclare(RMV); - ExternDeclare(RNVAR); - ExternDeclare(cNONZERO); - ExternDeclare(keepSpcActive); - ExternDeclare(keepActive); - /* hplin 10/19/21 */ - WriteOMPThreadPrivate(" DO_JVS, DO_SLV, DO_FUN, cLU_IROW, cLU_ICOL, cLU_CROW"); - WriteOMPThreadPrivate(" cLU_DIAG, JVS_MAP, SPC_MAP, iSPC_MAP, RMV, rNVAR, cNONZERO, KEEPACTIVE "); /* msl_20160419 */ + // + // Declare variables that can be used to exclude "passive" species + // from the Rosenbrock error norm and other computations (F90-only). + // -- Bob Yantosca (02 Jul 2026) + // + if ( useLang == F90_LANG ) { + ExternDeclare( NON_PASV_SPC_CT ); + ExternDeclare( NON_PASV_SPC_IND ); } + // + // Declare other variables + // ExternDeclare( CFACTOR ); if (useStochastic) ExternDeclare( VOLUME ); @@ -2853,7 +2884,6 @@ void GenerateGlobalHeader() ExternDeclare( DDMTYPE ); } - if ( (useLang == C_LANG) || (useLang == F77_LANG) ) { CommonName = "INTGDATA"; ExternDeclare( LOOKAT ); @@ -2865,7 +2895,40 @@ void GenerateGlobalHeader() ExternDeclare( EQN_TAGS ); ExternDeclare( FAM_NAMES ); } + // + // Special section for rosenbrock_autoreduce integrator variables (F90-only) + // Move this below the non-threadprivate variables. + // -- Bob Yantosca (02 Jul 2026) + // + if (doAutoReduce) { + + NewLines(1); + WriteComment( + "~~~ Variables for the ""rosenbrock_autoreduce"" integrator"); + NewLines(1); + ExternDeclare(DO_JVS); + ExternDeclare(DO_SLV); + ExternDeclare(DO_FUN); + ExternDeclare(cLU_IROW); + ExternDeclare(cLU_ICOL); + ExternDeclare(cLU_CROW); + ExternDeclare(cLU_DIAG); + ExternDeclare(JVS_MAP); + ExternDeclare(SPC_MAP); + ExternDeclare(iSPC_MAP); + ExternDeclare(RMV); + ExternDeclare(RNVAR); + ExternDeclare(cNONZERO); + ExternDeclare(keepSpcActive); + ExternDeclare(keepActive); + /* hplin 10/19/21 */ + WriteOMPThreadPrivate(" DO_JVS, DO_SLV, DO_FUN, cLU_IROW, cLU_ICOL, cLU_CROW"); + WriteOMPThreadPrivate(" cLU_DIAG, JVS_MAP, SPC_MAP, iSPC_MAP, RMV, rNVAR, cNONZERO, KEEPACTIVE "); /* msl_20160419 */ + } + // + // Inline code from the F90_GLOBAL section here + // NewLines(1); WriteComment("Begin inlined code from F90_GLOBAL"); @@ -2880,10 +2943,16 @@ void GenerateGlobalHeader() break; } FlushBuf(); - + // + // Cleanup + // NewLines(1); WriteComment("End inlined code from F90_GLOBAL"); NewLines(1); + if ( useLang == F90_LANG ) { + FreeVariable( NON_PASV_SPC_CT ); + FreeVariable( NON_PASV_SPC_IND ); + } } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ @@ -3104,40 +3173,84 @@ void GenerateInitialize() { int i; int I, X; -int INITVAL; +int INITVAL, PASV_SPC_ATOL_THRESH; if ( (useLang==C_LANG)||(useLang==F77_LANG)||(useLang==F90_LANG) ) UseFile( initFile ); - INITVAL = DefFnc( "Initialize", 0, "function to initialize concentrations"); - FunctionBegin( INITVAL ); + if ( useLang == F90_LANG ) { + // + // SPECIAL HANDLING FOR FORTRAN-90 + // ------------------------------- + // Pass the optional "PassiveSpc_ATOL_Threshold" variable to the + // F90 Initialize routine. This will allow the user to specify + // an absolute tolerance threshold that will be used to filter out + // "passive" species (i.e. species added to reactions for diagnostic + // purposes). + // + // Use FunctionBeginNoArgDecl to declare the subroutine interface. + // Then manually insert the subroutine argument declarations below + // all USE statements. This will avoid compile-time errors caused + // by variable declarations preceding USE statements. + // -- Bob Yantosca (02 Jul 2026) + // + INITVAL = DefFnc( "Initialize", 1, + "function to initialize concentrations"); + PASV_SPC_ATOL_THRESH = DefElmO( "PassiveSpc_ATOL_Threshold", real, + "Species with ATOL > this value are passive"); + FunctionBeginNoArgDecl( INITVAL, PASV_SPC_ATOL_THRESH ); + } else { + // + // C, FORTRAN-77, MATLAB + // --------------------- + // Do not declare any subroutine arguments + // + INITVAL = DefFnc( "Initialize", 0, + "function to initialize concentrations"); + PASV_SPC_ATOL_THRESH = 0; + FunctionBegin( INITVAL ); + } + // + // Inline include statements and/or USE statements + // F77_Inline(" INCLUDE '%s_Global.h'", rootFileName); F90_Inline(" USE %s_Global\n", rootFileName); MATLAB_Inline("global CFACTOR VAR FIX NVAR NFIX", rootFileName); F77_Inline(" INCLUDE '%s_Parameters.h'", rootFileName); F90_Inline(" USE %s_Parameters\n", rootFileName); - + // + // Manually declare F90 function arguments after USE statements + // so as to avoid any compile-time errors. + // -- Bob Yantosca (02 Jul 2026) + // + if ( useLang == F90_LANG ) { + Declare( PASV_SPC_ATOL_THRESH ); + NewLines(1); + } + // + // Declare local variables + // + WriteComment("~~~ Local variables"); I = DefElm( "i", INT, 0); X = DefElm( "x", real, 0); Declare( I ); Declare( X ); - + // + // Assign CFACTOR + // NewLines(1); WriteComment("~~~ Define scale factor for units"); WriteAssign( varTable[CFACTOR]->name , ascid( (double)cfactor ) ); NewLines(1); - //========================================================================= - // MODIFICATION by Bob Yantosca (25 Apr 2022) - // - // For F90, assign values to C directly (since VAR and FIX now point to C - // instead of the other way around). Otherwise, preserve prior code. - //========================================================================= if ( useLang == F90_LANG ) { - // - // Fortran-90 + // FORTRAN-90 + // ----------- + // For F90, assign values to C directly (since VAR and FIX + // now point to C instead of the other way around). + // -- Bob Yantosca (25 Apr 2022) // WriteComment("~~~ Zero C array"); if ( useDouble ) @@ -3157,9 +3270,11 @@ int INITVAL; NewLines(1); } else { - // - // Fortran-77, C, and Matlab + // C, FORTRAN-77, MATLAB + // --------------------- + // Initialize CFACTOR, VAR, FIX. Assign values to VAR and FIX + // which then point to C (or for F77, which are EQUIVALENCEd to C). // Assign( Elm( X ), Mul( Elm( IV, varDefault ), Elm( CFACTOR ) ) ); C_Inline(" for( i = 0; i < NVAR; i++ )" ); @@ -3198,14 +3313,18 @@ int INITVAL; Elm( CFACTOR ) ) ); } } - + // + // Inline constant rate coefficients here + // WriteComment("Begin constant rate coefficients"); for( i = 0; i < EqnNr; i++) { if ( kr[i].type == NUMBER ) Assign( Elm( RCONST, i ), Const( kr[i].val.f ) ); } WriteComment("End constant rate coefficients"); - + // + // Inline code from C_INIT, F77_INIT, F90_INIT, MATLAB_INIT sections here + // NewLines(1); WriteComment("Begin inlined code from F90_INIT"); @@ -3220,17 +3339,62 @@ int INITVAL; break; } FlushBuf(); - + NewLines(1); WriteComment("End inlined code from F90_INIT"); NewLines(1); MATLAB_Inline(" VAR = VAR(:);\n FIX = FIX(:);\n" ); - + // + if ( useLang == F90_LANG) { + // + // FORTRAN-90 + // ---------- + // Determine the count and index list of "non-passive" species, which + // have an absolute tolerance below a very high threshold. This will + // allow us to filter these dummy species out of e.g. Rosenbrock error + // norm calculations. Place this after the afer the F90_INIT block + // to avoid overwriting any inlined ATOL values. + // -- Bob Yantosca (07 Jul 2026) + // + WriteComment( + "~~~ Determine the count and indices of actual species (as opposed to"); + WriteComment( + "~~~ (""passive"" species used for diagnostics. Denote passive species"); + WriteComment( + "~~~ as those having ATOL > PassiveSpc_ATOL_Threshold. If the optional"); + WriteComment( + "~~~ argument PassiveSpc_ATOL_Threshold is not specified, then treat"); + WriteComment( + "~~~ all variable species as non-passive species."); + F90_Inline(" NonPassiveSpc_Count = 0"); + F90_Inline(" NonPassiveSpc_Indices = 0"); + F90_Inline(" IF ( PRESENT( PassiveSpc_ATOL_Threshold ) ) THEN"); + F90_Inline(" DO I = 1, NVAR"); + F90_Inline(" IF ( ATOL(I) < PassiveSpc_ATOL_Threshold ) THEN"); + F90_Inline(" NonPassiveSpc_Count = NonPassiveSpc_Count + 1"); + F90_Inline(" NonPassiveSpc_Indices(NonPassiveSpc_Count) = I"); + F90_Inline(" ENDIF"); + F90_Inline(" ENDDO"); + F90_Inline(" ELSE"); + F90_Inline(" NonPassiveSpc_Count = NVAR"); + F90_Inline(" DO I = 1, NVAR"); + F90_Inline(" NonPassiveSpc_Indices(I) = I"); + F90_Inline(" ENDDO"); + F90_Inline(" ENDIF"); + NewLines(1); + + } + // + // Cleanup + // FreeVariable( X ); FreeVariable( I ); FunctionEnd( INITVAL ); FreeVariable( INITVAL ); + if ( useLang == F90_LANG ) { + FreeVariable( PASV_SPC_ATOL_THRESH ); + } } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ diff --git a/util/Makefile_c b/util/Makefile_c index 0ea36a2..61031d5 100644 --- a/util/Makefile_c +++ b/util/Makefile_c @@ -1,6 +1,6 @@ # Set here the desired C compiler and its optimization options -CC = gcc -COPT = -O -Wall +CC ?= gcc +COPT = -O -Wall # To create Matlab gateway routines # Note: use $(CC) as the mex C compiler @@ -57,6 +57,10 @@ distclean: rm -f $(SPOBJ) $(OBJ) KPP_ROOT.exe KPP_ROOT*.dat \ KPP_ROOT_*.c KPP_ROOT_*.h KPP_ROOT*.log KPP_ROOT_*.mexglx *.csv +list: + @echo "CC : $(CC)" + @$(CC) --version + KPP_ROOT_Monitor.o: KPP_ROOT_Monitor.c $(HEADERS) $(CC) $(COPT) -c $< @@ -101,4 +105,3 @@ KPP_ROOT_Stoichiom.o: KPP_ROOT_Stoichiom.c $(HEADERS) $(SPOBJ) KPP_ROOT_Util.o: KPP_ROOT_Util.c $(HEADERS) $(SPOBJ) $(CC) $(COPT) -c $< - diff --git a/util/Makefile_f90 b/util/Makefile_f90 index 3b22644..776a8eb 100644 --- a/util/Makefile_f90 +++ b/util/Makefile_f90 @@ -35,7 +35,7 @@ FOPT_PGF = -Mpreprocess -O -fast -pc 80 -Kieee FC_HPUX = f90 FOPT_HPUX = -O -u +Oall +check=on -FC_GFORTRAN = gfortran +FC_GFORTRAN ?= gfortran FOPT_GFORTRAN = -cpp -O -g -frecursive # define FULL_ALGEBRA for non-sparse integration @@ -204,6 +204,11 @@ distclean: KPP_ROOT_*.f90 KPP_ROOT_*.f90 KPP_ROOT_*.mexglx \ results*.m *.dat *.csv +list: + @echo "COMPILER : $(COMPILER)" + @echo "FC : $(FC)" + @$(FC) --version + KPP_ROOT_Precision.o: KPP_ROOT_Precision.f90 $(FC) $(FOPT) -c $< diff --git a/util/Makefile_upper_F90 b/util/Makefile_upper_F90 index 5953198..e2240aa 100644 --- a/util/Makefile_upper_F90 +++ b/util/Makefile_upper_F90 @@ -35,7 +35,7 @@ FOPT_PGF = -Mpreprocess -O -fast -pc 80 -Kieee FC_HPUX = f90 FOPT_HPUX = -O -u +Oall +check=on -FC_GFORTRAN = gfortran +FC_GFORTRAN ?= gfortran FOPT_GFORTRAN = -cpp -O -g # define FULL_ALGEBRA for non-sparse integration @@ -206,6 +206,11 @@ distclean: KPP_ROOT_*.f90 KPP_ROOT_*.F90 KPP_ROOT_*.mexglx \ results*.m *.dat *.csv +list: + @echo "COMPILER : $(COMPILER)" + @echo "FC : $(FC)" + @$(FC) --version + KPP_ROOT_Precision.o: KPP_ROOT_Precision.F90 $(FC) $(FOPT) -c $<