OGS
ChemistryLib::PhreeqcIOData::PhreeqcIO Class Referencefinal

Detailed Description

Drives the chemistry step in the operator-split reactive transport loop.

Per timestep:

  1. initializeChemicalSystemConcrete(...) / setChemicalSystemConcrete(...): For each chemical_system_id, store the transported totals \(c_{T\alpha}\), the current porous-medium state (porosity, mineral fractions, reactive surface area), and the process variables (e.g. temperature \(T\), pressure \(p\), time \(t\), and timestep \(\Delta t\)) in the corresponding ChemicalSystem. Each chemical_system_id is treated as one local batch reactor.
  2. executeSpeciationCalculation(dt): Build PHREEQC input for all chemical_system_id, run PHREEQC via IPhreeqc, and obtain the reacted state after advancing chemistry over \(\Delta t\):
    • updated aqueous composition,
    • reaction/source terms \(R_{\alpha}\) for each transported component,
    • updated mineral amounts.
  3. updateVolumeFractionPostReaction(...), updatePorosityPostReaction(...): Apply precipitation / dissolution back into OpenGeoSys by updating mineral / solid volume fractions and porosity for each local system. These updates feed into flow / transport / mechanics in the next global step.
  4. computeSecondaryVariable(...): Optionally expose derived quantities (e.g. pH fields, mineral fractions, surface loading) for output.

Accessors:

  • getConcentration(component_id, chemical_system_id): Reacted total \(c_{T\alpha}\) of a transported component for that local system after the last chemistry step. Used as the starting composition for the next transport solve.
  • getComponentList(): List of transported components in the order expected by the transport process.

Internal data:

Definition at line 110 of file PhreeqcIO.h.

#include <PhreeqcIO.h>

Inheritance diagram for ChemistryLib::PhreeqcIOData::PhreeqcIO:
[legend]
Collaboration diagram for ChemistryLib::PhreeqcIOData::PhreeqcIO:
[legend]

Public Member Functions

 PhreeqcIO (MeshLib::Mesh const &mesh, GlobalLinearSolver &linear_solver, std::string const &project_file_name, std::string &&database, std::unique_ptr< ChemicalSystem > &&chemical_system, std::vector< ReactionRate > &&reaction_rates, std::unique_ptr< UserPunch > &&user_punch, std::unique_ptr< Output > &&output, std::unique_ptr< Dump > &&dump, Knobs &&knobs)
 ~PhreeqcIO ()
void initialize () override
void initializeChemicalSystemConcrete (std::vector< double > const &concentrations, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const &medium, ParameterLib::SpatialPosition const &pos, double const t) override
void setChemicalSystemConcrete (std::vector< double > const &concentrations, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const *medium, MaterialPropertyLib::VariableArray const &vars, ParameterLib::SpatialPosition const &pos, double const t, double const dt) override
void setAqueousSolutionsPrevFromDumpFile () override
void executeSpeciationCalculation (double const dt) override
double getConcentration (int const component_id, GlobalIndexType const chemical_system_id) const override
void updateVolumeFractionPostReaction (GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const &medium, ParameterLib::SpatialPosition const &pos, double const porosity, double const t, double const dt) override
void updatePorosityPostReaction (GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const &medium, double &porosity) override
void computeSecondaryVariable (std::size_t const ele_id, std::vector< GlobalIndexType > const &chemical_system_indices) override
std::vector< std::string > const getComponentList () const override
Public Member Functions inherited from ChemistryLib::ChemicalSolverInterface
 ChemicalSolverInterface (MeshLib::Mesh const &mesh, GlobalLinearSolver &linear_solver_)
std::vector< std::size_t > const & activeElementIDs () const
virtual Eigen::SparseMatrix< double > const * getStoichiometricMatrix () const
virtual double getKineticPrefactor (std::size_t reaction_id) const
virtual ~ChemicalSolverInterface ()=default

Public Attributes

std::string const _phreeqc_input_file
Public Attributes inherited from ChemistryLib::ChemicalSolverInterface
std::vector< GlobalIndexTypechemical_system_index_map
MeshLib::Mesh const & _mesh
GlobalLinearSolverlinear_solver

Private Member Functions

void writeInputsToFile (double const dt)
void callPhreeqc () const
void readOutputsFromFile ()
PhreeqcIOoperator<< (double const dt)

Private Attributes

std::string const _database
std::unique_ptr< ChemicalSystem_chemical_system
std::vector< ReactionRate > const _reaction_rates
std::unique_ptr< UserPunch_user_punch
std::unique_ptr< Output > const _output
std::unique_ptr< Dump > const _dump
Knobs const _knobs
double _dt = std::numeric_limits<double>::quiet_NaN()
const int phreeqc_instance_id = 0
std::size_t _num_chemical_systems = -1

Friends

std::ostream & operator<< (std::ostream &os, PhreeqcIO const &phreeqc_io)
std::istream & operator>> (std::istream &in, PhreeqcIO &phreeqc_io)

Constructor & Destructor Documentation

◆ PhreeqcIO()

ChemistryLib::PhreeqcIOData::PhreeqcIO::PhreeqcIO ( MeshLib::Mesh const & mesh,
GlobalLinearSolver & linear_solver,
std::string const & project_file_name,
std::string && database,
std::unique_ptr< ChemicalSystem > && chemical_system,
std::vector< ReactionRate > && reaction_rates,
std::unique_ptr< UserPunch > && user_punch,
std::unique_ptr< Output > && output,
std::unique_ptr< Dump > && dump,
Knobs && knobs )

Definition at line 258 of file PhreeqcIO.cpp.

269 _phreeqc_input_file(specifyFileName(project_file_name, ".inp")),
270 _database(std::move(database)),
271 _chemical_system(std::move(chemical_system)),
272 _reaction_rates(std::move(reaction_rates)),
273 _user_punch(std::move(user_punch)),
274 _output(std::move(output)),
275 _dump(std::move(dump)),
276 _knobs(std::move(knobs))
277{
278 // initialize phreeqc instance
279 if (CreateIPhreeqc() != phreeqc_instance_id)
280 {
281 OGS_FATAL(
282 "Failed to initialize phreeqc instance, due to lack of memory.");
283 }
284
285 // load specified thermodynamic database
286 if (LoadDatabase(phreeqc_instance_id, _database.c_str()) != IPQ_OK)
287 {
288 OGS_FATAL(
289 "Failed in loading the specified thermodynamic database file: "
290 "{:s}.",
291 _database);
292 }
293
294 if (SetSelectedOutputFileOn(phreeqc_instance_id, 1) != IPQ_OK)
295 {
296 OGS_FATAL(
297 "Failed to fly the flag for the specified file {:s} where phreeqc "
298 "will write output.",
299 _output->basic_output_setups.output_file);
300 }
301
302 if (_dump)
303 {
304 // Chemical composition of the aqueous solution of last time step will
305 // be written into .dmp file once the second function argument is set to
306 // one.
307 SetDumpFileOn(phreeqc_instance_id, 1);
308 }
309}
#define OGS_FATAL(...)
Definition Error.h:19
ChemicalSolverInterface(MeshLib::Mesh const &mesh, GlobalLinearSolver &linear_solver_)
std::unique_ptr< ChemicalSystem > _chemical_system
Definition PhreeqcIO.h:188
std::vector< ReactionRate > const _reaction_rates
Definition PhreeqcIO.h:189
std::unique_ptr< UserPunch > _user_punch
Definition PhreeqcIO.h:190
std::unique_ptr< Dump > const _dump
Definition PhreeqcIO.h:192
std::unique_ptr< Output > const _output
Definition PhreeqcIO.h:191
std::string specifyFileName(std::string const &project_file_name, std::string const &file_extension)

References ChemistryLib::ChemicalSolverInterface::ChemicalSolverInterface(), _chemical_system, _database, _dump, _knobs, _output, _phreeqc_input_file, _reaction_rates, _user_punch, ChemistryLib::ChemicalSolverInterface::linear_solver, OGS_FATAL, phreeqc_instance_id, and ChemistryLib::PhreeqcIOData::specifyFileName().

Referenced by operator<<(), operator<<, and operator>>.

◆ ~PhreeqcIO()

ChemistryLib::PhreeqcIOData::PhreeqcIO::~PhreeqcIO ( )

Definition at line 311 of file PhreeqcIO.cpp.

312{
313 DestroyIPhreeqc(phreeqc_instance_id);
314}

References phreeqc_instance_id.

Member Function Documentation

◆ callPhreeqc()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::callPhreeqc ( ) const
private

Definition at line 644 of file PhreeqcIO.cpp.

645{
646 INFO("Phreeqc: Executing chemical calculation.");
647 if (RunFile(phreeqc_instance_id, _phreeqc_input_file.c_str()) != IPQ_OK)
648 {
649 OutputErrorString(phreeqc_instance_id);
650 OGS_FATAL(
651 "Failed in performing speciation calculation with the generated "
652 "phreeqc input file '{:s}'.",
654 }
655}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28

References _phreeqc_input_file, INFO(), OGS_FATAL, and phreeqc_instance_id.

Referenced by executeSpeciationCalculation().

◆ computeSecondaryVariable()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::computeSecondaryVariable ( std::size_t const ele_id,
std::vector< GlobalIndexType > const & chemical_system_indices )
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 912 of file PhreeqcIO.cpp.

915{
916 for (auto const& kinetic_reactant : _chemical_system->kinetic_reactants)
917 {
918 (*kinetic_reactant.mesh_prop_molality)[ele_id] =
919 averageReactantMolality(kinetic_reactant, chemical_system_indices);
920 }
921
922 for (auto const& equilibrium_reactant :
923 _chemical_system->equilibrium_reactants)
924 {
925 (*equilibrium_reactant.mesh_prop_molality)[ele_id] =
926 averageReactantMolality(equilibrium_reactant,
927 chemical_system_indices);
928 }
929}
static double averageReactantMolality(Reactant const &reactant, std::vector< GlobalIndexType > const &chemical_system_indices)

References _chemical_system.

◆ executeSpeciationCalculation()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::executeSpeciationCalculation ( double const dt)
overridevirtual

Run PHREEQC for all local chemical systems for the current timestep.

Uses the state previously provided by initializeChemicalSystemConcrete() / setChemicalSystemConcrete() for each chemical_system_id. Each local system is advanced as an isolated batch reactor over \(\Delta t\): no mass is exchanged between different systems inside PHREEQC.

PHREEQC returns, for each system:

  • updated aqueous composition,
  • reaction / source terms \(R_{\alpha}\) for each transported component,
  • updated mineral amounts and saturation state.

After this call completes, these reacted values are available for porosity update and for assembling the reaction/source term in the transport equation.

Parameters
dtTimestep size \(\Delta t\) used for kinetic reactions.

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 396 of file PhreeqcIO.cpp.

References callPhreeqc(), readOutputsFromFile(), and writeInputsToFile().

◆ getComponentList()

std::vector< std::string > const ChemistryLib::PhreeqcIOData::PhreeqcIO::getComponentList ( ) const
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 862 of file PhreeqcIO.cpp.

863{
864 std::vector<std::string> component_names;
865 auto const& components = _chemical_system->aqueous_solution->components;
866 std::transform(components.begin(), components.end(),
867 std::back_inserter(component_names),
868 [](auto const& c) { return c.name; });
869
870 component_names.push_back("H");
871
872 return component_names;
873}

References _chemical_system.

◆ getConcentration()

double ChemistryLib::PhreeqcIOData::PhreeqcIO::getConcentration ( int const component_id,
GlobalIndexType const chemical_system_id ) const
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 405 of file PhreeqcIO.cpp.

407{
408 auto const& aqueous_solution = *_chemical_system->aqueous_solution;
409 auto& components = aqueous_solution.components;
410 auto const& pH = *aqueous_solution.pH;
411
412 if (component_id < static_cast<int>(components.size()))
413 {
415 *components[component_id].amount);
416
417 return components[component_id].amount->get(chemical_system_id);
418 }
419
420 // pH
421 MathLib::LinAlg::setLocalAccessibleVector(*aqueous_solution.pH);
422
423 return pH.get(chemical_system_id);
424}
void setLocalAccessibleVector(PETScVector const &x)
Definition LinAlg.cpp:20

References _chemical_system, ChemistryLib::PhreeqcIOData::pH, and MathLib::LinAlg::setLocalAccessibleVector().

◆ initialize()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::initialize ( )
overridevirtual

◆ initializeChemicalSystemConcrete()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::initializeChemicalSystemConcrete ( std::vector< double > const & concentrations,
GlobalIndexType const & chemical_system_id,
MaterialPropertyLib::Medium const & medium,
ParameterLib::SpatialPosition const & pos,
double const t )
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 328 of file PhreeqcIO.cpp.

