You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/catalyst_functionality/chemistry_related_functionality.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -82,16 +82,17 @@ as the components `C`, `H`, and `O` are not declared as a species anywhere. Plea
82
82
#### Designating metadata and default values for compounds
83
83
Just like for normal species, it is possible to designate metadata and default values for compounds. Metadata is provided after the compound name, but separated from it by a `,`:
84
84
```@example chem1
85
-
@compound CO2, [unit="mol"] ~ C + 2O
85
+
@compound (CO2, [unit="mol"]) ~ C + 2O
86
86
```
87
-
Default values are designated using `=`, and provided directly after the compound name. If default values are given, the left-hand side must be grouped using `()`:
87
+
Default values are designated using `=`, and provided directly after the compound name.:
88
88
```@example chem1
89
89
@compound (CO2 = 2.0) ~ C + 2O
90
90
```
91
91
If both default values and meta data are provided, the metadata is provided after the default value:
92
92
```@example chem1
93
93
@compound (CO2 = 2.0, [unit="mol"]) ~ C + 2O
94
94
```
95
+
In all of these cases, the side to the left of the `~` must be enclosed within `()`.
95
96
96
97
## Balancing chemical reactions
97
98
One use of defining a species as a compound is that they can be used to balance reactions to that the number of components are the same on both sides. Catalyst provides the `balance_reaction` function, which takes a reaction, and returns a balanced version. E.g. let us consider a reaction when carbon dioxide is formed from carbon and oxide `C + O --> CO2`. Here, `balance_reaction` enables us to find coefficients creating a balanced reaction (in this case, where the number of carbon and oxygen atoms are the same on both sides). To demonstrate, we first created the unbalanced reactions:
Copy file name to clipboardExpand all lines: src/chemistry_functionality.jl
+42-25Lines changed: 42 additions & 25 deletions
Original file line number
Diff line number
Diff line change
@@ -30,48 +30,64 @@ end
30
30
31
31
# Declares compound error messages:
32
32
const COMPOUND_CREATION_ERROR_BASE ="Malformed input to @compound. Should use form like e.g. \"@compound CO2 ~ C + 2O\"."
33
-
const COMPOUND_CREATION_ERROR_BAD_SEPARATOR ="Malformed input to @compound. Left-hand side (the compound) and the right-hand side (the components) should be separated by a \"~\" (e.g. \"@compound CO2 ~ C + 2O\"). If the left hand side contains metadata or default values, this should be enclosed by \"()\" (e.g. \"@compound (CO2 = 1.0, [output=true]) ~ C + 2O\")."
34
-
constCOMPOUND_CREATION_ERROR_DEPENDENT_VAR_GIVEN="Left hand side of @compound is malformed. Does the compound depend on a independent variable (e.g. \"CO2(t)\")? If so, that should not be the case, these are inferred from the compounds."
33
+
const COMPOUND_CREATION_ERROR_BAD_SEPARATOR ="Malformed input to @compound. Left-hand side (the compound) and the right-hand side (the components) should be separated by a \"~\" (e.g. \"@compound CO2 ~ C + 2O\"). If the left hand side contains metadata and/or default values, this should be enclosed by \"()\" (e.g. \"@compound (CO2 = 1.0, [output=true]) ~ C + 2O\")."
34
+
constCOMPOUND_CREATION_ERROR_DEPENDENT_VAR_REQUIRED="When the components (collectively) have more than 1 independent variable, independent variables have to be specified for the compound (e.g. `@compound CO2(t,s) ~ C + 2O`). This is required since the @compound macro cannot infer the correct order of the independent variables."
35
35
36
36
# Function managing the @compound macro.
37
37
functionmake_compound(expr)
38
38
# Error checks.
39
39
(expr isa Expr) ||error(COMPOUND_CREATION_ERROR_BASE)
((expr.args[2].args[1] isa Expr) && expr.args[2].args[1].head ==:call) &&error(COMPOUND_CREATION_ERROR_DEPENDENT_VAR_GIVEN)
45
-
((expr.args[2].args[1] isa Expr) && (expr.args[2].args[1].args[1] isa Expr) && expr.args[2].args[1].args[1].head ==:call) &&error(COMPOUND_CREATION_ERROR_DEPENDENT_VAR_GIVEN)
46
-
end
47
41
48
-
# Loops through all components, add the component and the coefficients to the corresponding vectors (cannot extract directly using e.g. "getfield.(composition, :reactant)" because then we get something like :([:C, :O]), rather than :([C, O]))
42
+
# Loops through all components, add the component and the coefficients to the corresponding vectors
43
+
# Cannot extract directly using e.g. "getfield.(composition, :reactant)" because then
44
+
# we get something like :([:C, :O]), rather than :([C, O]).
components = :([]) # Becomes something like :([C, O]).
51
-
coefficients = :([]) # Becomes something like :([1, 2]).
46
+
components = :([]) # Becomes something like :([C, O]).
47
+
coefficients = :([]) # Becomes something like :([1, 2]).
52
48
for comp in composition
53
49
push!(components.args, comp.reactant)
54
50
push!(coefficients.args, comp.stoichiometry)
55
51
end
56
52
57
-
# Extracts the composite species name, as well as the expression which creates it (with e.g. meta data and default values included).
58
-
species_expr = expr.args[2] # E.g. :(CO2 = 1.0, [metadata=true])
59
-
species_expr =insert_independent_variable(species_expr, :(..)) # Prepare iv addition, i.e. turns CO to CO(..).
60
-
species_name =find_varname_in_declaration(expr.args[2]) # E.g. :CO2
61
-
ivs_get_expr = :(unique(reduce(vcat,[arguments(ModelingToolkit.unwrap(iv)) for iv in$components]))) # Expression which when evaluated gives a vector with all the ivs of the components.
53
+
# Extracts:
54
+
# - The compound species name (species_name, e.g. `:CO2`).
55
+
# - Any ivs attached to it (ivs, e.g. `[]` or `[t,x]`).
56
+
# - The expression which creates the compound (species_expr, e.g. `CO2 = 1.0, [metadata=true]`).
# Expression which when evaluated gives a vector with all the ivs of the components.
64
+
ivs_get_expr = :(unique(reduce(vcat,[arguments(ModelingToolkit.unwrap(iv)) for iv in$components])))
62
65
63
66
# Creates the found expressions that will create the compound species.
64
-
# The `Expr(:escape, :(...))` is required so that the expressions are evaluated in the scope the users use the macro in (to e.g. detect already exiting species).
65
-
species_declaration_expr =Expr(:escape, :(@species$species_expr)) # E.g. `@species CO2(..)`
66
-
iv_designation_expression =Expr(:escape, :($species_name =$(species_name)($(ivs_get_expr)...))) # E.g. `CO2 = CO2([...]..)` where [...] is something which evaluates to a vector with all the ivs of the components.
iv_check_expr =Expr(:escape, :(issetequal(arguments(ModelingToolkit.unwrap($species_name)), $ivs_get_expr) ||error("The independent variable(S) provided to the compound ($(arguments(ModelingToolkit.unwrap($species_name)))), and those of its components ($($ivs_get_expr)))), are not identical.")))
# Creates an empty block containing the output call.
108
124
compound_declarations =Expr(:block)
109
125
110
-
# Creates a compound creation set of lines (4 in total) for each line. Loops through all 4x[Number of compounds] liens and add them to compound_declarations.
126
+
# Creates a compound creation set of lines (4 in total) for each compound line in expr.
127
+
# Loops through all 4x[Number of compounds] lines and add them to compound_declarations.
111
128
compound_calls = [Catalyst.make_compound(line) for line in expr.args]
112
129
for compound_call in compound_calls, line in MacroTools.striplines(compound_call).args
0 commit comments