Adding a Process#
This guide walks through the steps required to add a new process type to MIAM.
Process Interface#
Every process type must be a struct or class that provides the following
methods. MIAM uses std::variant (not virtual inheritance), so the
interface is enforced by the Model::ForEachProcess visitor pattern.
Required Methods#
CopyWithNewUuid()
MyProcess CopyWithNewUuid() const;
Return a copy of the process with a fresh UUID. Called by
Model::AddProcessesto ensure each registered process instance has a unique identifier.ProcessParameterNames(phase_prefixes)
std::set<std::string> ProcessParameterNames( const std::map<std::string, std::set<std::string>>& phase_prefixes) const;
Return unique names for all state parameters this process needs (e.g., rate constants). The
phase_prefixesmap provides the set of mode/section prefixes that own each phase name.SpeciesUsed(phase_prefixes)
std::set<std::string> SpeciesUsed( const std::map<std::string, std::set<std::string>>& phase_prefixes) const;
Return the set of fully-qualified state variable names that this process reads or writes.
RequiredAerosolProperties()
std::map<std::string, std::vector<AerosolProperty>> RequiredAerosolProperties() const;
Return a map from phase name to the list of aerosol properties this process needs. Return an empty map if none are required.
NonZeroJacobianElements(phase_prefixes, state_indices)
std::set<std::pair<std::size_t, std::size_t>> NonZeroJacobianElements( const std::map<std::string, std::set<std::string>>& phase_prefixes, const std::unordered_map<std::string, std::size_t>& state_indices) const;
Return all (row, col) pairs where this process contributes non-zero Jacobian entries. Include both direct and indirect (through provider) entries.
UpdateStateParametersFunction<DenseMatrixPolicy>(…)
template<typename DenseMatrixPolicy> std::function<void(const std::vector<micm::Conditions>&, DenseMatrixPolicy&)> UpdateStateParametersFunction( const std::map<std::string, std::set<std::string>>& phase_prefixes, const std::unordered_map<std::string, std::size_t>& param_indices) const;
Return a closure that evaluates temperature-dependent constants and writes them into the state parameter matrix.
ForcingFunction<DenseMatrixPolicy>(…)
template<typename DenseMatrixPolicy> std::function<void(const DenseMatrixPolicy&, const DenseMatrixPolicy&, DenseMatrixPolicy&)> ForcingFunction( const std::map<std::string, std::set<std::string>>& phase_prefixes, const std::unordered_map<std::string, std::size_t>& param_indices, const std::unordered_map<std::string, std::size_t>& var_indices, const ProviderMap& providers) const;
Return a closure that adds this process’s contribution to forcing terms. The closure signature is
(params, vars, forcing) -> void.JacobianFunction<DenseMatrixPolicy, SparseMatrixPolicy>(…)
template<typename DenseMatrixPolicy, typename SparseMatrixPolicy> std::function<void(const DenseMatrixPolicy&, const DenseMatrixPolicy&, SparseMatrixPolicy&)> JacobianFunction( const std::map<std::string, std::set<std::string>>& phase_prefixes, const std::unordered_map<std::string, std::size_t>& param_indices, const std::unordered_map<std::string, std::size_t>& var_indices, const SparseMatrixPolicy& jacobian, const ProviderMap& providers) const;
Return a closure that adds Jacobian contributions. Remember: MICM stores −J, so negate all entries relative to the mathematical derivative.
Registering the New Type#
Add the header to [include/miam/process.hpp](include/miam/process.hpp).
Add the type to the
ProcessVariantin [include/miam/model.hpp](include/miam/model.hpp):using ProcessVariant = std::variant< DissolvedReversibleReaction, HenryLawPhaseTransfer, MyNewProcess // ← add here >;
That’s it — the std::visit in ForEachProcess will automatically
dispatch to the new type.
Sign Convention Checklist#
Forcing: compute the mathematical rate and write it directly (positive for production, negative for consumption).
Jacobian: compute the mathematical ∂f/∂x, then negate before writing into the sparse Jacobian matrix.
Verify with a unit test that compares analytical Jacobian entries against finite-difference approximations.