0025. Solids as components and a bounded crystallizer adapter outside the simulation¶
- Status: Accepted
- Date: 2026-10-27
Context¶
Process-library cases (salts, fertilizers, pigments, hydrates; ChemE-as-Code/process-library#306)
need crystallization and solid-liquid separation. The
process model had no solid phase: thermodynamics/methods.yml declares solid equilibrium
unsupported in the property routes, the DWSIM translation has fluid outlet roles only, and
separations/coverage.py listed crystallization and solid-fluid separation as specified splits
with no solids model. The options were a solids phase on every stream (a new stream state
field, a second composition), a full solid-liquid equilibrium or population-balance model, or
treating a solid as its own component and adding a narrowly scoped crystallizer model.
Decision¶
- A solid is a component of
process/materials.yamlwithphase: solid(schemacheme/process/v1, additive): a crystal, or a hydrate whose formula carries its water of crystallization (MgSO4(H2O)7). It is a separate component from the same substance dissolved. Stream compositions, mass balances and provenance need nothing new; a stream's dry solid is the sum of its solid components and the rest is its liquid (mother liquor or moisture), computed bydomains/process/solids.py, never written twice. No particle size, porosity or population balance is part of the contract. - A block or step may carry
crystallizer:(one solute, one solvent, one crystal form; optional evaporation, a specified filter or centrifuge and a mother-liquor recycle; a lumped energy balance) orsolid_separation:(a filter or centrifuge on its own), not both.domains/process/crystallization.pysolves them insidecheme process propagate; they are not translated to DWSIM. A crystallizer node is balanced on mass and elements, like a reactor. - The model basis keeps prediction and imposition apart:
solubility-equilibrium(predictive within sourced solubility data: interpolated in temperature, never extrapolated; the mother liquor leaves saturated),imposed-yieldandsolid-split(specified). Because the solved crystallizer is not part of a converged simulation, it capspredictive.model-basis("not in the simulation"); a sourced imposed yield or solid split supportsbalanced. - Cases outside the model (impurities or a second solute in the inlet, a temperature outside
the solubility data, a hydrate formula that is not the solute plus n solvent) are refused with
cheme.process-crystallizer-unsupportedor-unsolved, andcheme.process-propagate- crystallizerin propagate, each naming file, line and hint. cheme process crystallizers [--case] [--json]reports each unit: basis, sources, assumptions, limitations, crystals formed and at equilibrium, recovery, recycle iterations and residual, mass, solute, solvent and element balances, duty terms and the outlets as dry solid, liquid and moisture.
Consequences¶
- Positive: salt and hydrate crystallization trains close mass and element balances in the flowsheet with traceable solubility and separation data; recovery and mother-liquor recycle are calculated, and specified yields stay possible at a lower declared basis.
- Positive: no change to stream state or the DWSIM translation; existing flowsheets (the ASU examples) are unaffected.
- Negative: the dissolved and solid forms are two components, so a plant must declare both; mixing, splitting or heating a slurry elsewhere uses the existing pass-through rules, which do not dissolve or crystallize anything.
- Known limitations: no supersaturation, kinetics, crystal size distribution, several solutes,
impurities, common-ion effects, polymorph or hydrate transitions, washing, heats of dilution or
filtration rates; the energy balance uses a constant heat capacity and a given heat of
crystallization. Solid-liquid equilibrium from a thermodynamic model (activity coefficients,
electrolytes) stays unsupported (
methods.ymlregimes.solid_equilibrium).
Evidence¶
src/chemeascode/domains/process/{solids,crystallization}.py,schema.py(Component.phase,Crystallizer,SolidSeparation),model_basis.solids_basis,propagate.py,interfaces/cli/process.py(process crystallizers).tests/test_crystallization.py: Felder & Rousseau (3rd ed.) Example 4.5-2, Geankoplis (4th ed.) Examples 12.11-1 and 12.11-2, refusals and the report.docs/framework/maturity.md(model basis table),separations/coverage.py.