Skip to content

MUSICA-MICM chemistry solver#1425

Open
dwfncar wants to merge 3 commits intoMPAS-Dev:developfrom
NCAR:musica_micm_integration
Open

MUSICA-MICM chemistry solver#1425
dwfncar wants to merge 3 commits intoMPAS-Dev:developfrom
NCAR:musica_micm_integration

Conversation

@dwfncar
Copy link
Copy Markdown
Contributor

@dwfncar dwfncar commented Mar 24, 2026

Added the MUSICA-MICM ODE chemistry solver.
MICM initialization, time-stepping, and finalization are called through
the existing chemistry hooks in mpas_atm_chemistry.F.
ABBA mechanism is hard coded for testing.

ABBA MICM configuration

The ABBA mechanism used for testing is two USER_DEFINED reactions (a
forward dissociation AB → A + B and a reverse recombination
A + B → AB) with prescribed scaling factors. abba.yaml:

version: "1.0.0"
name: ABBA
species:
  - name: A
    __absolute tolerance: 1e-4
    __long name: atom_A
    __do advect: true
    __initial concentration: 0.0
    __molar mass: 0.029
  - name: B
    __absolute tolerance: 1e-4
    __long name: atom_B
    __do advect: true
    __initial concentration: 0.0
    __molar mass: 0.029
  - name: AB
    __absolute tolerance: 1e-4
    __long name: molecule_AB
    __do advect: true
    __initial concentration: 1.0
    __molar mass: 0.058

phases:
  - name: gas
    species:
      - A
      - B
      - AB

reactions:
  - type: USER_DEFINED
    gas phase: gas
    reactants:
      - species name: AB
        coefficient: 1
    products:
      - species name: A
        coefficient: 1
      - species name: B
        coefficient: 1
    scaling factor: 2.0e-3
    name: forward_AB_to_A_B

  - type: USER_DEFINED
    gas phase: gas
    reactants:
      - species name: A
        coefficient: 1
      - species name: B
        coefficient: 1
    products:
      - species name: AB
        coefficient: 1
    scaling factor: 1.0e-3
    name: reverse_A_B_to_AB

Smoke test

Built on Ubuntu with the conda-forge mpas env (gfortran / openmpi / netcdf / pnetcdf) and MUSICA=true, linked against MUSICA-Fortran 0.14.5 / MICM 3.11.0. Ran the supercell idealized case with config_micm_file='abba.yaml', 30 s simulated time, 8 MPI ranks. Results:

Species t=0 (YAML init) t=3 s t=6 s
AB 1.0 0.994018 0.988072
A 0.0 0.005982 0.011921
B 0.0 0.005982 0.011921

Atom conservation [X] + [AB] = 1.0 holds exactly for X ∈ {A, B}. Solver: 9 steps, 9 accepted / 0 rejected, final_time = 3.0 s matches config_dt. Zero model errors.

Integrate the MUSICA-MICM ODE chemistry solver with the MPAS atmosphere
core. MICM initialization, time-stepping, and finalization are called
through the existing chemistry hooks in mpas_atm_chemistry.F.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dwfncar dwfncar marked this pull request as draft March 24, 2026 02:14
@dwfncar dwfncar marked this pull request as ready for review March 30, 2026 17:48
@mgduda mgduda added Atmosphere Chemistry Changes specific to chemistry in MPAS labels Apr 7, 2026
@mgduda mgduda self-requested a review April 7, 2026 22:11
Comment thread src/core_init_atmosphere/Registry.xml Outdated

<var name="qB" array_group="passive" units="kg kg^{-1}"
description="Atomic B mixing ratio"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These variables are declared here in the Registry.xml file for the init_atmosphere core, but it doesn't look like there's any corresponding code changes to actually provide values for them. Is there some offline script that's used to initialize the qAB, qA, and qB fields? Or are they just expected to be zero in the initial conditions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I use an offline python script to initialize the test tracers, e.g. to a sinusoidal pattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For symmetry with core_atmosphere/Registry.xml, these have also been moved to the end of the scalars var_array with array_group="chem_test" in 7a15848.

Comment thread src/core_atmosphere/Registry.xml Outdated

<var name="qB" array_group="passive" units="kg kg^{-1}"
description="Atomic B mixing ratio"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In principle, the order shouldn't matter too much, but it might be nicer to add these at the end of the scalars var_array. We could also give them a more descriptive group name, perhaps something like chem_test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved to the end of scalars with array_group="chem_test" in 7a15848.

Comment thread src/core_atmosphere/Registry.xml Outdated

