Skip to content

Introduce aerosol chemistry validation and parser support#282

Open
boulderdaze wants to merge 25 commits into
mainfrom
271-add-miam-parser
Open

Introduce aerosol chemistry validation and parser support#282
boulderdaze wants to merge 25 commits into
mainfrom
271-add-miam-parser

Conversation

@boulderdaze

@boulderdaze boulderdaze commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

This PR:

  • Adds aerosol representations and processes functions
  • Adds check schema, validation function for aerosol
  • Adds an integration test for the CAM cloud chemistry
  • Makes reactions an optional key, since an aerosol configuration does not always require reactions. See the code and comments for details.
  • Part of Add MIAM types to canonical Mechanism #271

Notes:

  • I noticed that the emissions PR creates its own directory, which I think is a good approach for keeping things clean and organized. I considered doing the same for the aerosol model, but decided against it. Gas-phase chemistry and aerosol processes can be used together within a single chemistry system, and their configurations are often closely related.
  • More unit tests will be added in a follow up PR.
  • I restructured the Validate function into ValidateGasModel and introduced a separate ValidateAerosolModel.
Errors ValidateGasModel(const Mechanism& mechanism);
Errors ValidateAerosolModel(const Mechanism& mechanism);

During aerosol validation, the relationship between phases and species(eg. condensed phase and species, gas phase and species, solvent, molecular weight, density ) cannot be expressed in the current semantics::Input because the required relationship information is lost during flattening. It does not preserve which species belongs to which phase.

The intermediate type that I tried to introduced AerosolProcessRef also loses the structure by dropping the association between a specific species and its phase context.

The current aerosol validation cannot preserve the error locations for the reasons above. This will be addressed in #284

@boulderdaze boulderdaze changed the title Add aerosol parser Add aerosol chemistry parser Jun 26, 2026
@codecov-commenter

codecov-commenter commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 31.57%. Comparing base (04d2f08) to head (534eabb).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #282   +/-   ##
=======================================
  Coverage   31.57%   31.57%           
=======================================
  Files           4        4           
  Lines          19       19           
=======================================
  Hits            6        6           
  Misses         13       13           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@boulderdaze boulderdaze self-assigned this Jun 26, 2026
@boulderdaze boulderdaze added this to the Cloud Chemistry milestone Jun 26, 2026
@boulderdaze boulderdaze requested a review from K20shores June 26, 2026 04:45
@boulderdaze boulderdaze marked this pull request as ready for review June 26, 2026 04:45

@K20shores K20shores left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to divorce the validation and parsing so that in-code mechanism can be validated. That means we need to update Validate to include aerosol validation

Comment thread src/detail/v1/aerosol_type_parsers.hpp Outdated
{
namespace
{
Errors CheckArrheniusReferenceTemperatureSchema(const YAML::Node& object)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

in the gas-phase parsing, we include this stuff directly in the parse function. Any reason we are doing it here?

@boulderdaze boulderdaze Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The one in the gas-phase parser for arrhenius includes A,B,C,D,E as well as the phase, reactants and products.

The aerosol model defines rate constant to calculate equilibrium rate constant in the form of arrhenius expression, but it only takes A, C values. This configuration calls micm::CalculateArrhenius in miam implementation, which is why it remains as arrhneinus struct in aerosol types.

On the other hand, henrys law constant uses a reference temperature, which uses van't hoff equation to calculate the rate constant. It depends on temperature difference. That's why the ArrheniusReferenceTemperature type was crated.

The direct answer to your question is that the required and optional keys should be different.

Errors CheckArrheniusSchema(const YAML::Node& object)
{
    const std::vector<std::string_view> required_keys = { keys::A, keys::C };
    const std::vector<std::string_view> optional_keys = { keys::type };
    return CheckSchema(object, required_keys, optional_keys);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah, that wasn't my question. My question is why the schema checks are here and not in src/v1/aerosol_type_parsers.cpp. All of the gas phase checks have their schema checks include in the parsers.

Comment thread src/v1/aerosol_type_schema.cpp Outdated
Comment thread src/v1/parser.cpp Outdated
@boulderdaze boulderdaze requested a review from K20shores June 27, 2026 02:25
@boulderdaze boulderdaze changed the title Add aerosol chemistry parser Introduce aerosol chemistry validation and parser support Jun 27, 2026

@K20shores K20shores left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A couple of comments, but nothing that should hold up a merge. There's only one comment that wouldn't be addressed by a future issue anyway. If you like the way things look now, I'm happy to accept it

{
std::string name;
std::optional<double> diffusion_coefficient;
std::optional<double> density;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do we know what this is? Is this just the molecular weight? If so, it's duplicated in the species

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.

It is the density of a species in a given phase, so it's expected to be different for solids, liquids, etc.

      "name": "AQUEOUS",
      "species": [
        "SO2", "H2O2", "O3", "Hp", "OHm", "HSO3m", "SO3mm", "SO4mm", "SO2OOHm",
        { "name": "H2O", "density [kg m-3]": 997.0 }
      ]

Comment on lines +22 to +24
// Aerosol cross-references are validated separately by ValidateAerosolModel, which works on the
// domain structs directly because it needs phase membership and optional-property values that
// this name-only view cannot carry.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The semantic input for an aerosol model doesn't yet exist. I suggest we do that as part of this PR, and then we can operate on the semantic inputs and share structural validation between in-code mechanisms and parsed mechanisms.

@boulderdaze boulderdaze Jul 1, 2026

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.

This work requires to restructure *Def classes. Right now, they only store values in flat arrays without any information about relationships (which species belong to which phases or where the solvent is). I think the restrucuting work is outside the scope of this PR. As mentioned in the comments, we can track it separately in the issue:

{
namespace
{
Errors CheckArrheniusReferenceTemperatureSchema(const YAML::Node& object)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah, that wasn't my question. My question is why the schema checks are here and not in src/v1/aerosol_type_parsers.cpp. All of the gas phase checks have their schema checks include in the parsers.

return errors;
}

Errors CheckAerosolProcessesSchema(const YAML::Node& processes_list)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

To me this reads like each of the types could be their own functions that we dispatch, similar to how we do for each different reaction type. Do you prefer this apporach?

Comment thread src/v1/parser.cpp
Comment on lines +383 to +384
// Uses the same ValidateSemantics engine as ValidateGasModel, but with
// YAML-derived input so errors include source locations.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ValidateGasModel also includes line information because we have the semantic reference inputs, which I feel we should also add for aerosols

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The gas model can store them in a flat array without relationship information unlike aerosol.

Comment thread src/v1/parser.cpp
// pair 'aerosol representations' + 'aerosol processes'. The two modes may also coexist.
const bool has_reactions = static_cast<bool>(object[keys::reactions]);
const bool has_aerosol_representations = static_cast<bool>(object[keys::aerosol_representations]);
const bool has_aerosol_processes = static_cast<bool>(object[keys::aerosol_processes]);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to replicate these checks in src/validate.cpp so that in-code mechanisms also have this checked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants