mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-16 16:44:49 +01:00
Phreeqcpp class methods. Still compiles on Debug and Release, but problem with phrq_malloc in cvdense and cvode. git-svn-id: svn://136.177.114.72/svn_GW/phreeqcpp/trunk@3876 1feff8c3-07ed-0310-ac33-dd36852eb9cd
467 lines
12 KiB
C++
467 lines
12 KiB
C++
#include <algorithm> // std::replace
|
|
|
|
#if !defined(PHREEQC_CLASS)
|
|
#define EXTERNAL extern
|
|
#include "global.h"
|
|
#else
|
|
#include "Phreeqc.h"
|
|
#endif
|
|
#include "System.h"
|
|
#include "SSassemblage.h"
|
|
#include "Solution.h"
|
|
#include "Exchange.h"
|
|
#include "GasPhase.h"
|
|
#include "cxxKinetics.h"
|
|
#include "PPassemblage.h"
|
|
#include "SSassemblageSS.h"
|
|
#include "SSassemblage.h"
|
|
#include "Surface.h"
|
|
#include "cxxMix.h"
|
|
#include "Reaction.h"
|
|
#include "Temperature.h"
|
|
|
|
|
|
extern void ORCH_write_chemistry_species(std::ostream & chemistry_dat);
|
|
cxxSystem::cxxSystem(void)
|
|
{
|
|
this->solution = NULL;
|
|
this->exchange = NULL;
|
|
this->ppassemblage = NULL;
|
|
this->gasphase = NULL;
|
|
this->ssassemblage = NULL;
|
|
this->kinetics = NULL;
|
|
this->surface = NULL;
|
|
this->mix = NULL;
|
|
this->reaction = NULL;
|
|
this->temperature = NULL;
|
|
}
|
|
cxxSystem::~cxxSystem(void)
|
|
{
|
|
}
|
|
void
|
|
cxxSystem::Initialize(void)
|
|
{
|
|
this->solution = NULL;
|
|
this->exchange = NULL;
|
|
this->ppassemblage = NULL;
|
|
this->gasphase = NULL;
|
|
this->ssassemblage = NULL;
|
|
this->kinetics = NULL;
|
|
this->surface = NULL;
|
|
this->mix = NULL;
|
|
this->reaction = NULL;
|
|
this->temperature = NULL;
|
|
}
|
|
void
|
|
cxxSystem::totalize(PHREEQC_PTR_ARG)
|
|
{
|
|
//initialize
|
|
this->totals.clear();
|
|
//add solution
|
|
if (this->solution != NULL)
|
|
{
|
|
char token[MAX_LENGTH];
|
|
strcpy(token, "O");
|
|
this->totals[token] = this->solution->get_total_o();
|
|
strcpy(token, "H");
|
|
this->totals[token] = this->solution->get_total_h();
|
|
strcpy(token, "Charge");
|
|
this->totals[token] = this->solution->get_cb();
|
|
this->totals.add_extensive(this->solution->get_totals(), 1.0);
|
|
}
|
|
if (this->exchange != NULL)
|
|
{
|
|
this->exchange->totalize();
|
|
this->totals.add_extensive(this->exchange->get_totals(), 1.0);
|
|
}
|
|
if (this->ppassemblage != NULL)
|
|
{
|
|
this->ppassemblage->totalize(P_INSTANCE);
|
|
this->totals.add_extensive(this->ppassemblage->get_totals(), 1.0);
|
|
}
|
|
if (this->gasphase != NULL)
|
|
{
|
|
this->gasphase->totalize(P_INSTANCE);
|
|
this->totals.add_extensive(this->gasphase->get_totals(), 1.0);
|
|
}
|
|
if (this->ssassemblage != NULL)
|
|
{
|
|
this->ssassemblage->totalize(P_INSTANCE);
|
|
this->totals.add_extensive(this->ssassemblage->get_totals(), 1.0);
|
|
}
|
|
if (this->surface != NULL)
|
|
{
|
|
this->ssassemblage->totalize(P_INSTANCE);
|
|
this->totals.add_extensive(this->surface->get_totals(), 1.0);
|
|
}
|
|
//Need to handle the following 3 reactions:
|
|
//
|
|
//this->kinetics = NULL;
|
|
//this->mix = NULL;
|
|
//this->reaction = NULL;
|
|
//this->temperature = NULL;
|
|
//this->totals.dump_raw(std::cerr, 1);
|
|
return;
|
|
}
|
|
#ifdef ORCHESTRA
|
|
void
|
|
cxxSystem::ORCH_write(std::ostream & chemistry_dat, std::ostream & input_dat,
|
|
std::ostream & output_dat)
|
|
{
|
|
//
|
|
// chemistry file
|
|
//
|
|
this->totalize();
|
|
// calculate orchestra components from PHREEQC totals
|
|
this->ORCH_components();
|
|
// write definitions for chemistry
|
|
chemistry_dat << std::
|
|
endl << "@class: species_reactions () {" << std::endl;
|
|
this->ORCH_write_chemistry_water(chemistry_dat);
|
|
this->ORCH_write_chemistry_primary(chemistry_dat);
|
|
this->ORCH_write_chemistry_total_O_H(chemistry_dat);
|
|
ORCH_write_chemistry_species(chemistry_dat);
|
|
// add definitions for pure phases
|
|
if (this->ppassemblage != NULL)
|
|
this->ppassemblage->ORCH_write_chemistry(chemistry_dat);
|
|
// add definitions for other PHREEQC entities here
|
|
// finish up
|
|
chemistry_dat << std::endl << "}" << std::endl;
|
|
//
|
|
// input file
|
|
//
|
|
input_dat << std::endl << "@class: input_file_data () {" << std::endl;
|
|
this->ORCH_write_input(input_dat);
|
|
input_dat << std::endl << "}" << std::endl;
|
|
//
|
|
// output file
|
|
//
|
|
output_dat << std::endl << "Output_every: 1" << std::endl;
|
|
output_dat << "Var:";
|
|
this->ORCH_write_output_vars(output_dat);
|
|
// add definitions for pure phases
|
|
if (this->ppassemblage != NULL)
|
|
this->ppassemblage->ORCH_write_output_vars(output_dat);
|
|
//finish up
|
|
output_dat << std::endl;
|
|
};
|
|
void
|
|
cxxSystem::ORCH_write_chemistry_water(std::ostream & chemistry_dat)
|
|
{
|
|
//
|
|
// Write water entities
|
|
//
|
|
chemistry_dat << std::
|
|
endl << "//********* The water entities" << std::endl;
|
|
// e-, total hydrogen
|
|
chemistry_dat << "@entity(e-, diss, 0)" << std::endl;
|
|
chemistry_dat << "@Calc: (1, \"e-.act = 10.^(-pe)\")" << std::endl;
|
|
chemistry_dat << "@solve (pe, 1e-6, lin, 1, e-.liter, 1e-14)" << std::
|
|
endl;
|
|
// H+, charge balance
|
|
chemistry_dat << "@Calc: (1, \"H+.act = 10.^(-pH)\")" << std::endl;
|
|
chemistry_dat << "@solve (pH, 1e-6, lin, 1, H+.liter, 1e-14)" << std::
|
|
endl;
|
|
// H2O
|
|
chemistry_dat << "@entity(" << s_h2o->
|
|
name << ", diss, 55.506)" << std::endl;
|
|
chemistry_dat << std::endl;
|
|
}
|
|
void
|
|
cxxSystem::ORCH_write_chemistry_primary(std::ostream & chemistry_dat)
|
|
{
|
|
chemistry_dat << std::endl << "//********* The primary species" << std::
|
|
endl;
|
|
//
|
|
// Write other master species definitions, i.e. primary entities
|
|
//
|
|
chemistry_dat << "@species(H+, 1)" << std::endl;
|
|
for (cxxNameDouble::iterator iter = this->totals.begin();
|
|
iter != this->totals.end(); ++iter)
|
|
{
|
|
std::string name(iter->first);
|
|
if (name == "H(1)" || name == "E" || name == "H" || name == "O"
|
|
|| name == "Charge")
|
|
continue;
|
|
struct element *elt;
|
|
char *element_name = string_hsave(name.c_str());
|
|
elt = element_store(element_name);
|
|
assert(elt != NULL);
|
|
struct species *s_ptr;
|
|
s_ptr = elt->master->s;
|
|
assert(s_ptr != NULL);
|
|
chemistry_dat << "@species(" << s_ptr->name << ", " << s_ptr->
|
|
z << ")" << std::endl;
|
|
// regular mole balance
|
|
chemistry_dat << "@primary_entity(" << s_ptr->
|
|
name << ", 1e-9, liter, 1.0e-9)" << std::endl;
|
|
}
|
|
chemistry_dat << std::endl;
|
|
}
|
|
void
|
|
cxxSystem::ORCH_write_chemistry_total_O_H(std::ostream & chemistry_dat)
|
|
{
|
|
chemistry_dat << std::
|
|
endl << "//********* Define total hydrogen and oxygen" << std::endl;
|
|
// Write H total equation
|
|
chemistry_dat << "@var: total_hydrogen 0" << std::endl;
|
|
chemistry_dat << "@calc: (5, \"total_hydrogen = 0";
|
|
int i;
|
|
for (i = 0; i < count_s_x; i++)
|
|
{
|
|
// write in terms of orchestra components
|
|
if (s_x[i]->primary != NULL
|
|
|| (s_x[i]->secondary != NULL
|
|
&& s_x[i]->secondary->in == TRUE))
|
|
{
|
|
if (s_x[i]->h != 0)
|
|
{
|
|
chemistry_dat << "+";
|
|
if (s_x[i]->h != 1)
|
|
{
|
|
chemistry_dat << s_x[i]->h << "*";
|
|
}
|
|
chemistry_dat << "{" << s_x[i]->name << ".liter}";
|
|
}
|
|
}
|
|
}
|
|
chemistry_dat << "\")" << std::endl;
|
|
// Write O total equation
|
|
chemistry_dat << "@var: total_oxygen 0" << std::endl;
|
|
chemistry_dat << "@calc: (5, \"total_oxygen = 0";
|
|
for (i = 0; i < count_s_x; i++)
|
|
{
|
|
if (s_x[i]->o != 0)
|
|
{
|
|
// write in terms of orchestra components
|
|
if (s_x[i]->primary != NULL
|
|
|| (s_x[i]->secondary != NULL
|
|
&& s_x[i]->secondary->in == TRUE))
|
|
{
|
|
chemistry_dat << "+";
|
|
if (s_x[i]->o != 1)
|
|
{
|
|
chemistry_dat << s_x[i]->o << "*";
|
|
}
|
|
chemistry_dat << "{" << s_x[i]->name << ".liter}";
|
|
}
|
|
}
|
|
}
|
|
chemistry_dat << "\")" << std::endl;
|
|
chemistry_dat << std::endl;
|
|
}
|
|
void
|
|
cxxSystem::ORCH_write_input(std::ostream & input_dat)
|
|
{
|
|
//
|
|
// Write orchestra input file info
|
|
//
|
|
std::ostringstream headings, data;
|
|
data.precision(DBL_DIG - 1);
|
|
headings << "var: ";
|
|
data << "data: ";
|
|
headings << "tempc\t";
|
|
data << this->solution->get_tc() << "\t";
|
|
headings << "pH\t";
|
|
data << this->solution->get_ph() << "\t";
|
|
headings << "pe\t";
|
|
data << this->solution->get_pe() << "\t";
|
|
headings << "H2O.act\t";
|
|
data << 1 << "\t";
|
|
headings << "I\t";
|
|
data << this->solution->get_mu() << "\t";
|
|
for (cxxNameDouble::iterator iter = this->orch_totals.begin();
|
|
iter != this->orch_totals.end(); ++iter)
|
|
{
|
|
headings << iter->first << ".liter" << "\t";
|
|
data << iter->second << "\t";
|
|
}
|
|
// activity estimate
|
|
for (cxxNameDouble::iterator iter = this->totals.begin();
|
|
iter != this->totals.end(); ++iter)
|
|
{
|
|
if (iter->first == "O" || iter->first == "Charge")
|
|
continue;
|
|
std::string master_name;
|
|
struct master *master_ptr;
|
|
master_ptr = master_bsearch(iter->first);
|
|
assert(master_ptr != NULL);
|
|
cxxNameDouble ma = this->solution->get_master_activity();
|
|
cxxNameDouble::iterator it = ma.find(iter->first);
|
|
if (it == ma.end())
|
|
{
|
|
it = ma.find(master_ptr->s->secondary->elt->name);
|
|
}
|
|
headings << master_ptr->s->name << ".act\t";
|
|
if (it != ma.end())
|
|
{
|
|
data << pow(10., it->second) << "\t";
|
|
}
|
|
else
|
|
{
|
|
data << 1e-9 << "\t";
|
|
}
|
|
}
|
|
// Isotopes
|
|
//s_oss << "-Isotopes" << std::endl;
|
|
/*
|
|
{
|
|
for (std::list<cxxSolutionIsotope>::const_iterator it = this->isotopes.begin(); it != isotopes.end(); ++it) {
|
|
it->dump_raw(s_oss, indent + 2);
|
|
}
|
|
}
|
|
*/
|
|
// Write data to string
|
|
input_dat << headings.str() << std::endl;
|
|
input_dat << data.str() << std::endl;
|
|
return;
|
|
}
|
|
void
|
|
cxxSystem::ORCH_components(void)
|
|
{
|
|
// translate from H, O, charge to H+tot, e-tot, and H2Otot
|
|
cxxNameDouble::iterator it;
|
|
cxxNameDouble temp_totals;
|
|
//
|
|
// Set names in orch_totals to master species names
|
|
//
|
|
this->orch_totals.clear();
|
|
temp_totals = this->totals;
|
|
temp_totals.erase("H");
|
|
temp_totals.erase("O");
|
|
temp_totals.erase("Charge");
|
|
//temp_totals.dump_raw(std::cerr, 1);
|
|
for (it = temp_totals.begin(); it != temp_totals.end(); it++)
|
|
{
|
|
struct element *elt_ptr;
|
|
elt_ptr = element_store(it->first);
|
|
assert(elt_ptr != NULL);
|
|
struct master *master_ptr;
|
|
master_ptr = elt_ptr->primary;
|
|
assert(master_ptr != NULL);
|
|
double coef = master_ptr->coef;
|
|
if (master_ptr->coef == 0)
|
|
{
|
|
coef = 1;
|
|
}
|
|
this->orch_totals[master_ptr->s->name] = it->second / coef;
|
|
}
|
|
//
|
|
// Calculate h2otot
|
|
//
|
|
it = this->totals.find("O");
|
|
assert(it != this->totals.end());
|
|
double h2otot = it->second;
|
|
// subtract O in master species
|
|
for (it = temp_totals.begin(); it != temp_totals.end(); it++)
|
|
{
|
|
struct element *elt_ptr;
|
|
elt_ptr = element_store(it->first);
|
|
struct master *master_ptr;
|
|
master_ptr = elt_ptr->primary;
|
|
h2otot -= it->second * master_ptr->s->o;
|
|
}
|
|
//
|
|
// Calculate htot
|
|
//
|
|
it = this->totals.find("H");
|
|
assert(it != this->totals.end());
|
|
double htot = it->second - 2 * h2otot;
|
|
// subtract O in master species
|
|
for (it = temp_totals.begin(); it != temp_totals.end(); it++)
|
|
{
|
|
struct element *elt_ptr;
|
|
elt_ptr = element_store(it->first);
|
|
struct master *master_ptr;
|
|
master_ptr = elt_ptr->primary;
|
|
htot -= it->second * master_ptr->s->h;
|
|
}
|
|
//
|
|
// Calculate etot
|
|
//
|
|
it = this->totals.find("Charge");
|
|
assert(it != this->totals.end());
|
|
double etot = -it->second + htot;
|
|
// subtract O in master species
|
|
for (it = temp_totals.begin(); it != temp_totals.end(); it++)
|
|
{
|
|
struct element *elt_ptr;
|
|
elt_ptr = element_store(it->first);
|
|
struct master *master_ptr;
|
|
master_ptr = elt_ptr->primary;
|
|
etot += it->second * master_ptr->s->z;
|
|
}
|
|
//
|
|
// store h2otot, htot, etot in orch_totals
|
|
//
|
|
this->orch_totals["H2O"] = h2otot;
|
|
this->orch_totals["H+"] = htot;
|
|
this->orch_totals["e-"] = etot;
|
|
this->orch_totals.dump_raw(std::cerr, 1);
|
|
}
|
|
void
|
|
cxxSystem::ORCH_write_output_vars(std::ostream & outstream)
|
|
{
|
|
outstream << "\tnr_iter";
|
|
//
|
|
// Serialize solution
|
|
//
|
|
outstream << "\tstart_solution";
|
|
//tc
|
|
outstream << "\ttempc";
|
|
//pH
|
|
outstream << "\tpH";
|
|
//pe
|
|
outstream << "\tpe";
|
|
//mu
|
|
outstream << "\tI";
|
|
//ah2o
|
|
outstream << "\tH2O.act";
|
|
//total_h;
|
|
outstream << "\ttotal_hydrogen";
|
|
//total_o;
|
|
outstream << "\ttotal_oxygen";
|
|
//cb
|
|
outstream << "\tchargebalance";
|
|
//mass_water;
|
|
outstream << "\tH2O.con";
|
|
//total_alkalinity;
|
|
outstream << "\tAlkalinity";
|
|
//orchestra master variables
|
|
outstream << "\tH+.diss";
|
|
outstream << "\te-.diss";
|
|
outstream << "\tH2O.diss";
|
|
//
|
|
// Write totals
|
|
for (cxxNameDouble::iterator it = this->orch_totals.begin();
|
|
it != this->orch_totals.end(); it++)
|
|
{
|
|
if (it->first == "H+" || it->first == "H2O" || it->first == "e-")
|
|
continue;
|
|
outstream << "\t" << it->first << ".diss";
|
|
}
|
|
outstream << "\tend_totals";
|
|
for (cxxNameDouble::iterator it = this->orch_totals.begin();
|
|
it != this->orch_totals.end(); it++)
|
|
{
|
|
if (it->first == "H+" || it->first == "H2O" || it->first == "e-")
|
|
continue;
|
|
outstream << "\t" << it->first << ".act";
|
|
}
|
|
outstream << "\tend_master_activities";
|
|
//
|
|
// Write all species activities and concentrations
|
|
//
|
|
int i;
|
|
for (i = 0; i < count_s_x; i++)
|
|
{
|
|
std::string name(s_x[i]->name);
|
|
std::replace(name.begin(), name.end(), '(', '[');
|
|
std::replace(name.begin(), name.end(), ')', ']');
|
|
outstream << "\t" << name.c_str() << ".act" << "\t" << name.
|
|
c_str() << ".con";
|
|
}
|
|
outstream << "\tend_species";
|
|
}
|
|
#endif /* */
|