iphreeqc/KineticsComp.cxx
David L Parkhurst 694c07488e Bugs with kinetics in PHAST.
The formula was not correct when converted to a phreeqcpp class, only the last instance of an element was kept and the rest were lost. Modified NameDouble to accumulate the sum of coefficients for each element when converting from a PHREEQC structure.

The order of the kinetics components was not maintained when converted to a phreeqcpp class. Components were in alphabetical order. This posed a problem with get and put statements because the gets could end up before the puts. Changed from map of components to list of components, which should maintain the order correctly.

Problems with modify solution and redox elements. Laurin pointed out that adding N may leave all the N(x) in place, which increases the total N. Revised read_solution to merge the valence states. If N defined, then all N(x) are removed. If N() defined, then N is removed. Still need to test.


git-svn-id: svn://136.177.114.72/svn_GW/phreeqcpp/trunk@3927 1feff8c3-07ed-0310-ac33-dd36852eb9cd
2010-01-14 16:26:14 +00:00

467 lines
12 KiB
C++

// KineticsComp.cxx: implementation of the cxxKineticsComp class.
//
//////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#pragma warning(disable : 4786) // disable truncation warning (Only used by debugger)
#endif
#include <cassert> // assert
#include <algorithm> // std::sort
#include "Utils.h" // define first
#if !defined(PHREEQC_CLASS)
#define EXTERNAL extern
#include "global.h"
#else
#include "Phreeqc.h"
#endif
#include "KineticsComp.h"
#include "Dictionary.h"
#include "phqalloc.h"
#include "phrqproto.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
cxxKineticsComp::cxxKineticsComp()
//
// default constructor for cxxKineticsComp
//
{
tol = 1e-8;
m = 0.0;
m0 = 0.0;
moles = 0.0;
namecoef.type = cxxNameDouble::ND_NAME_COEF;
}
cxxKineticsComp::cxxKineticsComp(struct kinetics_comp *kinetics_comp_ptr)
//
// constructor for cxxKineticsComp from struct kinetics_comp
//
:
namecoef(kinetics_comp_ptr->list, kinetics_comp_ptr->count_list)
{
this->set_rate_name(kinetics_comp_ptr->rate_name);
tol = kinetics_comp_ptr->tol;
m = kinetics_comp_ptr->m;
m0 = kinetics_comp_ptr->m0;
moles = kinetics_comp_ptr->moles;
for (int i = 0; i < kinetics_comp_ptr->count_d_params; i++)
{
this->d_params.push_back(kinetics_comp_ptr->d_params[i]);
}
}
cxxKineticsComp::~cxxKineticsComp()
{
}
struct kinetics_comp *
cxxKineticsComp::cxxKineticsComp2kinetics_comp(PHREEQC_PTR_ARG_COMMA std::list < cxxKineticsComp >
&el)
//
// Builds kinetics_comp structure from of cxxKineticsComp
//
{
struct kinetics_comp *kinetics_comp_ptr =
(struct kinetics_comp *)
P_INSTANCE_POINTER PHRQ_malloc((size_t) (el.size() * sizeof(struct kinetics_comp)));
if (kinetics_comp_ptr == NULL)
P_INSTANCE_POINTER malloc_error();
int i = 0;
for (std::list < cxxKineticsComp >::iterator it = el.begin();
it != el.end(); ++it)
{
if ((*it).rate_name.size() == 0)
kinetics_comp_ptr[i].rate_name = NULL;
else
kinetics_comp_ptr[i].rate_name = P_INSTANCE_POINTER string_hsave((*it).rate_name.c_str());
kinetics_comp_ptr[i].list = (*it).namecoef.name_coef(P_INSTANCE);
kinetics_comp_ptr[i].count_list = (int) (*it).namecoef.size();
kinetics_comp_ptr[i].tol = (*it).tol;
kinetics_comp_ptr[i].m = (*it).m;
kinetics_comp_ptr[i].initial_moles = 0.;
kinetics_comp_ptr[i].m0 = (*it).m0;
kinetics_comp_ptr[i].moles = (*it).moles;
kinetics_comp_ptr[i].count_c_params = 0;
kinetics_comp_ptr[i].c_params = NULL;
/*
kinetics_comp_ptr[i].count_d_params = 0;
kinetics_comp_ptr[i].d_params = NULL;
*/
kinetics_comp_ptr[i].count_d_params = (int) (*it).d_params.size();
kinetics_comp_ptr[i].d_params = NULL;
if ((*it).d_params.size() > 0)
{
kinetics_comp_ptr[i].d_params = (double *)
P_INSTANCE_POINTER PHRQ_malloc((size_t) ((*it).d_params.size() * sizeof(double)));
if (kinetics_comp_ptr[i].d_params == NULL)
P_INSTANCE_POINTER malloc_error();
std::copy((*it).d_params.begin(), (*it).d_params.end(),
kinetics_comp_ptr[i].d_params);
}
i++;
}
return (kinetics_comp_ptr);
}
#ifdef SKIP
void
cxxKineticsComp::dump_xml(std::ostream & s_oss, unsigned int indent) const const
{
//const char ERR_MESSAGE[] = "Packing kinetics_comp message: %s, element not found\n";
unsigned int i;
s_oss.precision(DBL_DIG - 1);
std::string indent0(""), indent1(""), indent2("");
for (i = 0; i < indent; ++i)
indent0.append(Utilities::INDENT);
for (i = 0; i < indent + 1; ++i)
indent1.append(Utilities::INDENT);
for (i = 0; i < indent + 2; ++i)
indent2.append(Utilities::INDENT);
// Kinetics_Comp element and attributes
s_oss << indent0 << "formula=\"" << this->formula << "\"" << std::endl;
s_oss << indent0 << "moles=\"" << this->moles << "\"" << std::endl;
s_oss << indent0 << "la=\"" << this->la << "\"" << std::endl;
s_oss << indent0 << "charge_balance=\"" << this->
charge_balance << "\"" << std::endl;
if (this->phase_name != NULL)
{
s_oss << indent0 << "phase_name=\"" << this->
phase_name << "\"" << std::endl;
}
if (this->rate_name != NULL)
{
s_oss << indent0 << "rate_name=\"" << this->
rate_name << "\"" << std::endl;
}
s_oss << indent0 << "phase_proportion=\"" << this->
phase_proportion << "\"" << std::endl;
// totals
s_oss << indent0;
s_oss << "<totals " << std::endl;
this->totals.dump_xml(s_oss, indent + 1);
// formula_totals
s_oss << indent0;
s_oss << "<formula_totals " << std::endl;
this->formula_totals.dump_xml(s_oss, indent + 1);
}
#endif
void
cxxKineticsComp::dump_raw(std::ostream & s_oss, unsigned int indent) const
{
//const char ERR_MESSAGE[] = "Packing kinetics_comp message: %s, element not found\n";
unsigned int i;
s_oss.precision(DBL_DIG - 1);
std::string indent0(""), indent1(""), indent2("");
for (i = 0; i < indent; ++i)
indent0.append(Utilities::INDENT);
for (i = 0; i < indent + 1; ++i)
indent1.append(Utilities::INDENT);
for (i = 0; i < indent + 2; ++i)
indent2.append(Utilities::INDENT);
// Kinetics_Comp element and attributes
s_oss << indent0 << "-rate_name " << this->
rate_name << std::endl;
s_oss << indent1 << "-tol " << this->tol << std::endl;
s_oss << indent1 << "-m " << this->m << std::endl;
s_oss << indent1 << "-m0 " << this->m0 << std::endl;
s_oss << indent1 << "-moles " << this->moles << std::endl;
// namecoef
s_oss << indent1;
s_oss << "-namecoef" << std::endl;
this->namecoef.dump_raw(s_oss, indent + 2);
// d_params
s_oss << indent1;
s_oss << "-d_params" << std::endl;
{
int i = 0;
s_oss << indent2;
for (std::vector < double >::const_iterator it = d_params.begin();
it != d_params.end(); it++)
{
if (i++ == 5)
{
s_oss << std::endl;
s_oss << indent2;
i = 0;
}
s_oss << *it << " ";
}
s_oss << std::endl;
}
}
void
cxxKineticsComp::read_raw(PHREEQC_PTR_ARG_COMMA CParser & parser, bool check)
{
std::string str;
double d;
static std::vector < std::string > vopts;
if (vopts.empty())
{
vopts.reserve(10);
vopts.push_back("rate_name"); // 0
vopts.push_back("tol"); // 1
vopts.push_back("m"); // 2
vopts.push_back("m0"); // 3
vopts.push_back("moles"); // 4
vopts.push_back("namecoef"); // 5
vopts.push_back("d_params"); // 6
}
std::istream::pos_type ptr;
std::istream::pos_type next_char;
std::string token;
int opt_save;
std::vector < double > temp_d_params;
opt_save = CParser::OPT_ERROR;
bool rate_name_defined(false);
bool tol_defined(false);
bool m_defined(false);
bool m0_defined(false);
bool moles_defined(false);
bool d_params_defined(false);
for (;;)
{
int opt = parser.get_option(vopts, next_char);
if (opt == CParser::OPT_DEFAULT)
{
opt = opt_save;
}
switch (opt)
{
case CParser::OPT_EOF:
break;
case CParser::OPT_KEYWORD:
break;
case CParser::OPT_DEFAULT:
case CParser::OPT_ERROR:
opt = CParser::OPT_KEYWORD;
// Allow return to Kinetics for more processing
//parser.error_msg("Unknown input in KINETICS_COMP read.", CParser::OT_CONTINUE);
//parser.error_msg(parser.line().c_str(), CParser::OT_CONTINUE);
break;
case 0: // rate_name
if (!(parser.get_iss() >> str))
{
this->rate_name.clear();
parser.incr_input_error();
parser.error_msg("Expected string value for rate_name.",
CParser::OT_CONTINUE);
}
else
{
this->rate_name = str;
}
rate_name_defined = true;
break;
case 1: // tol
if (!(parser.get_iss() >> this->tol))
{
this->tol = 0;
parser.incr_input_error();
parser.error_msg("Expected numeric value for tol.",
CParser::OT_CONTINUE);
}
tol_defined = true;
break;
case 2: // m
if (!(parser.get_iss() >> this->m))
{
this->m = 0;
parser.incr_input_error();
parser.error_msg("Expected numeric value for m.",
CParser::OT_CONTINUE);
}
m_defined = true;
break;
case 3: // m0
if (!(parser.get_iss() >> this->m0))
{
this->m0 = 0;
parser.incr_input_error();
parser.error_msg("Expected numeric value for m0.",
CParser::OT_CONTINUE);
}
m0_defined = true;
break;
case 4: // moles
if (!(parser.get_iss() >> this->moles))
{
this->moles = 0;
parser.incr_input_error();
parser.error_msg("Expected numeric value for moles.",
CParser::OT_CONTINUE);
}
moles_defined = true;
break;
case 5: // namecoef
if (this->namecoef.read_raw(P_INSTANCE_COMMA parser, next_char) !=
CParser::PARSER_OK)
{
parser.incr_input_error();
parser.
error_msg
("Expected element name and molality for namecoef.",
CParser::OT_CONTINUE);
}
opt_save = 5;
break;
case 6: // d_params
while (parser.copy_token(token, next_char) == CParser::TT_DIGIT)
{
sscanf(token.c_str(), "%lf", &d);
temp_d_params.push_back(d);
d_params_defined = true;
}
opt_save = 6;
}
if (opt == CParser::OPT_EOF || opt == CParser::OPT_KEYWORD)
break;
}
if (d_params_defined)
{
this->d_params = temp_d_params;
}
// members that must be defined
if (rate_name_defined == false)
{
parser.incr_input_error();
parser.error_msg("Rate_name not defined for KineticsComp input.",
CParser::OT_CONTINUE);
}
if (tol_defined == false)
{
parser.incr_input_error();
parser.error_msg("Tol not defined for KineticsComp input.",
CParser::OT_CONTINUE);
}
if (m_defined == false)
{
parser.incr_input_error();
parser.error_msg("M not defined for KineticsComp input.",
CParser::OT_CONTINUE);
}
if (m0_defined == false)
{
parser.incr_input_error();
parser.error_msg("M0 not defined for KineticsComp input.",
CParser::OT_CONTINUE);
}
if (moles_defined == false)
{
parser.incr_input_error();
parser.error_msg("Moles not defined for KineticsComp input.",
CParser::OT_CONTINUE);
}
}
#ifdef USE_MPI
void
cxxKineticsComp::mpi_pack(std::vector < int >&ints,
std::vector < double >&doubles)
{
extern cxxDictionary dictionary;
ints.push_back(dictionary.string2int(this->rate_name));
this->namecoef.mpi_pack(ints, doubles);
doubles.push_back(this->tol);
doubles.push_back(this->m);
doubles.push_back(this->m0);
doubles.push_back(this->moles);
ints.push_back((int) this->d_params.size());
for (std::vector < double >::iterator it = this->d_params.begin();
it != this->d_params.end(); it++)
{
doubles.push_back(*it);
}
}
void
cxxKineticsComp::mpi_unpack(int *ints, int *ii, double *doubles, int *dd)
{
extern cxxDictionary dictionary;
int i = *ii;
int d = *dd;
this->rate_name = dictionary.int2stdstring(ints[i++]);
this->namecoef.mpi_unpack(ints, &i, doubles, &d);
this->tol = doubles[d++];
this->m = doubles[d++];
this->m0 = doubles[d++];
this->moles = doubles[d++];
int n = ints[i++];
this->d_params.clear();
for (int j = 0; j < n; j++)
{
this->d_params.push_back(doubles[d++]);
}
*ii = i;
*dd = d;
}
#endif
void
cxxKineticsComp::add(const cxxKineticsComp & addee, double extensive)
{
if (extensive == 0.0)
return;
if (addee.rate_name.size() == 0)
return;
// this and addee must have same name
// otherwise generate a new KineticsComp with multiply
if (this->rate_name.size() == 0 && addee.rate_name.size() == 0)
{
return;
}
//char * rate_name;
assert(this->rate_name == addee.rate_name);
//cxxNameDouble namecoef;
//double tol;
//double m;
this->m += addee.m * extensive;
//double m0;
this->m0 += addee.m0 * extensive;
//double moles;
this->moles += addee.moles * extensive;
//std::vector<double> d_params;
}
void
cxxKineticsComp::multiply(double extensive)
{
//char * rate_name;
//cxxNameDouble namecoef;
//double tol;
//double m;
this->m *= extensive;
//double m0;
this->m0 *= extensive;
//double moles;
this->moles *= extensive;
//std::vector<double> d_params;
}