334{
335 setAqueousSolution(concentrations, chemical_system_id,
336 *_chemical_system->aqueous_solution);
337
338 auto const& solid_phase = medium.phase("Solid");
339 auto const& liquid_phase = medium.phase("AqueousLiquid");
340
341 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
342 {
343 initializeReactantMolality(kinetic_reactant, chemical_system_id,
344 solid_phase, liquid_phase, medium, pos, t);
345 }
346
347 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
348 {
349 initializeReactantMolality(equilibrium_reactant, chemical_system_id,
350 solid_phase, liquid_phase, medium, pos, t);
351 }
352
353 for (auto& exchanger : _chemical_system->exchangers)
354 {
355 initializeSiteMolality(exchanger, chemical_system_id, solid_phase, pos,
356 t);
357 }
358
359 for (auto& surface_site : _chemical_system->surface)
360 {
361 if (auto const surface_site_ptr =
362 std::get_if<MoleBasedSurfaceSite>(&surface_site))
363 {
364 initializeSiteMolality(*surface_site_ptr, chemical_system_id,
365 solid_phase, pos, t);
366 }
367 }
368}
void initializeSiteMolality(Site &site, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Phase const &solid_phase, ParameterLib::SpatialPosition const &pos, double const t)
void initializeReactantMolality(Reactant &reactant, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Phase const &solid_phase, MaterialPropertyLib::Phase const &liquid_phase, MaterialPropertyLib::Medium const &medium, ParameterLib::SpatialPosition const &pos, double const t)
Definition PhreeqcIO.cpp:79
void setAqueousSolution(std::vector< double > const &concentrations, GlobalIndexType const &chemical_system_id, AqueousSolution &aqueous_solution)
Definition PhreeqcIO.cpp:55

References _chemical_system, and MaterialPropertyLib::Medium::phase().

◆ operator<<()

PhreeqcIO & ChemistryLib::PhreeqcIOData::PhreeqcIO::operator<< ( double const dt)
inlineprivate

Definition at line 181 of file PhreeqcIO.h.

182 {
183 _dt = dt;
184 return *this;
185 }

References PhreeqcIO(), and _dt.

◆ readOutputsFromFile()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::readOutputsFromFile ( )
private

Definition at line 657 of file PhreeqcIO.cpp.

658{
659 auto const& basic_output_setups = _output->basic_output_setups;
660 auto const& phreeqc_result_file = basic_output_setups.output_file;
661 DBUG("Reading phreeqc results from file '{:s}'.", phreeqc_result_file);
662 std::ifstream in(phreeqc_result_file);
663
664 if (!in)
665 {
666 OGS_FATAL("Could not open phreeqc result file '{:s}'.",
667 phreeqc_result_file);
668 }
669
670 in >> *this;
671
672 if (!in)
673 {
674 OGS_FATAL("Error when reading phreeqc result file '{:s}'",
675 phreeqc_result_file);
676 }
677
678 in.close();
679}
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22

References _output, DBUG(), and OGS_FATAL.

Referenced by executeSpeciationCalculation().

◆ setAqueousSolutionsPrevFromDumpFile()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::setAqueousSolutionsPrevFromDumpFile ( )
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 426 of file PhreeqcIO.cpp.

427{
428 if (!_dump)
429 {
430 return;
431 }
432
433 auto const& dump_file = _dump->dump_file;
434 std::ifstream in(dump_file);
435 if (!in)
436 {
437 // return if phreeqc dump file doesn't exist. This happens in
438 // the first time step when no dump file is provided by the user.
439 return;
440 }
441
442 _dump->readDumpFile(in, _num_chemical_systems);
443
444 if (!in)
445 {
446 OGS_FATAL("Error when reading phreeqc dump file '{:s}'", dump_file);
447 }
448
449 in.close();
450}

References _dump, _num_chemical_systems, and OGS_FATAL.

◆ setChemicalSystemConcrete()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::setChemicalSystemConcrete ( std::vector< double > const & concentrations,
GlobalIndexType const & chemical_system_id,
MaterialPropertyLib::Medium const * medium,
MaterialPropertyLib::VariableArray const & vars,
ParameterLib::SpatialPosition const & pos,
double const t,
double const dt )
overridevirtual

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 370 of file PhreeqcIO.cpp.

376{
377 setAqueousSolution(concentrations, chemical_system_id,
378 *_chemical_system->aqueous_solution);
379
380 auto const& solid_phase = medium->phase("Solid");
381 auto const& liquid_phase = medium->phase("AqueousLiquid");
382
383 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
384 {
385 setReactantMolality(kinetic_reactant, chemical_system_id, solid_phase,
386 liquid_phase, vars, pos, t, dt);
387 }
388
389 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
390 {
391 setReactantMolality(equilibrium_reactant, chemical_system_id,
392 solid_phase, liquid_phase, vars, pos, t, dt);
393 }
394}
void setReactantMolality(Reactant &reactant, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Phase const &solid_phase, MaterialPropertyLib::Phase const &liquid_phase, MaterialPropertyLib::VariableArray const &vars, ParameterLib::SpatialPosition const &pos, double const t, double const dt)

References _chemical_system, and MaterialPropertyLib::Medium::phase().

◆ updatePorosityPostReaction()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::updatePorosityPostReaction ( GlobalIndexType const & ,
MaterialPropertyLib::Medium const & ,
double &  )
overridevirtual

Update porosity after chemical reactions.

This applies porosity changes caused by precipitation / dissolution in the local chemical system. The updated porosity can then be used to update flow parameters (e.g. permeability) in the next timestep.

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 894 of file PhreeqcIO.cpp.

898{
899 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
900 {
901 setPorosityPostReaction(kinetic_reactant, chemical_system_id, medium,
902 porosity);
903 }
904
905 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
906 {
907 setPorosityPostReaction(equilibrium_reactant, chemical_system_id,
908 medium, porosity);
909 }
910}
void setPorosityPostReaction(Reactant &reactant, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const &medium, double &porosity)

References _chemical_system.

◆ updateVolumeFractionPostReaction()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::updateVolumeFractionPostReaction ( GlobalIndexType const & ,
MaterialPropertyLib::Medium const & ,
ParameterLib::SpatialPosition const & ,
double const ,
double const ,
double const  )
overridevirtual

Apply mineral precipitation / dissolution to the solid fraction in OGS.

Called after executeSpeciationCalculation(). For a given chemical_system_id, this function updates the solid / mineral inventory and related volume fractions based on the PHREEQC results for the last timestep.

Typical effect:

  • change in mineral volume fraction at this location,
  • updated solid composition available to mechanics / flow.

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 875 of file PhreeqcIO.cpp.

880{
881 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
882 {
883 updateReactantVolumeFraction(kinetic_reactant, chemical_system_id,
884 medium, pos, porosity, t, dt);
885 }
886
887 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
888 {
889 updateReactantVolumeFraction(equilibrium_reactant, chemical_system_id,
890 medium, pos, porosity, t, dt);
891 }
892}
void updateReactantVolumeFraction(Reactant &reactant, GlobalIndexType const &chemical_system_id, MaterialPropertyLib::Medium const &medium, ParameterLib::SpatialPosition const &pos, double const porosity, double const t, double const dt)

References _chemical_system.

◆ writeInputsToFile()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::writeInputsToFile ( double const dt)
private

Definition at line 452 of file PhreeqcIO.cpp.

453{
454 DBUG("Writing phreeqc inputs into file '{:s}'.", _phreeqc_input_file);
455 std::ofstream out(_phreeqc_input_file, std::ofstream::out);
456
457 if (!out)
458 {
459 OGS_FATAL("Could not open file '{:s}' for writing phreeqc inputs.",
461 }
462
463 out << std::scientific
464 << std::setprecision(std::numeric_limits<double>::max_digits10);
465 out << (*this << dt);
466
467 if (!out)
468 {
469 OGS_FATAL("Failed in generating phreeqc input file '{:s}'.",
471 }
472
473 out.close();
474}

References _phreeqc_input_file, DBUG(), and OGS_FATAL.

Referenced by executeSpeciationCalculation().

◆ operator<<

std::ostream & operator<< ( std::ostream & os,
PhreeqcIO const & phreeqc_io )
friend

Definition at line 476 of file PhreeqcIO.cpp.

477{
478 bool const fixing_pe =
479 phreeqc_io._chemical_system->aqueous_solution->fixing_pe;
480 if (fixing_pe)
481 {
482 os << "PHASES\n"
483 << "Fix_pe\n"
484 << "e- = e-\n"
485 << "log_k 0.0\n\n";
486 }
487
488 os << phreeqc_io._knobs << "\n";
489
490 os << *phreeqc_io._output << "\n";
491
492 auto const& user_punch = phreeqc_io._user_punch;
493 if (user_punch)
494 {
495 os << *user_punch << "\n";
496 }
497
498 auto const& reaction_rates = phreeqc_io._reaction_rates;
499 if (!reaction_rates.empty())
500 {
501 os << "RATES\n";
502 os << reaction_rates << "\n";
503 }
504
505 for (std::size_t chemical_system_id = 0;
506 chemical_system_id < phreeqc_io._num_chemical_systems;
507 ++chemical_system_id)
508 {
509 os << "SOLUTION " << chemical_system_id + 1 << "\n";
510 phreeqc_io._chemical_system->aqueous_solution->print(
511 os, chemical_system_id);
512
513 auto const& dump = phreeqc_io._dump;
514 if (dump)
515 {
516 auto const& aqueous_solutions_prev = dump->aqueous_solutions_prev;
517 // Print previous aqueous solution if it exists.
518 if (!aqueous_solutions_prev.empty())
519 {
520 os << aqueous_solutions_prev[chemical_system_id] << "\n\n";
521 }
522 }
523
524 os << "USE solution none\n";
525 os << "END\n\n";
526
527 os << "USE solution " << chemical_system_id + 1 << "\n\n";
528
529 auto const& equilibrium_reactants =
530 phreeqc_io._chemical_system->equilibrium_reactants;
531 if (!equilibrium_reactants.empty() || fixing_pe)
532 {
533 os << "EQUILIBRIUM_PHASES " << chemical_system_id + 1 << "\n";
534 for (auto const& equilibrium_reactant : equilibrium_reactants)
535 {
536 equilibrium_reactant.print(os, chemical_system_id);
537 }
538 fixing_pe
539 ? os << "Fix_pe "
540 << -phreeqc_io._chemical_system->aqueous_solution->pe0
541 << " O2(g)\n\n"
542 : os << "\n";
543 }
544
545 auto const& kinetic_reactants =
546 phreeqc_io._chemical_system->kinetic_reactants;
547 if (!kinetic_reactants.empty())
548 {
549 os << "KINETICS " << chemical_system_id + 1 << "\n";
550 for (auto const& kinetic_reactant : kinetic_reactants)
551 {
552 kinetic_reactant.print(os, chemical_system_id);
553 }
554 os << "-steps " << phreeqc_io._dt << "\n\n";
555 }
556
557 auto const& surface = phreeqc_io._chemical_system->surface;
558 if (!surface.empty())
559 {
560 // To get the amount of surface species from the previous time step,
561 // an equilibration calculation with the previous aqueous solution
562 // is needed. The previous aqueous solution is saved using the
563 // PHREEQC keyword "DUMP" in the dump file and then stored as
564 // SOLUTION_RAW within aqueous_solutions_prev. Along with the
565 // PHREEQC keyword 'SURFACE', distinguish between the current and
566 // previous solutions, the previous solution number is added to the
567 // total number of chemical systems (_num_chemical_systems).
568 os << "SURFACE " << chemical_system_id + 1 << "\n";
569 std::size_t aqueous_solution_id =
570 dump->aqueous_solutions_prev.empty()
571 ? chemical_system_id + 1
572 : phreeqc_io._num_chemical_systems + chemical_system_id + 1;
573 os << "-equilibrate with solution " << aqueous_solution_id << "\n";
574
575 // print unit
576 if (std::holds_alternative<DensityBasedSurfaceSite>(
577 surface.front()))
578 {
579 os << "-sites_units density\n";
580 }
581 else
582 {
583 os << "-sites_units absolute\n";
584 }
585
586 for (auto const& surface_site : surface)
587 {
588 std::visit(
589 overloaded{[&os](DensityBasedSurfaceSite const& s)
590 {
591 os << s.name << " " << s.site_density << " "
592 << s.specific_surface_area << " "
593 << s.mass << "\n";
594 },
595 [&os, chemical_system_id](
596 MoleBasedSurfaceSite const& s) {
597 os << s.name << " "
598 << (*s.molality)[chemical_system_id]
599 << "\n";
600 }},
601 surface_site);
602 }
603
604 // overlook the effect of the buildup of charges onto the surface
605 if (std::holds_alternative<MoleBasedSurfaceSite>(surface.front()))
606 {
607 os << "-no_edl\n";
608 }
609 // Here the PHREEQC "save" command is printed to save the solution
610 // internally in PHREEQC. The solution composition is saved after
611 // equilibration with the surface has been completed. The solution
612 // will not be saved for use in the next PHREEQC run.
613 os << "SAVE solution " << chemical_system_id + 1 << "\n";
614 }
615
616 auto const& exchangers = phreeqc_io._chemical_system->exchangers;
617 if (!exchangers.empty())
618 {
619 os << "EXCHANGE " << chemical_system_id + 1 << "\n";
620 std::size_t const aqueous_solution_id =
621 dump->aqueous_solutions_prev.empty()
622 ? chemical_system_id + 1
623 : phreeqc_io._num_chemical_systems + chemical_system_id + 1;
624 os << "-equilibrate with solution " << aqueous_solution_id << "\n";
625 for (auto const& exchanger : exchangers)
626 {
627 exchanger.print(os, chemical_system_id);
628 }
629 os << "SAVE solution " << chemical_system_id + 1 << "\n";
630 }
631
632 os << "END\n\n";
633 }
634
635 auto const& dump = phreeqc_io._dump;
636 if (dump)
637 {
638 dump->print(os, phreeqc_io._num_chemical_systems);
639 }
640
641 return os;
642}

References PhreeqcIO(), _chemical_system, _dt, _dump, _knobs, _num_chemical_systems, _output, _reaction_rates, and _user_punch.

◆ operator>>

std::istream & operator>> ( std::istream & in,
PhreeqcIO & phreeqc_io )
friend

Definition at line 681 of file PhreeqcIO.cpp.

682{
683 // Skip the headline
684 in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
685
686 std::string line;
687 auto const& output = *phreeqc_io._output;
688 auto const& dropped_item_ids = output.dropped_item_ids;
689
690 auto const& surface = phreeqc_io._chemical_system->surface;
691 auto const& exchangers = phreeqc_io._chemical_system->exchangers;
692
693 int const num_skipped_lines =
694 1 + (!surface.empty() ? 1 : 0) + (!exchangers.empty() ? 1 : 0);
695
696 auto& equilibrium_reactants =
697 phreeqc_io._chemical_system->equilibrium_reactants;
698 auto& kinetic_reactants = phreeqc_io._chemical_system->kinetic_reactants;
699
700 for (std::size_t chemical_system_id = 0;
701 chemical_system_id < phreeqc_io._num_chemical_systems;
702 ++chemical_system_id)
703 {
704 // Skip equilibrium calculation result of initial solution
705 for (int i = 0; i < num_skipped_lines; ++i)
706 {
707 in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
708 }
709
710 // Get calculation result of the solution after the reaction
711 if (!std::getline(in, line))
712 {
713 OGS_FATAL(
714 "Error when reading calculation result of Solution {:d} "
715 "after the reaction.",
716 chemical_system_id);
717 }
718
719 std::vector<double> accepted_items;
720 std::vector<std::string> items;
721 boost::trim_if(line, boost::is_any_of("\t "));
722 boost::algorithm::split(items, line, boost::is_any_of("\t "),
723 boost::token_compress_on);
724 for (int item_id = 0; item_id < static_cast<int>(items.size());
725 ++item_id)
726 {
727 if (std::find(dropped_item_ids.begin(), dropped_item_ids.end(),
728 item_id) == dropped_item_ids.end())
729 {
730 double value;
731 try
732 {
733 value = std::stod(items[item_id]);
734 }
735 catch (const std::invalid_argument& e)
736 {
737 OGS_FATAL(
738 "Invalid argument. Could not convert string '{:s}' to "
739 "double for chemical system {:d}, column {:d}. "
740 "Exception '{:s}' was thrown.",
741 items[item_id], chemical_system_id + 1, item_id,
742 e.what());
743 }
744 catch (const std::out_of_range& e)
745 {
746 OGS_FATAL(
747 "Out of range error. Could not convert string "
748 "'{:s}' to double for chemical system {:d}, column "
749 "{:d}. Exception '{:s}' was thrown.",
750 items[item_id], chemical_system_id + 1, item_id,
751 e.what());
752 }
753 accepted_items.push_back(value);
754 }
755 }
756 assert(accepted_items.size() == output.accepted_items.size());
757
758 auto& aqueous_solution = phreeqc_io._chemical_system->aqueous_solution;
759 auto& components = aqueous_solution->components;
760 auto& user_punch = phreeqc_io._user_punch;
761
762 GlobalIndexType const offset = aqueous_solution->pH->getRangeBegin();
763 GlobalIndexType const global_index = offset + chemical_system_id;
764
765 for (int item_id = 0; item_id < static_cast<int>(accepted_items.size());
766 ++item_id)
767 {
768 auto const& accepted_item = output.accepted_items[item_id];
769 auto const& item_name = accepted_item.name;
770
771 auto compare_by_name = [&item_name](auto const& item)
772 { return item.name == item_name; };
773
774 switch (accepted_item.item_type)
775 {
776 case ItemType::pH:
777 {
778 // Update pH value
780 *aqueous_solution->pH);
781 aqueous_solution->pH->set(
782 global_index, std::pow(10, -accepted_items[item_id]));
783 break;
784 }
785 case ItemType::pe:
786 {
787 // Update pe value
788 (*aqueous_solution->pe)[chemical_system_id] =
789 accepted_items[item_id];
790 break;
791 }
793 {
794 // Update component concentrations
795 auto const& component = BaseLib::findElementOrError(
796 components, compare_by_name,
797 [&]() {
798 OGS_FATAL("Could not find component '{:s}'.",
799 item_name);
800 });
802 *component.amount);
803 component.amount->set(global_index,
804 accepted_items[item_id]);
805 break;
806 }
808 {
809 // Update amounts of equilibrium reactant
810 auto const& equilibrium_reactant =
812 equilibrium_reactants, compare_by_name,
813 [&]()
814 {
815 OGS_FATAL(
816 "Could not find equilibrium reactant "
817 "'{:s}'",
818 item_name);
819 });
820 (*equilibrium_reactant.molality)[chemical_system_id] =
821 accepted_items[item_id];
822 break;
823 }
825 {
826 // Update amounts of kinetic reactants
827 auto const& kinetic_reactant = BaseLib::findElementOrError(
828 kinetic_reactants, compare_by_name,
829 [&]() {
830 OGS_FATAL("Could not find kinetic reactant '{:s}'.",
831 item_name);
832 });
833 (*kinetic_reactant.molality)[chemical_system_id] =
834 accepted_items[item_id];
835 break;
836 }
838 {
839 assert(user_punch);
840 auto const& secondary_variables =
841 user_punch->secondary_variables;
842 // Update values of secondary variables
843 auto const& secondary_variable =
845 secondary_variables, compare_by_name,
846 [&]() {
847 OGS_FATAL(
848 "Could not find secondary variable '{:s}'.",
849 item_name);
850 });
851 (*secondary_variable.value)[chemical_system_id] =
852 accepted_items[item_id];
853 break;
854 }
855 }
856 }
857 }
858
859 return in;
860}
GlobalMatrix::IndexType GlobalIndexType
ranges::range_reference_t< Range > findElementOrError(Range &range, std::predicate< ranges::range_reference_t< Range > > auto &&predicate, std::invocable auto error_callback)
Definition Algorithm.h:74

References PhreeqcIO(), _chemical_system, _num_chemical_systems, _output, _user_punch, ChemistryLib::PhreeqcIOData::Component, ChemistryLib::PhreeqcIOData::EquilibriumReactant, BaseLib::findElementOrError(), ChemistryLib::PhreeqcIOData::KineticReactant, OGS_FATAL, ChemistryLib::PhreeqcIOData::pe, ChemistryLib::PhreeqcIOData::pH, ChemistryLib::PhreeqcIOData::SecondaryVariable, and MathLib::LinAlg::setLocalAccessibleVector().

Member Data Documentation

◆ _chemical_system

◆ _database

std::string const ChemistryLib::PhreeqcIOData::PhreeqcIO::_database
private

Definition at line 187 of file PhreeqcIO.h.

Referenced by PhreeqcIO().

◆ _dt

double ChemistryLib::PhreeqcIOData::PhreeqcIO::_dt = std::numeric_limits<double>::quiet_NaN()
private

Definition at line 194 of file PhreeqcIO.h.

Referenced by operator<<(), and operator<<.

◆ _dump

std::unique_ptr<Dump> const ChemistryLib::PhreeqcIOData::PhreeqcIO::_dump
private

Definition at line 192 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), operator<<, and setAqueousSolutionsPrevFromDumpFile().

