OGS
PhreeqcIOData/AqueousSolution.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "AqueousSolution.h"
5
6#include <cmath>
7#include <ostream>
8
9#include "BaseLib/Error.h"
12
13namespace ChemistryLib
14{
15namespace PhreeqcIOData
16{
17void AqueousSolution::print(std::ostream& os,
18 std::size_t const chemical_system_id) const
19{
20 os << "temp " << temperature << "\n";
21
22 os << "pressure " << pressure << "\n";
23
24 double const pH_value = -std::log10(H_plus_activity[chemical_system_id]);
25
26 switch (charge_balance)
27 {
29 os << "pH " << pH_value << " charge" << "\n";
30 os << "pe " << (*pe)[chemical_system_id] << "\n";
31 break;
33 os << "pH " << pH_value << "\n";
34 os << "pe " << (*pe)[chemical_system_id] << " charge" << "\n";
35 break;
37 os << "pH " << pH_value << "\n";
38 os << "pe " << (*pe)[chemical_system_id] << "\n";
39 break;
40 }
41
42 os << "units mol/kgw\n";
43
44 for (auto const& component : components)
45 {
46 os << component.name << " " << component.amount[chemical_system_id];
47 component.chemical_formula.empty()
48 ? os << "\n"
49 : os << " as " << component.chemical_formula << "\n";
50 }
51
52 os << "\n\n";
53}
54
55ClampingStats setAqueousSolution(std::vector<double> const& concentrations,
56 std::size_t const chemical_system_id,
57 AqueousSolution& aqueous_solution,
58 double const warning_threshold)
59{
60 ClampingStats stats;
61 auto& components = aqueous_solution.components;
62 for (unsigned component_id = 0; component_id < components.size();
63 ++component_id)
64 {
65 components[component_id].amount[chemical_system_id] =
66 stats.clamp(concentrations[component_id], warning_threshold,
67 components[component_id].name);
68 }
69 // clamp() collects value-level counters; the per-cell counters are this
70 // one cell's contribution to the run-level accumulator.
71 stats.n_cells = stats.n_values > 0 ? 1 : 0;
72 stats.n_severe_cells = stats.n_severe_values > 0 ? 1 : 0;
73
74 // The transport process carries the H+ activity 10^-pH as the last entry
75 // of the concentrations vector for the pH "component". Unlike component
76 // concentrations it is not clamped: PHREEQC assumes 1 kg of water, and
77 // water autoprotolysis always yields some H+, so a non-positive H+ activity
78 // is physically impossible. Clamping it to zero would make
79 // pH = -log10(activity) NaN/inf, so a non-positive value here signals a
80 // transport-side bug rather than floating-point noise.
81 double const h_plus_activity = concentrations.back();
82 if (h_plus_activity <= 0.0)
83 {
85 "H+ activity (10^-pH) at chemical system {:d} is {:g} <= 0, which "
86 "is physically impossible (PHREEQC's 1 kg-water assumption "
87 "guarantees a positive H+ activity).",
88 chemical_system_id, h_plus_activity);
89 }
90 aqueous_solution.H_plus_activity[chemical_system_id] = h_plus_activity;
91 return stats;
92}
93} // namespace PhreeqcIOData
94} // namespace ChemistryLib
#define OGS_FATAL(...)
Definition Error.h:10
Per-system aqueous state exchanged with PHREEQC.
ClampingStats setAqueousSolution(std::vector< double > const &concentrations, std::size_t const chemical_system_id, AqueousSolution &aqueous_solution, double const warning_threshold)
std::vector< double > H_plus_activity
H+ activity 10^-pH, per chemical_system_id.
void print(std::ostream &os, std::size_t const chemical_system_id) const
std::size_t n_severe_values
total severe values clamped
std::size_t n_severe_cells
cells with a severe clamp
double clamp(double c, double warning_threshold, std::string_view name)
std::size_t n_values
total values clamped
std::size_t n_cells
cells with any clamping