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, bool use_stream_mode)
 ~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)
std::stringstream writeInputsToStringStream (double const dt)
void setAqueousSolutionsPrevFromDumpString (std::string_view dump_content)
void callPhreeqc () const
void callPhreeqcWithString (std::string const &input_content) const
std::string_view retrieveSelectedOutputString () const
std::string_view retrieveDumpString () const
void readOutputsFromFile ()
void readOutputsFromStringView (std::string_view output_content)
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
bool _use_stream_mode = false

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,
bool use_stream_mode )

Definition at line 364 of file PhreeqcIO.cpp.

376 _phreeqc_input_file(specifyFileName(project_file_name, ".inp")),
377 _database(std::move(database)),
378 _chemical_system(std::move(chemical_system)),
379 _reaction_rates(std::move(reaction_rates)),
380 _user_punch(std::move(user_punch)),
381 _output(std::move(output)),
382 _dump(std::move(dump)),
383 _knobs(std::move(knobs)),
384 _use_stream_mode(use_stream_mode)
385{
386 // initialize phreeqc instance
387 if (CreateIPhreeqc() != phreeqc_instance_id)
388 {
389 OGS_FATAL(
390 "Failed to initialize phreeqc instance, due to lack of memory.");
391 }
392
393 // load specified thermodynamic database
394 if (LoadDatabase(phreeqc_instance_id, _database.c_str()) != IPQ_OK)
395 {
396 OGS_FATAL(
397 "Failed in loading the specified thermodynamic database file: "
398 "{:s}.",
399 _database);
400 }
401
403 {
404 // In stream mode, disable file-based selected output
405 // Output will be retrieved via GetSelectedOutputString() from memory
406 // buffer
407 if (SetSelectedOutputFileOn(phreeqc_instance_id, 0) != IPQ_OK)
408 {
409 OGS_FATAL(
410 "Failed to disable file output for selected output in stream "
411 "mode.");
412 }
413
414 // Enable in-memory buffering of selected output
415 if (SetSelectedOutputStringOn(phreeqc_instance_id, 1) != IPQ_OK)
416 {
417 OGS_FATAL(
418 "Failed to enable string buffering for selected output in "
419 "stream mode.");
420 }
421
422 INFO(
423 "PhreeqcIO stream mode: selected output file disabled, using "
424 "internal memory buffer.");
425 }
426 else
427 {
428 // In file mode, enable file-based selected output (current behavior)
429 if (SetSelectedOutputFileOn(phreeqc_instance_id, 1) != IPQ_OK)
430 {
431 OGS_FATAL(
432 "Failed to fly the flag for the specified file {:s} where "
433 "phreeqc will write output.",
434 _output->basic_output_setups.output_file);
435 }
436 }
437
438 if (_dump)
439 {
441 {
442 // In stream mode, disable file-based dump output
443 // Dump data will be retrieved via GetDumpString() instead
444 INFO(
445 "PhreeqcIO is configured for stream-based data exchange: dump "
446 "file output disabled.");
447 SetDumpFileOn(phreeqc_instance_id, 0);
448
449 // Enable in-memory buffering of dump output
450 if (SetDumpStringOn(phreeqc_instance_id, 1) != IPQ_OK)
451 {
452 OGS_FATAL(
453 "Failed to enable string buffering for dump output in "
454 "stream mode.");
455 }
456 }
457 else
458 {
459 // In file mode, enable file-based dump output (current behavior)
460 // Chemical composition of the aqueous solution of last time step
461 // will be written into .dmp file
462 SetDumpFileOn(phreeqc_instance_id, 1);
463 }
464 }
465
467 {
468 INFO(
469 "PhreeqcIO is configured for stream-based data exchange: input "
470 "and output will be exchanged via in-memory strings.");
471 }
472}
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
ChemicalSolverInterface(MeshLib::Mesh const &mesh, GlobalLinearSolver &linear_solver_)
std::unique_ptr< ChemicalSystem > _chemical_system
Definition PhreeqcIO.h:201
std::vector< ReactionRate > const _reaction_rates
Definition PhreeqcIO.h:202
std::unique_ptr< UserPunch > _user_punch
Definition PhreeqcIO.h:203
std::unique_ptr< Dump > const _dump
Definition PhreeqcIO.h:205
std::unique_ptr< Output > const _output
Definition PhreeqcIO.h:204
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, _use_stream_mode, _user_punch, INFO(), 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 474 of file PhreeqcIO.cpp.