◆ _knobs

Knobs const ChemistryLib::PhreeqcIOData::PhreeqcIO::_knobs
private

Definition at line 193 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), and operator<<.

◆ _num_chemical_systems

std::size_t ChemistryLib::PhreeqcIOData::PhreeqcIO::_num_chemical_systems = -1
private

Definition at line 196 of file PhreeqcIO.h.

Referenced by initialize(), operator<<, operator>>, and setAqueousSolutionsPrevFromDumpFile().

◆ _output

std::unique_ptr<Output> const ChemistryLib::PhreeqcIOData::PhreeqcIO::_output
private

Definition at line 191 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), operator<<, operator>>, and readOutputsFromFile().

◆ _phreeqc_input_file

std::string const ChemistryLib::PhreeqcIOData::PhreeqcIO::_phreeqc_input_file

Definition at line 172 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), callPhreeqc(), and writeInputsToFile().

◆ _reaction_rates

std::vector<ReactionRate> const ChemistryLib::PhreeqcIOData::PhreeqcIO::_reaction_rates
private

Definition at line 189 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), and operator<<.

◆ _user_punch

std::unique_ptr<UserPunch> ChemistryLib::PhreeqcIOData::PhreeqcIO::_user_punch
private

Definition at line 190 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), initialize(), operator<<, and operator>>.

◆ phreeqc_instance_id

const int ChemistryLib::PhreeqcIOData::PhreeqcIO::phreeqc_instance_id = 0
private

Definition at line 195 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), ~PhreeqcIO(), and callPhreeqc().


The documentation for this class was generated from the following files: