Skip to content

Commit

Permalink
Merge pull request #115 from PALEOtoolkit/aqchem_updates
Browse files Browse the repository at this point in the history
Updates to support PALEOaqchem generic chemistry
  • Loading branch information
sjdaines authored Mar 18, 2024
2 parents fe46fa9 + 76e898e commit 94e4edb
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 98 deletions.
2 changes: 1 addition & 1 deletion docs/src/Reaction API.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ AbstractVarList
VarList_single
VarList_namedtuple
VarList_tuple
VarList_ttuple
VarList_vector
VarList_vvector
VarList_nothing
VarList_tuple_nothing
```

### Implementing method functions
Expand Down
2 changes: 1 addition & 1 deletion src/ReactionMethod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ call_method_codefn(io::IO, codefn, method::ReactionMethod{M, R, P, 5}, vardata,
Get all [`VariableReaction`](@ref)s from `method` as a Tuple of `Vector{VariableReaction}`
"""
get_variables_tuple(@nospecialize(method::ReactionMethod)) = Tuple(get_variables(vl) for vl in method.varlists)
get_variables_tuple(@nospecialize(method::ReactionMethod); flatten=true) = Tuple(get_variables(vl; flatten) for vl in method.varlists)

"""
get_variables(method::AbstractReactionMethod; filterfn = v -> true) -> Vector{VariableReaction}
Expand Down
31 changes: 27 additions & 4 deletions src/VariableAttributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defining the Variable function to the host ODE or DAE solver.
Explicit ODE problems with dS/dt = F(S) consist of pairs of S::VF_StateExplicit, F::VF_Deriv Variables.
An implicit ODE problem with dU/dt = F(U) where Total variables U are functions U(S) of State variables S
will consist of pairs of U::VF_Total and F::VF_Deriv Variables, and also the same number of S::VF_State (in
will consist of pairs of U::VF_Total and F::VF_Deriv Variables, and also the same number of S::VF_StateTotal (in
no particular order).
Algebraic constraints C(S) = 0 include variables C::VF_Constraint and the same number of S::VF_State,
Expand All @@ -66,6 +66,7 @@ Not all solvers support all combinations.
VF_Constraint = 3
VF_State = 4
VF_Deriv = 5
VF_StateTotal = 6
end

"parse eg \"VF_Deriv\" as Enum VF_Deriv"
Expand Down Expand Up @@ -104,7 +105,7 @@ added with `default_value` when Variable is created), `units`, and an optional `
Note that Variable attributes are stored as a per-Variable `Dict(name => value)`, these definitions are only used to provide defaults,
check types, and provide descriptive metadata.
`ParseFromString` should usually be `false`: a value of `Type T` is then required when calling [`set_attribute!`](@ref).
`ParseFromString` should usually be `Nothing`: a value of `Type T` is then required when calling [`set_attribute!`](@ref).
If `ParseFromString` is `true`, then [`set_attribute!`](@ref) will accept an `AbstractString` and call `Base.parse(T, strvalue)`
to convert to `T`. This allows eg an enum-valued Attribute to be defined by Attribute{EnumType, true} and implementing
parse(EnumType, rawvalue::AbstractString)
Expand Down Expand Up @@ -149,7 +150,10 @@ const StandardAttributes = [
Attribute{Vector{Int}, Nothing}( :operatorID, Int[], false, "", "Reaction operatorIDs that modify this Variable")
Attribute{VariablePhase, VariablePhase}(
:vphase, VP_Undefined, false, "", "phase for concentrations in multiphase cells")
Attribute{String, Nothing}( :totalname, "", false, "", "total Variable name for this species")
Attribute{Vector{String}, Nothing}( :totalnames, String[], false, "", "Vector of total Variable names for this species")
Attribute{String, Nothing}( :rate_processname, "", false, "", "process name for this reaction rate variable")
Attribute{Vector{String}, Nothing}( :rate_species, String[], false, "", "Vector of reactant and product species for this reaction rate variable")
Attribute{Vector{Float64}, Nothing}( :rate_stoichiometry, Float64[], false, "", "Vector of reactant and product stoichiometries for this reaction rate variable")
Attribute{String, Nothing}( :safe_name, "", false, "", "optional short or escaped name for compatibility with other software")
Attribute{String, Nothing}( :long_name, "", false, "", "netcdf long descriptive name")
Attribute{String, Nothing}( :units, "", true, "", "where possible should follow netcdf conventions")
Expand All @@ -160,7 +164,11 @@ const StandardAttributes = [
# Attribute{Bool, Nothing}( :optional, false, true, "", "")
Attribute{Bool, Nothing}( :initialize_to_zero, false, false, "", "request initialize to zero at start of each timestep.")
Attribute{Float64, Nothing}( :vertical_movement, 0.0, false, "m d-1", "vertical advective transport (+ve upwards) in column")
Attribute{String, Nothing}( :diffusivity_speciesname, "", false, "", "species name to define diffusivity")
Attribute{String, Nothing}( :diffusivity_speciesname, "", false, "", "species name to define diffusivity and charge")
Attribute{Union{Float64,Missing}, Nothing}(
:diffusivity, missing, false, "cm^2/s", "species diffusivity")
Attribute{Union{Float64,Missing}, Nothing}(
:charge, missing, false, "", "species charge")
Attribute{Union{Float64,Vector{Float64}}, Nothing}(
:initial_value, 0.0, true, "", "initial value to be applied eg to state or constant variable")
Attribute{Union{Float64,Vector{Float64}}, Nothing}(
Expand Down Expand Up @@ -200,6 +208,21 @@ function is_standard_attribute(attribute::Symbol)
return !isnothing(findfirst(a->a.name==attribute, StandardAttributes))
end


"""
standard_attribute_type(attribute::Symbol) -> DataType
"""
function standard_attribute_type(attribute::Symbol)
idx = findfirst(a->a.name==attribute, StandardAttributes)

if isnothing(idx)
return nothing
else
return attributeType(StandardAttributes[idx])
end
end

###################################
# Internal implementation
##################################
Expand Down
4 changes: 2 additions & 2 deletions src/VariableDomain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ end

function add_dependency(vardom::VariableDomPropDep, varreact::VariableReaction{VT_ReactDependency})
push!(vardom.var_dependencies, varreact)
if get_attribute(varreact, :vfunction) in (VF_StateExplicit, VF_State)
if get_attribute(varreact, :vfunction) in (VF_StateExplicit, VF_StateTotal, VF_State)
@debug " Resetting master variable"
_reset_master!(vardom, varreact)
end
Expand All @@ -371,7 +371,7 @@ end
function add_dependency(vardom::VariableDomContribTarget, varreact::VariableReaction{VT_ReactDependency})
push!(vardom.var_dependencies, varreact)
vf = get_attribute(varreact, :vfunction)
if vf in (VF_StateExplicit, VF_State)
if vf in (VF_StateExplicit, VF_StateTotal, VF_State)
error("attempt to link Dependency with :vfunction==$vf to a VariableDomContribTarget "*
"$(fullname(varreact)) --> $(fullname(vardom))")
end
Expand Down
67 changes: 42 additions & 25 deletions src/VariableReaction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ VarTotalScalar(localname, units, description; attributes::Tuple=(), kwargs...) =
VarTotal(localname, units, description; attributes::Tuple=(), kwargs... ) =
VarContrib(localname, units, description; attributes=(:initialize_to_zero=>true, :field_data=>ScalarData, attributes..., :vfunction=>VF_Total), kwargs...)

VarStateTotalScalar(localname, units, description; attributes::Tuple=(), kwargs...) =
VarDepScalar(localname, units, description; attributes=(:field_data=>ScalarData, attributes..., :vfunction=>VF_StateTotal), kwargs...)
VarStateTotal(localname, units, description; attributes::Tuple=(), kwargs... ) =
VarDep(localname, units, description; attributes=(:field_data=>ScalarData, attributes..., :vfunction=>VF_StateTotal), kwargs...)

# set :initialize_to_zero as :vfunction VF_Deriv is host-dependent so there will be no VT_ReactTarget within the model to handle :initialize_to_zero
VarDerivScalar(localname, units, description; attributes::Tuple=(), kwargs... ) =
VarContribScalar(localname, units, description; attributes=(:initialize_to_zero=>true, :field_data=>ScalarData, attributes..., :vfunction=>VF_Deriv), kwargs...)
Expand Down Expand Up @@ -393,6 +398,8 @@ VarDep, VarDepColumn, VarDepScalar, VarDepStateIndep, VarDepColumnStateIndep, Va
VarTarget, VarTargetScalar,
VarContrib, VarContribColumn, VarContribScalar,
VarStateExplicit, VarStateExplicitScalar,
VarTotal, VarTotalScalar,
VarStateTotal, VarStateTotalScalar,
VarDeriv, VarDerivScalar,
VarState, VarStateScalar,
VarConstraint, VarConstraintScalar
Expand Down Expand Up @@ -443,9 +450,11 @@ Collection and view are determined by `varlist` Type.
function create_accessors(va::AbstractVarList, modeldata::AbstractModelData, arrays_idx::Int) end

"""
get_variables(varlist::AbstractVarList) -> Vector{VariableReaction}
get_variables(varlist::AbstractVarList; flatten=true) -> Vector{VariableReaction}
Return VariableReaction in `varlist`.
Return VariableReaction in `varlist` as a flat Vector.
If `flatten=true`, a Vector-of-Vectors is flattened.
"""
function get_variables(va::AbstractVarList) end

Expand All @@ -462,7 +471,7 @@ struct VarList_single <: AbstractVarList
VarList_single(var; components=false) = new(copy(var), components)
end

get_variables(vl::VarList_single) = [vl.var]
get_variables(vl::VarList_single; flatten=true) = [vl.var]

create_accessors(vl::VarList_single, modeldata::AbstractModelData, arrays_idx::Int) =
create_accessor(vl.var, modeldata, arrays_idx, vl.components)
Expand All @@ -481,7 +490,7 @@ struct VarList_components <: AbstractVarList
new([copy(v) for v in varcollection], allow_unlinked)
end

get_variables(vl::VarList_components) = vl.vars
get_variables(vl::VarList_components; flatten=true) = vl.vars

function create_accessors(vl::VarList_components, modeldata::AbstractModelData, arrays_idx::Int)
accessors_generic = []
Expand Down Expand Up @@ -547,7 +556,7 @@ function VarList_namedtuple_fields(objectwithvars; components=false)
end


get_variables(vl::VarList_namedtuple) = vl.vars
get_variables(vl::VarList_namedtuple; flatten=true) = vl.vars

create_accessors(vl::VarList_namedtuple, modeldata::AbstractModelData, arrays_idx::Int) =
NamedTuple{Tuple(vl.keys)}(create_accessor(v, modeldata, arrays_idx, vl.components) for v in vl.vars)
Expand All @@ -558,18 +567,38 @@ create_accessors(vl::VarList_namedtuple, modeldata::AbstractModelData, arrays_id
Create a `VarList_tuple` describing a collection of `VariableReaction`s,
`create_accessors` will then return a Tuple of data arrays.
An entry of `nothing` in `varcollection` will produce `nothing` in the corresponding
entry in the Tuple of arrays supplied to the Reaction method.
If `components = true`, each Tuple field will be a Vector of data array components.
"""
struct VarList_tuple <: AbstractVarList
vars::Vector{VariableReaction}
vars::Vector{Union{VariableReaction, Nothing}}
components::Bool
VarList_tuple(varcollection; components=false) = new([copy(v) for v in varcollection], components)
VarList_tuple(varcollection; components=false) = new([isnothing(v) ? nothing : copy(v) for v in varcollection], components)
end

get_variables(vl::VarList_tuple) = vl.vars
get_variables(vl::VarList_tuple; flatten=true) = vl.vars

create_accessors(vl::VarList_tuple, modeldata::AbstractModelData, arrays_idx::Int) =
Tuple(create_accessor(v, modeldata, arrays_idx, vl.components) for v in vl.vars)
Tuple(isnothing(v) ? nothing : create_accessor(v, modeldata, arrays_idx, vl.components) for v in vl.vars)


"""
VarList_ttuple(varcollection) -> VarList_ttuple
Create a `VarList_ttuple` describing a collection of collections of `VariableReaction`s,
`create_accessors` will then return a Tuple of Tuples of data arrays.
"""
struct VarList_ttuple <: AbstractVarList
vars::Vector{Vector{VariableReaction}}
VarList_ttuple(vars) = new([[copy(v) for v in vv] for vv in vars])
end

get_variables(vl::VarList_ttuple; flatten=true) = flatten ? vcat(vl.vars...) : vl.vars

create_accessors(vl::VarList_ttuple, modeldata::AbstractModelData, arrays_idx::Int) =
Tuple(Tuple(create_accessor(v, modeldata, arrays_idx, false) for v in vv) for vv in vl.vars)

"""
VarList_vector(varcollection; components=false, forceview=false) -> VarList_vector
Expand All @@ -590,7 +619,7 @@ struct VarList_vector <: AbstractVarList
new([copy(v) for v in varcollection], components, forceview)
end

get_variables(vl::VarList_vector) = vl.vars
get_variables(vl::VarList_vector; flatten=true) = vl.vars

create_accessors(vl::VarList_vector, modeldata::AbstractModelData, arrays_idx::Int) =
[create_accessor(v, modeldata, arrays_idx, vl.components, forceview=vl.forceview) for v in vl.vars]
Expand All @@ -610,7 +639,7 @@ struct VarList_vvector <: AbstractVarList
VarList_vvector(vars; components=false) = new([[copy(v) for v in vv] for vv in vars], components)
end

get_variables(vl::VarList_vvector) = vcat(vl.vars...)
get_variables(vl::VarList_vvector; flatten=true) = flatten ? vcat(vl.vars...) : vl.vars

create_accessors(vl::VarList_vvector, modeldata::AbstractModelData, arrays_idx::Int) =
[[create_accessor(v, modeldata, arrays_idx, vl.components) for v in vv] for vv in vl.vars]
Expand All @@ -624,21 +653,9 @@ Create a placeholder for a missing/unavailable VariableReaction.
struct VarList_nothing <: AbstractVarList
end

get_variables(vl::VarList_nothing) = VariableReaction[]
get_variables(vl::VarList_nothing; flatten=true) = VariableReaction[]
create_accessors(vl::VarList_nothing, modeldata::AbstractModelData, arrays_idx::Int) = nothing

"""
VarList_tuple_nothing(nvar) -> VarList_tuple_nothing
Create a placeholder for `nvar` missing/unavailable VariableReactions.
`create_accessors` will then return an `NTuple{nvar, Nothing}`.
"""
struct VarList_tuple_nothing <: AbstractVarList
nvar::Int
end

get_variables(vl::VarList_tuple_nothing) = VariableReaction[]
create_accessors(vl::VarList_tuple_nothing, modeldata::AbstractModelData, arrays_idx::Int) = ntuple(x->nothing, vl.nvar)

"""
VarList_fields(varcollection) -> VarList_fields
Expand All @@ -651,7 +668,7 @@ struct VarList_fields <: AbstractVarList
VarList_fields(varcollection) = new([copy(v) for v in varcollection])
end

get_variables(vl::VarList_fields) = vl.vars
get_variables(vl::VarList_fields; flatten=true) = vl.vars

function create_accessors(vl::VarList_fields, modeldata::AbstractModelData, arrays_idx::Int)
accessors = []
Expand Down
Loading

0 comments on commit 94e4edb

Please sign in to comment.