475{
476 DestroyIPhreeqc(phreeqc_instance_id);
477}

References phreeqc_instance_id.

Member Function Documentation

◆ callPhreeqc()

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

Definition at line 879 of file PhreeqcIO.cpp.

880{
881 INFO("Phreeqc: Executing chemical calculation.");
882 if (RunFile(phreeqc_instance_id, _phreeqc_input_file.c_str()) != IPQ_OK)
883 {
884 OutputErrorString(phreeqc_instance_id);
885 OGS_FATAL(
886 "Failed in performing speciation calculation with the generated "
887 "phreeqc input file '{:s}'.",
889 }
890}

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

Referenced by executeSpeciationCalculation().

◆ callPhreeqcWithString()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::callPhreeqcWithString ( std::string const & input_content) const
private

Definition at line 892 of file PhreeqcIO.cpp.

893{
894 INFO("Phreeqc: Executing chemical calculation from string stream.");
895
896 if (RunString(phreeqc_instance_id, input_content.c_str()) != IPQ_OK)
897 {
898 OutputErrorString(phreeqc_instance_id);
899 OGS_FATAL(
900 "Failed in performing speciation calculation with string input.");
901 }
902}

References 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 1309 of file PhreeqcIO.cpp.

1312{
1313 for (auto const& kinetic_reactant : _chemical_system->kinetic_reactants)
1314 {
1315 (*kinetic_reactant.mesh_prop_molality)[ele_id] =
1316 averageReactantMolality(kinetic_reactant, chemical_system_indices);
1317 }
1318
1319 for (auto const& equilibrium_reactant :
1320 _chemical_system->equilibrium_reactants)
1321 {
1322 (*equilibrium_reactant.mesh_prop_molality)[ele_id] =
1323 averageReactantMolality(equilibrium_reactant,
1324 chemical_system_indices);
1325 }
1326}
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 563 of file PhreeqcIO.cpp.

564{
566 {
567 // Stream-based data exchange
568 DBUG("Executing speciation with stream-based data exchange.");
569
570 // This gives us a null-terminated string required by RunString().
571 std::string input_content = writeInputsToStringStream(dt).str();
572
573 // Execute PhreeqC with string input
574 callPhreeqcWithString(input_content);
575
576 // Retrieve output from memory buffer and parse
577 auto output_content = retrieveSelectedOutputString();
578 readOutputsFromStringView(output_content);
579
580 // Handle dump data if surfaces/exchangers exist
581 if (_dump)
582 {
583 auto dump_content = retrieveDumpString();
585 }
586 }
587 else
588 {
589 // File-based data exchange (original behavior)
590 DBUG("Executing speciation with file-based data exchange.");
591
593
594 callPhreeqc();
595
597 }
598}
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
void writeInputsToFile(double const dt)
void readOutputsFromStringView(std::string_view output_content)
void callPhreeqcWithString(std::string const &input_content) const
std::string_view retrieveDumpString() const
std::string_view retrieveSelectedOutputString() const
void setAqueousSolutionsPrevFromDumpString(std::string_view dump_content)
std::stringstream writeInputsToStringStream(double const dt)

References _dump, _use_stream_mode, callPhreeqc(), callPhreeqcWithString(), DBUG(), readOutputsFromFile(), readOutputsFromStringView(), retrieveDumpString(), retrieveSelectedOutputString(), setAqueousSolutionsPrevFromDumpString(), writeInputsToFile(), and writeInputsToStringStream().

◆ getComponentList()

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

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 1259 of file PhreeqcIO.cpp.

1260{
1261 std::vector<std::string> component_names;
1262 auto const& components = _chemical_system->aqueous_solution->components;
1263 std::transform(components.begin(), components.end(),
1264 std::back_inserter(component_names),
1265 [](auto const& c) { return c.name; });
1266
1267 component_names.push_back("H");
1268
1269 return component_names;
1270}

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 600 of file PhreeqcIO.cpp.

602{
603 auto const& aqueous_solution = *_chemical_system->aqueous_solution;
604 auto& components = aqueous_solution.components;
605 auto const& pH = *aqueous_solution.pH;
606
607 if (component_id < static_cast<int>(components.size()))
608 {
610 *components[component_id].amount);
611
612 return components[component_id].amount->get(chemical_system_id);
613 }
614
615 // pH
616 MathLib::LinAlg::setLocalAccessibleVector(*aqueous_solution.pH);
617
618 return pH.get(chemical_system_id);
619}
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 491 of file PhreeqcIO.cpp.

497{
498 setAqueousSolution(concentrations, chemical_system_id,
499 *_chemical_system->aqueous_solution);
500
501 auto const& solid_phase =
503 auto const& liquid_phase =
505
506 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
507 {
508 initializeReactantMolality(kinetic_reactant, chemical_system_id,
509 solid_phase, liquid_phase, medium, pos, t);
510 }
511
512 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
513 {
514 initializeReactantMolality(equilibrium_reactant, chemical_system_id,
515 solid_phase, liquid_phase, medium, pos, t);
516 }
517
518 for (auto& exchanger : _chemical_system->exchangers)
519 {
520 initializeSiteMolality(exchanger, chemical_system_id, solid_phase, pos,
521 t);
522 }
523
524 for (auto& surface_site : _chemical_system->surface)
525 {
526 if (auto const surface_site_ptr =
527 std::get_if<MoleBasedSurfaceSite>(&surface_site))
528 {
529 initializeSiteMolality(*surface_site_ptr, chemical_system_id,
530 solid_phase, pos, t);
531 }
532 }
533}
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)
void setAqueousSolution(std::vector< double > const &concentrations, GlobalIndexType const &chemical_system_id, AqueousSolution &aqueous_solution)

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

◆ operator<<()

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

Definition at line 194 of file PhreeqcIO.h.

195 {
196 _dt = dt;
197 return *this;
198 }

References PhreeqcIO(), and _dt.

◆ readOutputsFromFile()

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

Definition at line 933 of file PhreeqcIO.cpp.

934{
935 auto const& basic_output_setups = _output->basic_output_setups;
936 auto const& phreeqc_result_file = basic_output_setups.output_file;
937 DBUG("Reading phreeqc results from file '{:s}'.", phreeqc_result_file);
938 std::ifstream in(phreeqc_result_file);
939
940 if (!in)
941 {
942 OGS_FATAL("Could not open phreeqc result file '{:s}'.",
943 phreeqc_result_file);
944 }
945
946 in >> *this;
947
948 if (!in)
949 {
950 OGS_FATAL("Error when reading phreeqc result file '{:s}'",
951 phreeqc_result_file);
952 }
953
954 in.close();
955}

References _output, DBUG(), and OGS_FATAL.

Referenced by executeSpeciationCalculation().

◆ readOutputsFromStringView()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::readOutputsFromStringView ( std::string_view output_content)
private

Definition at line 957 of file PhreeqcIO.cpp.

958{
959 DBUG("Reading phreeqc results from string buffer.");
960
961 if (output_content.empty())
962 {
963 OGS_FATAL("Output content is empty.");
964 }
965
966 StringViewLineIterator line_iter(output_content);
967 std::string_view line;
968
969 // Skip the headline
970 line_iter.getline(line);
971
972 if (!_output)
973 {
974 OGS_FATAL(
975 "No output configuration available when reading PhreeqC results "
976 "strings.");
977 }
978
979 auto const& output = *_output;
980 auto const& dropped_item_ids = output.dropped_item_ids;
981
982 auto const& surface = _chemical_system->surface;
983 auto const& exchangers = _chemical_system->exchangers;
984
985 int const num_skipped_lines =
986 1 + (!surface.empty() ? 1 : 0) + (!exchangers.empty() ? 1 : 0);
987
988 auto& equilibrium_reactants = _chemical_system->equilibrium_reactants;
989 auto& kinetic_reactants = _chemical_system->kinetic_reactants;
990
991 for (std::size_t chemical_system_id = 0;
992 chemical_system_id < _num_chemical_systems;
993 ++chemical_system_id)
994 {
995 // Skip equilibrium calculation result of initial solution
996 line_iter.skip(num_skipped_lines);
997
998 // Get calculation result of the solution after the reaction
999 if (!line_iter.getline(line))
1000 {
1001 OGS_FATAL(
1002 "Error when reading calculation result of Solution {:d} "
1003 "after the reaction.",
1004 chemical_system_id);
1005 }
1006
1007 auto accepted_items = parseAndFilterChemicalData(
1008 std::string(line), dropped_item_ids, chemical_system_id);
1009 assert(accepted_items.size() == output.accepted_items.size());
1010
1011 auto& aqueous_solution = _chemical_system->aqueous_solution;
1012 auto& components = aqueous_solution->components;
1013 auto& user_punch = _user_punch;
1014
1015 GlobalIndexType const offset = aqueous_solution->pH->getRangeBegin();
1016 GlobalIndexType const global_index = offset + chemical_system_id;
1017
1018 for (int item_id = 0; item_id < static_cast<int>(accepted_items.size());
1019 ++item_id)
1020 {
1021 auto const& accepted_item = output.accepted_items[item_id];
1022 auto const& item_name = accepted_item.name;
1023
1024 auto compare_by_name = [&item_name](auto const& item)
1025 { return item.name == item_name; };
1026
1027 switch (accepted_item.item_type)
1028 {
1029 case ItemType::pH:
1030 {
1031 // Update pH value
1033 *aqueous_solution->pH);
1034 aqueous_solution->pH->set(
1035 global_index, std::pow(10, -accepted_items[item_id]));
1036 break;
1037 }
1038 case ItemType::pe:
1039 {
1040 // Update pe value
1041 (*aqueous_solution->pe)[chemical_system_id] =
1042 accepted_items[item_id];
1043 break;
1044 }
1046 {
1047 // Update component concentrations
1048 auto const& component = BaseLib::findElementOrError(
1049 components, compare_by_name,
1050 [&]() {
1051 OGS_FATAL("Could not find component '{:s}'.",
1052 item_name);
1053 });
1055 *component.amount);
1056 component.amount->set(global_index,
1057 accepted_items[item_id]);
1058 break;
1059 }
1061 {
1062 // Update amounts of equilibrium reactant
1063 auto const& equilibrium_reactant =
1065 equilibrium_reactants, compare_by_name,
1066 [&]()
1067 {
1068 OGS_FATAL(
1069 "Could not find equilibrium reactant "
1070 "'{:s}'",
1071 item_name);
1072 });
1073 (*equilibrium_reactant.molality)[chemical_system_id] =
1074 accepted_items[item_id];
1075 break;
1076 }
1078 {
1079 // Update amounts of kinetic reactants
1080 auto const& kinetic_reactant = BaseLib::findElementOrError(
1081 kinetic_reactants, compare_by_name,
1082 [&]() {
1083 OGS_FATAL("Could not find kinetic reactant '{:s}'.",
1084 item_name);
1085 });
1086 (*kinetic_reactant.molality)[chemical_system_id] =
1087 accepted_items[item_id];
1088 break;
1089 }
1091 {
1092 assert(user_punch);
1093 auto const& secondary_variables =
1094 user_punch->secondary_variables;
1095 // Update values of secondary variables
1096 auto const& secondary_variable =
1098 secondary_variables, compare_by_name,
1099 [&]() {
1100 OGS_FATAL(
1101 "Could not find secondary variable '{:s}'.",
1102 item_name);
1103 });
1104 (*secondary_variable.value)[chemical_system_id] =
1105 accepted_items[item_id];
1106 break;
1107 }
1108 }
1109 }
1110 }
1111}
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
std::vector< double > parseAndFilterChemicalData(std::string const &line, std::vector< int > const &dropped_item_ids, std::size_t chemical_system_id)

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

Referenced by executeSpeciationCalculation().

◆ retrieveDumpString()

std::string_view ChemistryLib::PhreeqcIOData::PhreeqcIO::retrieveDumpString ( ) const
private

Definition at line 918 of file PhreeqcIO.cpp.

919{
920 DBUG("Retrieving phreeqc dump data from internal buffer.");
921
922 const char* dump_ptr = GetDumpString(phreeqc_instance_id);
923 if (!dump_ptr)
924 {
925 // Dump might be empty in first time step
926 DBUG("Dump string is empty or unavailable.");
927 return std::string_view();
928 }
929
930 return std::string_view(dump_ptr);
931}

References DBUG(), and phreeqc_instance_id.

Referenced by executeSpeciationCalculation().

◆ retrieveSelectedOutputString()

std::string_view ChemistryLib::PhreeqcIOData::PhreeqcIO::retrieveSelectedOutputString ( ) const
private

Definition at line 904 of file PhreeqcIO.cpp.

905{
906 DBUG("Retrieving phreeqc results from internal memory buffer.");
907
908 const char* output_ptr = GetSelectedOutputString(phreeqc_instance_id);
909 if (!output_ptr)
910 {
911 DBUG("Selected output string is empty or unavailable.");
912 return std::string_view();
913 }
914
915 return std::string_view(output_ptr);
916}

References DBUG(), and phreeqc_instance_id.

Referenced by executeSpeciationCalculation().

◆ setAqueousSolutionsPrevFromDumpFile()

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

Reimplemented from ChemistryLib::ChemicalSolverInterface.

Definition at line 621 of file PhreeqcIO.cpp.

622{
623 if (!_dump)
624 {
625 return;
626 }
627
628 auto const& dump_file = _dump->dump_file;
629 std::ifstream in(dump_file);
630 if (!in)
631 {
632 // return if phreeqc dump file doesn't exist. This happens in
633 // the first time step when no dump file is provided by the user.
634 return;
635 }
636
637 _dump->readDumpFile(in, _num_chemical_systems);
638
639 if (!in)
640 {
641 OGS_FATAL("Error when reading phreeqc dump file '{:s}'", dump_file);
642 }
643
644 in.close();
645}

References _dump, _num_chemical_systems, and OGS_FATAL.

◆ setAqueousSolutionsPrevFromDumpString()

void ChemistryLib::PhreeqcIOData::PhreeqcIO::setAqueousSolutionsPrevFromDumpString ( std::string_view dump_content)
private

Definition at line 647 of file PhreeqcIO.cpp.

649{
650 if (!_dump)
651 {
652 return;
653 }
654
655 if (dump_content.empty())
656 {
657 // return if dump content is empty. This happens in
658 // the first time step when no dump data is available.
659 DBUG(
660 "Dump content is empty, skipping aqueous solutions initialization "
661 "from dump.");
662 return;
663 }
664
665 _dump->readDumpFromString(dump_content, _num_chemical_systems);
666}

References _dump, _num_chemical_systems, and DBUG().

Referenced by executeSpeciationCalculation().

◆ 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 535 of file PhreeqcIO.cpp.

541{
542 setAqueousSolution(concentrations, chemical_system_id,
543 *_chemical_system->aqueous_solution);
544
545 auto const& solid_phase =
547 auto const& liquid_phase =
549
550 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
551 {
552 setReactantMolality(kinetic_reactant, chemical_system_id, solid_phase,
553 liquid_phase, vars, pos, t, dt);
554 }
555
556 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
557 {
558 setReactantMolality(equilibrium_reactant, chemical_system_id,
559 solid_phase, liquid_phase, vars, pos, t, dt);
560 }
561}
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, MaterialPropertyLib::AqueousLiquid, MaterialPropertyLib::Medium::phase(), and MaterialPropertyLib::Solid.

◆ 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 1291 of file PhreeqcIO.cpp.

1295{
1296 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
1297 {
1298 setPorosityPostReaction(kinetic_reactant, chemical_system_id, medium,
1299 porosity);
1300 }
1301
1302 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
1303 {
1304 setPorosityPostReaction(equilibrium_reactant, chemical_system_id,
1305 medium, porosity);
1306 }
1307}
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 1272 of file PhreeqcIO.cpp.

1277{
1278 for (auto& kinetic_reactant : _chemical_system->kinetic_reactants)
1279 {
1280 updateReactantVolumeFraction(kinetic_reactant, chemical_system_id,
1281 medium, pos, porosity, t, dt);
1282 }
1283
1284 for (auto& equilibrium_reactant : _chemical_system->equilibrium_reactants)
1285 {
1286 updateReactantVolumeFraction(equilibrium_reactant, chemical_system_id,
1287 medium, pos, porosity, t, dt);
1288 }
1289}
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 686 of file PhreeqcIO.cpp.

687{
688 DBUG("Writing phreeqc inputs into file '{:s}'.", _phreeqc_input_file);
689 std::ofstream out(_phreeqc_input_file, std::ofstream::out);
690
691 if (!out)
692 {
693 OGS_FATAL("Could not open file '{:s}' for writing phreeqc inputs.",
695 }
696
697 out << std::scientific
698 << std::setprecision(std::numeric_limits<double>::max_digits10);
699 *this << dt;
700 out << *this;
701
702 if (!out)
703 {
704 OGS_FATAL("Failed in generating phreeqc input file '{:s}'.",
706 }
707
708 out.close();
709}

References _phreeqc_input_file, DBUG(), and OGS_FATAL.

Referenced by executeSpeciationCalculation().

◆ writeInputsToStringStream()

std::stringstream ChemistryLib::PhreeqcIOData::PhreeqcIO::writeInputsToStringStream ( double const dt)
private

Definition at line 668 of file PhreeqcIO.cpp.

669{
670 DBUG("Serializing phreeqc inputs to string stream.");
671 std::stringstream ss;
672
673 ss << std::scientific
674 << std::setprecision(std::numeric_limits<double>::max_digits10);
675 *this << dt;
676 ss << *this;
677
678 if (!ss)
679 {
680 OGS_FATAL("Failed in serializing phreeqc inputs to string.");
681 }
682
683 return ss;
684}

References DBUG(), and OGS_FATAL.

Referenced by executeSpeciationCalculation().

◆ operator<<

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

Definition at line 711 of file PhreeqcIO.cpp.

712{
713 bool const fixing_pe =
714 phreeqc_io._chemical_system->aqueous_solution->fixing_pe;
715 if (fixing_pe)
716 {
717 os << "PHASES\n"
718 << "Fix_pe\n"
719 << "e- = e-\n"
720 << "log_k 0.0\n\n";
721 }
722
723 os << phreeqc_io._knobs << "\n";
724
725 os << *phreeqc_io._output << "\n";
726
727 auto const& user_punch = phreeqc_io._user_punch;
728 if (user_punch)
729 {
730 os << *user_punch << "\n";
731 }
732
733 auto const& reaction_rates = phreeqc_io._reaction_rates;
734 if (!reaction_rates.empty())
735 {
736 os << "RATES\n";
737 os << reaction_rates << "\n";
738 }
739
740 for (std::size_t chemical_system_id = 0;
741 chemical_system_id < phreeqc_io._num_chemical_systems;
742 ++chemical_system_id)
743 {
744 os << "SOLUTION " << chemical_system_id + 1 << "\n";
745 phreeqc_io._chemical_system->aqueous_solution->print(
746 os, chemical_system_id);
747
748 auto const& dump = phreeqc_io._dump;
749 if (dump)
750 {
751 auto const& aqueous_solutions_prev = dump->aqueous_solutions_prev;
752 // Print previous aqueous solution if it exists.
753 if (!aqueous_solutions_prev.empty())
754 {
755 os << aqueous_solutions_prev[chemical_system_id] << "\n\n";
756 }
757 }
758
759 os << "USE solution none\n";
760 os << "END\n\n";
761
762 os << "USE solution " << chemical_system_id + 1 << "\n\n";
763
764 auto const& equilibrium_reactants =
765 phreeqc_io._chemical_system->equilibrium_reactants;
766 if (!equilibrium_reactants.empty() || fixing_pe)
767 {
768 os << "EQUILIBRIUM_PHASES " << chemical_system_id + 1 << "\n";
769 for (auto const& equilibrium_reactant : equilibrium_reactants)
770 {
771 equilibrium_reactant.print(os, chemical_system_id);
772 }
773 fixing_pe
774 ? os << "Fix_pe "
775 << -phreeqc_io._chemical_system->aqueous_solution->pe0
776 << " O2(g)\n\n"
777 : os << "\n";
778 }
779
780 auto const& kinetic_reactants =
781 phreeqc_io._chemical_system->kinetic_reactants;
782 if (!kinetic_reactants.empty())
783 {
784 os << "KINETICS " << chemical_system_id + 1 << "\n";
785 for (auto const& kinetic_reactant : kinetic_reactants)
786 {
787 kinetic_reactant.print(os, chemical_system_id);
788 }
789 os << "-steps " << phreeqc_io._dt << "\n\n";
790 }
791
792 auto const& surface = phreeqc_io._chemical_system->surface;
793 if (!surface.empty())
794 {
795 // To get the amount of surface species from the previous time step,
796 // an equilibration calculation with the previous aqueous solution
797 // is needed. The previous aqueous solution is saved using the
798 // PHREEQC keyword "DUMP" in the dump file and then stored as
799 // SOLUTION_RAW within aqueous_solutions_prev. Along with the
800 // PHREEQC keyword 'SURFACE', distinguish between the current and
801 // previous solutions, the previous solution number is added to the
802 // total number of chemical systems (_num_chemical_systems).
803 os << "SURFACE " << chemical_system_id + 1 << "\n";
804 std::size_t aqueous_solution_id =
805 dump->aqueous_solutions_prev.empty()
806 ? chemical_system_id + 1
807 : phreeqc_io._num_chemical_systems + chemical_system_id + 1;
808 os << "-equilibrate with solution " << aqueous_solution_id << "\n";
809
810 // print unit
811 if (std::holds_alternative<DensityBasedSurfaceSite>(
812 surface.front()))
813 {
814 os << "-sites_units density\n";
815 }
816 else
817 {
818 os << "-sites_units absolute\n";
819 }
820
821 for (auto const& surface_site : surface)
822 {
823 std::visit(
824 overloaded{[&os](DensityBasedSurfaceSite const& s)
825 {
826 os << s.name << " " << s.site_density << " "
827 << s.specific_surface_area << " "
828 << s.mass << "\n";
829 },
830 [&os, chemical_system_id](
831 MoleBasedSurfaceSite const& s) {
832 os << s.name << " "
833 << (*s.molality)[chemical_system_id]
834 << "\n";
835 }},
836 surface_site);
837 }
838
839 // overlook the effect of the buildup of charges onto the surface
840 if (std::holds_alternative<MoleBasedSurfaceSite>(surface.front()))
841 {
842 os << "-no_edl\n";
843 }
844 // Here the PHREEQC "save" command is printed to save the solution
845 // internally in PHREEQC. The solution composition is saved after
846 // equilibration with the surface has been completed. The solution
847 // will not be saved for use in the next PHREEQC run.
848 os << "SAVE solution " << chemical_system_id + 1 << "\n";
849 }
850
851 auto const& exchangers = phreeqc_io._chemical_system->exchangers;
852 if (!exchangers.empty())
853 {
854 os << "EXCHANGE " << chemical_system_id + 1 << "\n";
855 std::size_t const aqueous_solution_id =
856 dump->aqueous_solutions_prev.empty()
857 ? chemical_system_id + 1
858 : phreeqc_io._num_chemical_systems + chemical_system_id + 1;
859 os << "-equilibrate with solution " << aqueous_solution_id << "\n";
860 for (auto const& exchanger : exchangers)
861 {
862 exchanger.print(os, chemical_system_id);
863 }
864 os << "SAVE solution " << chemical_system_id + 1 << "\n";
865 }
866
867 os << "END\n\n";
868 }
869
870 auto const& dump = phreeqc_io._dump;
871 if (dump)
872 {
873 dump->print(os, phreeqc_io._num_chemical_systems);
874 }
875
876 return os;
877}

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 1113 of file PhreeqcIO.cpp.

1114{
1115 // Skip the headline
1116 in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
1117
1118 std::string line;
1119 auto const& output = *phreeqc_io._output;
1120 auto const& dropped_item_ids = output.dropped_item_ids;
1121
1122 auto const& surface = phreeqc_io._chemical_system->surface;
1123 auto const& exchangers = phreeqc_io._chemical_system->exchangers;
1124
1125 int const num_skipped_lines =
1126 1 + (!surface.empty() ? 1 : 0) + (!exchangers.empty() ? 1 : 0);
1127
1128 auto& equilibrium_reactants =
1129 phreeqc_io._chemical_system->equilibrium_reactants;
1130 auto& kinetic_reactants = phreeqc_io._chemical_system->kinetic_reactants;
1131
1132 for (std::size_t chemical_system_id = 0;
1133 chemical_system_id < phreeqc_io._num_chemical_systems;
1134 ++chemical_system_id)
1135 {
1136 // Skip equilibrium calculation result of initial solution
1137 for (int i = 0; i < num_skipped_lines; ++i)
1138 {
1139 in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
1140 }
1141
1142 // Get calculation result of the solution after the reaction
1143 if (!std::getline(in, line))
1144 {
1145 OGS_FATAL(
1146 "Error when reading calculation result of Solution {:d} "
1147 "after the reaction.",
1148 chemical_system_id);
1149 }
1150
1151 auto accepted_items = parseAndFilterChemicalData(line, dropped_item_ids,
1152 chemical_system_id);
1153 assert(accepted_items.size() == output.accepted_items.size());
1154
1155 auto& aqueous_solution = phreeqc_io._chemical_system->aqueous_solution;
1156 auto& components = aqueous_solution->components;
1157 auto& user_punch = phreeqc_io._user_punch;
1158
1159 GlobalIndexType const offset = aqueous_solution->pH->getRangeBegin();
1160 GlobalIndexType const global_index = offset + chemical_system_id;
1161
1162 for (int item_id = 0; item_id < static_cast<int>(accepted_items.size());
1163 ++item_id)
1164 {
1165 auto const& accepted_item = output.accepted_items[item_id];
1166 auto const& item_name = accepted_item.name;
1167
1168 auto compare_by_name = [&item_name](auto const& item)
1169 { return item.name == item_name; };
1170
1171 switch (accepted_item.item_type)
1172 {
1173 case ItemType::pH:
1174 {
1175 // Update pH value
1177 *aqueous_solution->pH);
1178 aqueous_solution->pH->set(
1179 global_index, std::pow(10, -accepted_items[item_id]));
1180 break;
1181 }
1182 case ItemType::pe:
1183 {
1184 // Update pe value
1185 (*aqueous_solution->pe)[chemical_system_id] =
1186 accepted_items[item_id];
1187 break;
1188 }
1190 {
1191 // Update component concentrations
1192 auto const& component = BaseLib::findElementOrError(
1193 components, compare_by_name,
1194 [&]() {
1195 OGS_FATAL("Could not find component '{:s}'.",
1196 item_name);
1197 });
1199 *component.amount);
1200 component.amount->set(global_index,
1201 accepted_items[item_id]);
1202 break;
1203 }
1205 {
1206 // Update amounts of equilibrium reactant
1207 auto const& equilibrium_reactant =
1209 equilibrium_reactants, compare_by_name,
1210 [&]()
1211 {
1212 OGS_FATAL(
1213 "Could not find equilibrium reactant "
1214 "'{:s}'",
1215 item_name);
1216 });
1217 (*equilibrium_reactant.molality)[chemical_system_id] =
1218 accepted_items[item_id];
1219 break;
1220 }
1222 {
1223 // Update amounts of kinetic reactants
1224 auto const& kinetic_reactant = BaseLib::findElementOrError(
1225 kinetic_reactants, compare_by_name,
1226 [&]() {
1227 OGS_FATAL("Could not find kinetic reactant '{:s}'.",
1228 item_name);
1229 });
1230 (*kinetic_reactant.molality)[chemical_system_id] =
1231 accepted_items[item_id];
1232 break;
1233 }
1235 {
1236 assert(user_punch);
1237 auto const& secondary_variables =
1238 user_punch->secondary_variables;
1239 // Update values of secondary variables
1240 auto const& secondary_variable =
1242 secondary_variables, compare_by_name,
1243 [&]() {
1244 OGS_FATAL(
1245 "Could not find secondary variable '{:s}'.",
1246 item_name);
1247 });
1248 (*secondary_variable.value)[chemical_system_id] =
1249 accepted_items[item_id];
1250 break;
1251 }
1252 }
1253 }
1254 }
1255
1256 return in;
1257}

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 200 of file PhreeqcIO.h.

Referenced by PhreeqcIO().

◆ _dt

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

Definition at line 207 of file PhreeqcIO.h.

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

◆ _dump

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

◆ _knobs

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

Definition at line 206 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), and operator<<.

◆ _num_chemical_systems

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

◆ _output

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

◆ _phreeqc_input_file

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

Definition at line 173 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 202 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), and operator<<.

◆ _use_stream_mode

bool ChemistryLib::PhreeqcIOData::PhreeqcIO::_use_stream_mode = false
private

Definition at line 210 of file PhreeqcIO.h.

Referenced by PhreeqcIO(), and executeSpeciationCalculation().

◆ _user_punch

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

Definition at line 203 of file PhreeqcIO.h.

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

◆ phreeqc_instance_id

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

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