<var name="tend_qB" name_in_code="qB" array_group="passive" units="kg m^{-3} s^{-1}"
description="Tendency of atomic B mass per unit volume divided by d(zeta)/dz"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Similar to the comment for the scalars var_array, perhaps we can add these at the end of the var_array using the chem_test array group?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved to the end of scalars_tend with array_group="chem_test" in 7a15848.

!-------------------------------------------------------------------------
module mpas_atm_chemistry

use mpas_kind_types, only : StrKIND, RKIND
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It doesn't look like StrKIND is only used in chemistry_init, where there's already an use statement to import StrKIND.
Also, it looks like RKIND is only used in the chemistry_step routine. Would it be worth moving the use statement to import RKIND to chemistry_step for consistency with the import of real64?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. The module-level use mpas_kind_types was redundant (chemistry_init already imports StrKIND locally, and RKIND is only needed in chemistry_step). In 7a15848 the module-level import is removed and use mpas_kind_types, only : RKIND is moved into chemistry_step.

! TEMPORARY: ABBA specific initial concentrations
real(real64), allocatable :: init_ab(:)
real(real64), allocatable :: init_a(:)
real(real64), allocatable :: init_b(:)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It doesn't look like these variables are actually used. Is there otherwise a reason for declaring them here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These were placeholders for initial-concentration seeding that had not been wired up yet. In 7a15848 they are replaced with a single reused initial_profile(:) populated per species in a loop over state%species_ordering, using micm%get_species_property_double() with the INITIAL_CONCENTRATION_PROPERTY constant. MICM species concentrations are now initialized from the __initial concentration field in the MICM YAML, so the hard-coded ABBA scaffolding is gone.

real(real64), allocatable :: init_a(:)
real(real64), allocatable :: init_b(:)

character(len=*), parameter :: INITIAL_CONCENTRATION_PROPERTY = "__initial concentration"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It doesn't look like this parameter is used anywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now used in 7a15848 as the property key passed to micm%get_species_property_double() to read initial concentrations from the MICM YAML. See the reply on the init_ab/init_a/init_b thread for the full pattern.

@mgduda
Copy link
Copy Markdown
Contributor

mgduda commented Apr 8, 2026

@dwfncar Is there a MICM configuration file that's needed in order to run with the ABBA mechanism? If so (and assuming it's short), could you include the contents of that configuration file in the PR description?

dwfncar and others added 2 commits April 18, 2026 11:56
- Registry (core_atmosphere, core_init_atmosphere): move qAB/qA/qB and
  tend_qAB/tend_qA/tend_qB to the end of their scalars/scalars_tend
  var_arrays with array_group="chem_test" (per mgduda review comments).
- mpas_atm_chemistry.F: move RKIND import from module level into
  chemistry_step, where it is the only consumer.
- mpas_musica.F: wire up INITIAL_CONCENTRATION_PROPERTY through
  micm%get_species_property_double() so initial species concentrations
  from the MICM YAML (__initial concentration) are loaded into
  state%concentrations at init. Replace unused init_ab/init_a/init_b
  placeholders with a single reused initial_profile(:). Also call
  assign_rate_parameters after the species loop so USER_DEFINED
  reactions in the ABBA mechanism have a defined rate. Smoke test on
  the supercell case now shows physically correct AB -> A + B decay
  with atom conservation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
musica_step now treats non-convergence and early termination as
fatal errors that set error_code and return with a descriptive
error_message, instead of just logging a warning. The caller
(mpas_atm_chemistry:chemistry_step) already routes non-zero
error_code through MPAS_LOG_CRIT, so the model now aborts on a
silent MICM failure rather than advancing with stale state.

Two checks added:
- solver_state must be 'Converged' (previously only log-warned)
- solver_stats%final_time() must reach the requested time_step
  (catches partial/interrupted solves that would otherwise be
  invisible)

log_solver_stats is now called before the checks so the stats
leading to a failure are always in the log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dwfncar
Copy link
Copy Markdown
Contributor Author

dwfncar commented Apr 18, 2026

Done — the full abba.yaml is now in the PR description.

@dwfncar
Copy link
Copy Markdown
Contributor Author

dwfncar commented Apr 18, 2026

@mgduda Thanks for the review. All six review threads addressed in 7a15848; individual replies left on each.

One extra, unsolicited change in a follow-up commit (752f895) that I want to flag because it changes semantics: musica_step now propagates non-convergence and early termination as errors (error_code = 1 + descriptive error_message) instead of just logging a warning. Since chemistry_step already routes non-zero error_code through MPAS_LOG_CRIT, the model will now abort on silent MICM solver failures rather than advancing with stale state. Happy to split that into a separate PR if you would prefer to review it in isolation.

@dwfncar dwfncar requested a review from mgduda April 18, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Atmosphere Chemistry Changes specific to chemistry in MPAS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants