Species
ChemistryLab.AbstractSpeciesChemistryLab.AggregateStateChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.CemSpeciesChemistryLab.ClassChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesChemistryLab.SpeciesBase.getindexBase.getpropertyBase.hashBase.haskeyBase.isequalBase.promote_ruleBase.setindex!Base.setproperty!Base.showBase.showBase.showBase.showChemistryLab._identity_symbolChemistryLab.aggregate_stateChemistryLab.applyChemistryLab.atomsChemistryLab.atoms_chargeChemistryLab.cemformulaChemistryLab.chargeChemistryLab.check_mendeleevChemistryLab.classChemistryLab.coloredChemistryLab.coloredChemistryLab.complete_thermo_functions!ChemistryLab.componentsChemistryLab.componentsChemistryLab.exprChemistryLab.exprChemistryLab.find_speciesChemistryLab.formulaChemistryLab.mainformulaChemistryLab.mainformulaChemistryLab.mendeleev_filterChemistryLab.nameChemistryLab.ordered_dict_with_defaultChemistryLab.oxidesChemistryLab.oxides_chargeChemistryLab.phreeqcChemistryLab.phreeqcChemistryLab.pprintChemistryLab.pprintChemistryLab.propertiesChemistryLab.symbolChemistryLab.unicodeChemistryLab.unicodeChemistryLab.with_aggregate_stateChemistryLab.with_classChemistryLab.with_symbol
ChemistryLab.AbstractSpecies Type
abstract type AbstractSpecies endAbstract base type for all chemical species representations.
All concrete species types (Species, CemSpecies) inherit from this type.
ChemistryLab.AggregateState Type
@enum AggregateStateEnumeration for species aggregate states.
Values
AS_UNDEF: undefined state.AS_AQUEOUS: aqueous solution.AS_CRYSTAL: crystalline solid.AS_GAS: gas phase.AS_LIQUID: a pure liquid phase.AS_SURFACE: bound to a surface site — not a bulk phase at all.
Correspondence with ThermoFun
An imported label is matched by name, so ThermoFun's numbering and this enum's are independent and neither constrains the other. The codes below are the ones its files carry, counted over the databases shipped in data/:
| ThermoFun code | label | occurrences | here |
|---|---|---|---|
| 4 | AS_AQUEOUS | 2183 | AS_AQUEOUS |
| 3 | AS_CRYSTAL | 870 | AS_CRYSTAL |
| 0 | AS_GAS | 57 | AS_GAS |
| 1 | AS_LIQUID | 1 | AS_LIQUID |
| — | not stated | — | AS_UNDEF |
AS_SURFACE has no ThermoFun counterpart: no database describes a surface complex, because it is a modeling declaration rather than a substance record.
Both AS_LIQUID and AS_SURFACE are appended rather than inserted, so no existing member changes its integer value. It is here because a shipped database uses it – metallic mercury in slop98-inorganic-thermofun.json – and until it was added that record read as AS_UNDEF, an import silently losing what the file said.
A label with no member to land on takes the fallback, and a fallback is a valid value, so nothing announces the loss. test/databases.jl therefore walks the substances of every shipped database and requires each label to resolve, which is what turns the table above from a claim into a check.
ChemistryLab.CemSpecies Type
struct CemSpecies{T<:Number,S<:Number} <: AbstractSpeciesCement chemistry species representation using oxide notation.
Fields
name::String: human-readable name.symbol::String: species symbol.formula::Formula{T}: atomic composition formula.cemformula::Formula{S}: oxide notation formula.aggregate_state::AggregateState: physical state.class::Class: chemical class.properties::OrderedDict{Symbol,PropertyType}: thermodynamic and other properties.
Examples
julia> s = CemSpecies("C3A"; name="Tricalcium aluminate");
julia> oxides(s)
OrderedDict{Symbol, Int64} with 2 entries:
:C => 3
:A => 1ChemistryLab.CemSpecies Method
CemSpecies(f::AbstractString; name, symbol, aggregate_state, class, properties) -> CemSpeciesConstruct a CemSpecies from an oxide formula string.
Examples
julia> s = CemSpecies("C3S"; name="Alite");
julia> oxides(s)
OrderedDict{Symbol, Int64} with 2 entries:
:C => 3
:S => 1ChemistryLab.CemSpecies Method
CemSpecies(s::CemSpecies; kwargs...) -> CemSpeciesCopy constructor for CemSpecies with optional field overrides.
ChemistryLab.CemSpecies Method
CemSpecies(cemformula::Formula; name, symbol, aggregate_state, class, properties) -> CemSpeciesConstruct a CemSpecies from an oxide formula.
Arguments
cemformula: Formula object in oxide notation.name: species name (default: formula expression).symbol: species symbol (default: formula expression).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
ChemistryLab.CemSpecies Method
CemSpecies(s::Species; name, symbol, aggregate_state, class, properties) -> CemSpeciesConvert a Species to CemSpecies by decomposing into oxide notation.
Throws an error if the species cannot be decomposed into cement oxides.
Arguments
s: source Species.name: override name (default: keep original).symbol: override symbol (default: keep original).aggregate_state: override state (default: keep original).class: override class (default: keep original).properties: override properties (default: keep original).
ChemistryLab.CemSpecies Method
CemSpecies(oxides::Pair{Symbol,T}...; name, symbol, aggregate_state, class, properties) where {T} -> CemSpeciesConstruct a CemSpecies from oxide => coefficient pairs.
Examples
julia> s = CemSpecies(:C => 3, :S => 2; name="C3S2");
julia> oxides(s)
OrderedDict{Symbol, Int64} with 2 entries:
:C => 3
:S => 2ChemistryLab.CemSpecies Method
CemSpecies(; expr, name, symbol, aggregate_state, class, properties) -> CemSpeciesConstruct a CemSpecies from keyword arguments with an oxide formula string.
ChemistryLab.CemSpecies Method
CemSpecies(oxides::AbstractDict{Symbol,T}, charge=0; name, symbol, aggregate_state, class, properties) where {T} -> CemSpeciesConstruct a CemSpecies from an oxide composition dictionary.
Arguments
oxides: dictionary mapping oxide symbols to stoichiometric coefficients.charge: formal charge (default 0).name: species name (default: computed from formula).symbol: species symbol (default: name).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
ChemistryLab.CemSpecies Method
CemSpecies{S}(s::CemSpecies; kwargs...) where {S} -> CemSpecies{S}Construct a CemSpecies with a specific coefficient type from another CemSpecies.
ChemistryLab.CemSpecies Method
CemSpecies{S,T}(s::CemSpecies; kwargs...) where {S,T} -> CemSpecies{S,T}Construct a CemSpecies with specific coefficient types from another CemSpecies.
ChemistryLab.Class Type
@enum ClassEnumeration for species chemical classes.
Values
SC_UNDEF: undefined class.SC_AQSOLVENT: aqueous solvent.SC_AQSOLUTE: aqueous solute.SC_COMPONENT: component.SC_GASFLUID: gas or fluid.SC_SSENDMEMBER: end-member of a solid solution phase.SC_SURFCOMPLEX: a species occupying a surface site — the free site itself as much as an occupied one, since both take part in the site mixing and both consume the family's site budget.
ChemistryLab.Species Type
struct Species{T<:Number} <: AbstractSpeciesStandard chemical species representation using atomic composition.
Fields
name::String: human-readable name.symbol::String: species symbol.formula::Formula{T}: chemical formula with stoichiometric coefficients.aggregate_state::AggregateState: physical state.class::Class: chemical class.properties::OrderedDict{Symbol,PropertyType}: thermodynamic and other properties.
Examples
julia> s = Species("H2O"; name="Water", aggregate_state=AS_AQUEOUS);
julia> atoms(s)
OrderedDict{Symbol, Int64} with 2 entries:
:H => 2
:O => 1ChemistryLab.Species Method
Species(f::AbstractString; name, symbol, aggregate_state, class, properties) -> SpeciesConstruct a Species from a formula string.
Arguments
f: formula string to parse.name: species name (default: f).symbol: species symbol (default: f).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
Examples
julia> s = Species("Ca+2"; aggregate_state=AS_AQUEOUS);
julia> charge(s)
2ChemistryLab.Species Method
Species(s::CemSpecies; name, symbol, aggregate_state, class, properties) -> SpeciesConvert a CemSpecies to Species using atomic composition.
Arguments
s: source CemSpecies.name: override name (default: keep original).symbol: override symbol (default: keep original).aggregate_state: override state (default: keep original).class: override class (default: keep original).properties: override properties (default: keep original).
ChemistryLab.Species Method
Species(formula::Formula; name, symbol, aggregate_state, class, properties) -> SpeciesConstruct a Species from a Formula object.
Arguments
formula: Formula object with atomic composition.name: species name (default: formula expression).symbol: species symbol (default: formula expression).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
Examples
julia> f = Formula("NaCl");
julia> s = Species(f; name="Sodium chloride", aggregate_state=AS_CRYSTAL);
julia> name(s)
"Sodium chloride"ChemistryLab.Species Method
Species(s::Species; kwargs...) -> SpeciesCopy constructor for Species with optional field overrides.
ChemistryLab.Species Method
Species(atoms::Pair{Symbol,T}...; name, symbol, aggregate_state, class, properties) where {T} -> SpeciesConstruct a Species from element => coefficient pairs.
Examples
julia> s = Species(:H => 2, :O => 1; name="Water");
julia> atoms(s)
OrderedDict{Symbol, Int64} with 2 entries:
:H => 2
:O => 1ChemistryLab.Species Method
Species(; expr, name, symbol, aggregate_state, class, properties) -> SpeciesConstruct a Species from keyword arguments.
Arguments
expr: formula string to parse (default: "").name: species name (default: expr).symbol: species symbol (default: expr).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
ChemistryLab.Species Method
Species(atoms::AbstractDict{Symbol,T}, charge=0; name, symbol, aggregate_state, class, properties) where {T} -> SpeciesConstruct a Species from an atomic composition dictionary.
Arguments
atoms: dictionary mapping element symbols to stoichiometric coefficients.charge: formal charge (default 0).name: species name (default: computed from formula).symbol: species symbol (default: name).aggregate_state: physical state (default: AS_UNDEF).class: chemical class (default: SC_UNDEF).properties: property dictionary (default: empty OrderedDict).
ChemistryLab.Species Method
Species{T}(s::Species; kwargs...) where {T} -> Species{T}Construct a Species with a specific coefficient type from another Species.
Base.getindex Method
Base.getindex(s::AbstractSpecies, i::Symbol) -> AnyAccess species components, atoms, or properties by symbol key.
Returns 0 if the key is not found.
Examples
julia> s = Species("H2O");
julia> s[:H]
2
julia> s[:N]
0Base.getproperty Method
Base.getproperty(s::AbstractSpecies, sym::Symbol) -> AnyAccess species fields or registered properties.
Throws an error if the symbol is neither a field nor a property.
Base.hash Method
Base.hash(s::AbstractSpecies, h::UInt) -> UIntHash a species on exactly what Base.isequal compares — formula, aggregate state, class, and _identity_symbol — which is what Dict and Set require of the pair.
It used to hash the stored symbol while isequal ignored it altogether, so two species that compared equal could land in different buckets.
Base.haskey Method
Base.haskey(s::AbstractSpecies, sym::Symbol) -> BoolCheck if a property key exists in the species properties dictionary.
Base.isequal Method
Base.isequal(s1::AbstractSpecies, s2::AbstractSpecies) -> BoolWhether two species are the same species: same formula, aggregate state, class, and whatever the symbol adds to that.
Why the symbol is part of it
Because the first three do not separate polymorphs, and a polymorph is a different substance. Calcite and aragonite are both CaCO3, both AS_CRYSTAL, both SC_COMPONENT; in CEMDATA18 their standard Gibbs energies differ by 821 J/mol, which at 298 K is 0.33 in ln K — the whole difference in solubility between them. Without the symbol they compared equal, and a Dict keyed by species could not tell them apart.
It also restores the invariant isequal ⟹ hash, which Base.hash had always broken by including the symbol when this did not: Dict(calcite => 1) raised KeyError on aragonite while calcite == aragonite said true.
Two spellings of one formula remain one species, because _identity_symbol drops a symbol that merely spells the formula instead of comparing it as text.
Examples
julia> s1 = Species("H2O"; aggregate_state=AS_AQUEOUS);
julia> s2 = Species("H₂O"; aggregate_state=AS_AQUEOUS);
julia> s1 == s2
true
julia> calcite = Species("CaCO3"; symbol="Cal", aggregate_state=AS_CRYSTAL);
julia> aragonite = Species("CaCO3"; symbol="Arg", aggregate_state=AS_CRYSTAL);
julia> calcite == aragonite
falseSee also: Base.hash, _identity_symbol.
Base.promote_rule Method
Base.promote_rule(::Type{Species}, ::Type{<:AbstractSpecies}) -> Type{Species}Define promotion rule to convert AbstractSpecies to Species.
Base.setindex! Method
Base.setindex!(s::AbstractSpecies, value, i::Symbol)Set a property value for the species.
Base.setproperty! Method
Base.setproperty!(s::AbstractSpecies, sym::Symbol, value)Set a property value, preventing direct modification of structural fields.
Throws an error if attempting to modify a structural field directly.
Base.show Method
Base.show(io::IO, s::CemSpecies)Compact single-line representation of a CemSpecies.
Base.show Method
Base.show(io::IO, ::MIME"text/plain", s::CemSpecies)Detailed multi-line REPL display for CemSpecies.
Base.show Method
Base.show(io::IO, ::MIME"text/plain", s::Species)Detailed multi-line REPL display for Species.
ChemistryLab._identity_symbol Method
_identity_symbol(s::AbstractSpecies) -> Union{Nothing, String}What the symbol contributes to a species' identity: nothing when it is merely a spelling of the species' own formula, and the symbol itself otherwise.
Why identity cannot just read symbol
Because a symbol serves two masters. It is the lookup key — cs["H2O"] indexes a ChemicalSystem by it, so it must stay the string the caller typed — and it is the only thing that separates two substances sharing a formula, a state and a class. Rewriting the stored symbol satisfies the second and breaks the first: measured, cs["H2O"] raised KeyError and ChemicalSystem(sp, ["H2O", "NaCl"]) could no longer name its components.
Why nothing, and not a canonical spelling
The obvious move is to replace a derived symbol by unicode(formula(s)). It is wrong, and measurably so: unicode is not constant on the equality classes of Formula, which are composition and charge.
Formula("e") == Formula("e-") yet unicode is "e" and "e⁻"
Formula("Ca+2") == Formula("Ca⁺²") yet unicode is "Ca²⁺" and "Ca⁺²"Two species that are the same substance, both with derived symbols, would then have carried different identity symbols and compared unequal. So a derived symbol must contribute nothing rather than a canonical form: the formula it spells is already compared, and spelling it twice cannot add information.
expr, phreeqc and unicode are stored fields of a Formula, so the three tests below are string comparisons, not re-parsing.
What it returns
| species | symbol | identity symbol |
|---|---|---|
Species("H2O") | "H2O" | nothing — a spelling of its formula |
Species("H₂O") | "H₂O" | nothing — the same species |
ELECTRON | "e-" | nothing — and Species("e") likewise |
Species("CaCO3"; symbol="Cal") | "Cal" | "Cal" — names a polymorph |
Species("CaCO3"; symbol="Arg") | "Arg" | "Arg" — names the other one |
ChemistryLab.aggregate_state Method
aggregate_state(s::AbstractSpecies) -> AggregateStateReturn the aggregate state of the species.
Examples
julia> s1 = Species("H2O"; aggregate_state=AS_AQUEOUS);
julia> aggregate_state(s1) == AS_AQUEOUS
trueChemistryLab.apply Method
apply(func::Function, s::S, args...; kwargs...) where {S<:AbstractSpecies} -> SApply a function element-wise to all numeric components and properties of a species.
Arguments
func: function to apply.s: source species.args...: additional arguments for func.kwargs...: keyword arguments (including potential overrides for name, symbol, etc.).
Returns
- New species with transformed values.
Handles Quantity types, attempting to preserve dimensions when possible.
ChemistryLab.atoms Method
atoms(s::AbstractSpecies) -> OrderedDict{Symbol,Number}Return the atomic composition (element => coefficient) of the species.
ChemistryLab.atoms_charge Method
atoms_charge(s::AbstractSpecies) -> OrderedDict{Symbol,Number}Return atomic composition including the charge as a :Zz key if non-zero.
Examples
julia> s = Species("Ca+2");
julia> atoms_charge(s)
OrderedDict{Symbol, Int64} with 2 entries:
:Ca => 1
:Zz => 2ChemistryLab.cemformula Method
cemformula(s::CemSpecies) -> FormulaReturn the oxide notation formula of the cement species.
ChemistryLab.charge Method
charge(s::AbstractSpecies) -> Int8Return the formal charge of the species.
Examples
julia> s1 = Species("Ca(HSiO3)+");
julia> charge(s1) == 1
trueChemistryLab.check_mendeleev Method
check_mendeleev(s::AbstractSpecies) -> BoolValidate that all element symbols in the species exist in the periodic table.
ChemistryLab.class Method
class(s::AbstractSpecies) -> ClassReturn the chemical class of the species.
ChemistryLab.colored Method
colored(s::CemSpecies) -> StringReturn the colored terminal representation of the cement formula.
ChemistryLab.colored Method
colored(s::Species) -> StringReturn the colored terminal representation of the species formula.
ChemistryLab.complete_thermo_functions! Method
complete_thermo_functions!(s::AbstractSpecies)Populate thermodynamic properties (Cp⁰, ΔₐH⁰, S⁰, ΔₐG⁰, V⁰) from parameters in s.properties.
If thermo_params dictionary is present in properties, it initializes thermodynamic functions using :thermo_method (e.g., "cp_ft_equation", "solute_hkf88_reaktoro") or scalar defaults. New thermodynamic models are registered by dispatching build_thermo_functions(Val(:model_name), params).
ChemistryLab.components Method
components(s::CemSpecies) -> OrderedDict{Symbol,Number}Return the components of a CemSpecies (oxide composition with charge).
ChemistryLab.components Method
components(s::Species) -> OrderedDict{Symbol,Number}Return the components of a Species (atomic composition with charge).
ChemistryLab.expr Method
expr(s::CemSpecies) -> StringReturn the expression string of the cement formula.
ChemistryLab.expr Method
expr(s::Species) -> StringReturn the original expression string of the species formula.
Examples
julia> expr(Species("H2O"; name="Water", aggregate_state=AS_AQUEOUS))
"H2O"
julia> expr(Species("H2O"; name="Water", aggregate_state=AS_AQUEOUS)) == expr(Formula("H2O"))
trueChemistryLab.find_species Function
find_species(s::AbstractString, species_list=nothing, S::Type{<:AbstractSpecies}=Species; aggregate_state=AS_UNDEF, class=SC_UNDEF) -> AbstractSpeciesFind or construct a species from a string identifier.
Arguments
s: species identifier string (formula, symbol, or name).species_list: optional list of species to search (default: nothing constructs new species).S: species type to construct if not found (default: Species).aggregate_state: filter by aggregate state (default: AS_UNDEF, no filter).class: filter by chemical class (default: SC_UNDEF, no filter).
Returns
- Matching species from list, or newly constructed species if not found.
The function searches by symbol, PHREEQC format, Unicode format, formula expression, and name. If multiple matches are found, a warning is displayed and the first match is returned.
Examples
julia> species_list = [
Species("H2O"; aggregate_state=AS_AQUEOUS), Species("H2O"; aggregate_state=AS_GAS)
];
julia> s = find_species("H2O", species_list; aggregate_state=AS_AQUEOUS);
julia> aggregate_state(s)
AS_AQUEOUS::AggregateState = 1ChemistryLab.formula Method
formula(s::AbstractSpecies) -> FormulaReturn the Formula object associated with the species.
Examples
julia> s1 = Species("H2O"; aggregate_state=AS_AQUEOUS);
julia> formula(s1) == Formula("H2O")
trueChemistryLab.mainformula Method
mainformula(s::CemSpecies) -> FormulaReturn the main formula representation (oxide notation) for the cement species.
ChemistryLab.mainformula Method
mainformula(s::Species) -> FormulaReturn the main formula representation for the species.
ChemistryLab.mendeleev_filter Method
mendeleev_filter(s::AbstractSpecies) -> Union{AbstractSpecies,Nothing}Return the species if valid according to Mendeleev check, otherwise nothing.
ChemistryLab.name Method
name(s::AbstractSpecies) -> StringReturn the name of the species.
Examples
julia> s1 = Species("H2O"; aggregate_state=AS_AQUEOUS);
julia> s1.name == "H2O"
trueChemistryLab.ordered_dict_with_default Method
ordered_dict_with_default(gen, key_type, val_type) -> OrderedDictCreate an OrderedDict from a generator, ensuring proper typing even when empty.
ChemistryLab.oxides Method
oxides(s::CemSpecies) -> OrderedDict{Symbol,Number}Return the oxide composition of the cement species.
ChemistryLab.oxides_charge Method
oxides_charge(s::CemSpecies) -> OrderedDict{Symbol,Number}Return oxide composition including the charge as a :Zz key if non-zero.
ChemistryLab.phreeqc Method
phreeqc(s::CemSpecies) -> StringReturn the PHREEQC-compatible representation of the cement formula.
ChemistryLab.phreeqc Method
phreeqc(s::Species) -> StringReturn the PHREEQC-compatible representation of the species formula.
ChemistryLab.pprint Method
pprint(s::CemSpecies)Pretty-print a CemSpecies to standard output using the same multi-line layout as the MIME "text/plain" show method.
Arguments
s: CemSpecies instance to print.
Returns
nothing(side-effect: formatted output to stdout).
ChemistryLab.pprint Method
pprint(s::Species)Pretty-print a Species to standard output using the same multi-line layout as the MIME "text/plain" show method.
Arguments
s: Species instance to print.
Returns
nothing(side-effect: formatted output to stdout).
ChemistryLab.properties Method
properties(s::AbstractSpecies) -> OrderedDict{Symbol,PropertyType}Return the properties dictionary of the species.
ChemistryLab.symbol Method
symbol(s::AbstractSpecies) -> StringReturn the symbol of the species.
ChemistryLab.unicode Method
unicode(s::CemSpecies) -> StringReturn the Unicode representation of the cement formula.
ChemistryLab.unicode Method
unicode(s::Species) -> StringReturn the Unicode pretty representation of the species formula.
ChemistryLab.with_aggregate_state Method
with_aggregate_state(s::AbstractSpecies, a::AggregateState) -> AbstractSpeciesReturn a copy of s in aggregate state a, everything else preserved.
The counterpart of with_class, and it exists for the same reason: a species is immutable, and a database record has to be requalified before it can join a phase that the database knows nothing about. SiteFamily uses it to put its members in AS_SURFACE, which is what keeps them out of the index sets the solver reads as "a pure mineral phase".
Examples
julia> s = Species("XsOH"; aggregate_state=AS_CRYSTAL, class=SC_COMPONENT);
julia> aggregate_state(with_aggregate_state(s, AS_SURFACE))
AS_SURFACE::AggregateState = 5ChemistryLab.with_class Method
with_class(s::Species, c::Class) -> SpeciesReturn a copy of s with its class set to c. All other fields (name, symbol, formula, aggregate state, properties) are preserved unchanged.
Useful to requalify database species as SC_SSENDMEMBER before grouping them into a SolidSolutionPhase, since Species is immutable.
Examples
julia> s = Species("CaCO3"; aggregate_state=AS_CRYSTAL, class=SC_COMPONENT);
julia> class(s)
SC_COMPONENT::Class = 3
julia> s2 = with_class(s, SC_SSENDMEMBER);
julia> class(s2)
SC_SSENDMEMBER::Class = 5ChemistryLab.with_symbol Method
with_symbol(s::Species, sym::AbstractString) -> SpeciesThe same species under a different symbol, everything else shared.
Exists for one purpose: a miscibility gap needs the same substance present twice, as two coexisting compositions, and a formulation carrying one amount per species can only express that if the species appears twice. ChemicalSystem uses this to build the extra copies a SolidSolutionPhase declared with instances > 1 asks for — see SolidSolutionPhase.
The copy shares the formula and the whole property dictionary, so the two carry byte-identical thermodynamic data: they are one substance under two labels, not two substances. Only the label distinguishes them, and it is what keeps the solid-solution groups disjoint.
Examples
julia> s = Species("CaCO3"; aggregate_state=AS_CRYSTAL, class=SC_COMPONENT);
julia> s2 = with_symbol(s, "CaCO3#2");
julia> symbol(s2), atoms(s2) == atoms(s)
("CaCO3#2", true)