mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-15 16:18:22 +01:00
d6a74675 Merge commit '4e80a54467a084df3b666c7d6fc56a4798fd3301' 4e80a544 Squashed 'phreeqcpp/' changes from 7c7fafd..c876219 0209fdf9 Merge commit 'b537589773f4819fe97ff8e5322bcd38c54b63f7' b5375897 Squashed 'phreeqcpp/' changes from e317dd0..7c7fafd git-subtree-dir: src git-subtree-split: d6a74675d73985977ceac1601b57463c1ee8c331
1340 lines
32 KiB
C++
1340 lines
32 KiB
C++
#include "Utils.h"
|
|
#include "Phreeqc.h"
|
|
#include "phqalloc.h"
|
|
#include "NameDouble.h"
|
|
#include "Exchange.h"
|
|
#include "Solution.h"
|
|
#include <time.h>
|
|
|
|
#if defined(PHREEQCI_GUI)
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
double Phreeqc::
|
|
calc_alk(CReaction& rxn_ref)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
LDBLE return_value;
|
|
class master* master_ptr;
|
|
|
|
return_value = 0.0;
|
|
class rxn_token* r_token = &rxn_ref.token[1];
|
|
while (r_token->s != NULL)
|
|
{
|
|
master_ptr = r_token->s->secondary;
|
|
if (master_ptr == NULL)
|
|
{
|
|
master_ptr = r_token->s->primary;
|
|
}
|
|
if (master_ptr == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"Non-master species in secondary reaction, %s.",
|
|
rxn_ref.token[0].s->name);
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
break;
|
|
}
|
|
return_value += r_token->coef * master_ptr->alk;
|
|
//if (strcmp(r_token->name, "e-") == 0 && strcmp(rxn_ref.token[0].name,"e-") != 0)
|
|
//{
|
|
// std::cerr << rxn_ref.token[0].name << " Non-master species has e- in reaction.\n";
|
|
//}
|
|
r_token++;
|
|
}
|
|
return (return_value);
|
|
}/* ---------------------------------------------------------------------- */
|
|
double Phreeqc::
|
|
calc_delta_v(CReaction& r_ref, bool phase)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/* calculate delta_v from molar volumes */
|
|
double d_v = 0.0;
|
|
if (phase)
|
|
{
|
|
/* for phases: reactants have coef's < 0, products have coef's > 0, v.v. for species */
|
|
for (size_t i = 1; r_ref.Get_tokens()[i].s; i++)
|
|
{
|
|
if (!r_ref.Get_tokens()[i].s)
|
|
continue;
|
|
d_v += r_ref.Get_tokens()[i].coef * r_ref.Get_tokens()[i].s->logk[vm_tc];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; r_ref.token[i].name /*|| r_ptr->token[i].s*/; i++)
|
|
{
|
|
if (!r_ref.Get_tokens()[i].s)
|
|
continue;
|
|
d_v -= r_ref.Get_tokens()[i].coef * r_ref.Get_tokens()[i].s->logk[vm_tc];
|
|
}
|
|
}
|
|
return d_v;
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
calc_dielectrics(LDBLE tc, LDBLE pa)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/* Relative dielectric constant of pure water, eps as a function of (P, T)
|
|
Bradley and Pitzer, 1979, JPC 83, 1599.
|
|
(newer data in Fernandez et al., 1995, JPCRD 24, 33,
|
|
and Fernandez et al., 1997, JPCRD 26, 1125, show its correctness)
|
|
+ d(eps)/d(P), Debye-Hueckel A and B, and Av (for Av, see Pitzer et al., 1984, JPCRD 13, p. 4)
|
|
*/
|
|
if (llnl_temp.size() > 0) return OK;
|
|
if (tc > 350.)
|
|
{
|
|
tc = 350.;
|
|
}
|
|
LDBLE T = tc + 273.15;
|
|
LDBLE u1 = 3.4279e2, u2 = -5.0866e-3, u3 = 9.469e-7, u4 = -2.0525,
|
|
u5 = 3.1159e3, u6 = -1.8289e2, u7 = -8.0325e3, u8 = 4.2142e6,
|
|
u9 = 2.1417;
|
|
LDBLE d1000 = u1 * exp(T * (u2 + T * u3)); // relative dielectric constant at 1000 bar
|
|
LDBLE c = u4 + u5 / (u6 + T);
|
|
LDBLE b = u7 + u8 / T + u9 * T;
|
|
LDBLE pb = pa * 1.01325; // pa in bar
|
|
eps_r = d1000 + c * log((b + pb) / (b + 1e3)); // relative dielectric constant
|
|
if (eps_r <= 0)
|
|
{
|
|
eps_r = 10.;
|
|
warning_msg("Relative dielectric constant is negative.\nTemperature is out of range of parameterization.");
|
|
}
|
|
|
|
/* qe^2 / (eps_r * kB * T) = 4.803204e-10**2 / 1.38065e-16 / (eps_r * T)
|
|
= 1.671008e-3 (esu^2 / (erg/K)) / (eps_r * T) */
|
|
LDBLE e2_DkT = 1.671008e-3 / (eps_r * T);
|
|
|
|
DH_B = sqrt(8 * pi * AVOGADRO * e2_DkT * rho_0 / 1e3); // Debye length parameter, 1/cm(mol/kg)^-0.5
|
|
|
|
DH_A = DH_B * e2_DkT / (2. * LOG_10); //(mol/kg)^-0.5
|
|
|
|
/* A0 in pitzer */
|
|
if (pitzer_model || sit_model)
|
|
{
|
|
A0 = DH_B * e2_DkT / 6.0;
|
|
if (pitzer_model && aphi != NULL)
|
|
{
|
|
calc_pitz_param(aphi, T, 298.15);
|
|
A0 = aphi->p;
|
|
}
|
|
}
|
|
|
|
/* Debye-Hueckel limiting slope = DH_B * e2_DkT * RT * (d(ln(eps_r)) / d(P) - compressibility) */
|
|
DH_Av = DH_B * e2_DkT * R_LITER_ATM * 1e3 * T * (c / (b + pb) * 1.01325 / eps_r - kappa_0 / 3.); // (cm3/mol)(mol/kg)^-0.5
|
|
|
|
DH_B /= 1e8; // kappa, 1/Angstrom(mol/kg)^-0.5
|
|
|
|
/* the Born functions, * 41.84 to give molal volumes in cm3/mol... */
|
|
ZBrn = (-1 / eps_r + 1.0) * 41.84004;
|
|
QBrn = c / (b + pb) / eps_r / eps_r * 41.84004;
|
|
/* dgdP from subroutine gShok2 in supcrt92, g is neglected here (at tc < 300)...
|
|
and, dgdP is small. Better, adapt Wref to experimental Vm's */
|
|
dgdP = 0;
|
|
//if (tc > 150 && rho_0 < 1.0)
|
|
//{
|
|
// LDBLE sc[7] = {1, -0.2037662e+01, 0.5747000e-02, -0.6557892e-05,
|
|
// 0.6107361e+01, -0.1074377e-01, 0.1268348e-04};
|
|
// LDBLE csc[4] = {1, 0.3666666e+02, -0.1504956e-9, 0.5017997e-13};
|
|
// LDBLE sa = sc[1] + tc * (sc[2] + tc * sc[3]);
|
|
// LDBLE sb = sc[4] + tc * (sc[5] + tc * sc[6]);
|
|
|
|
// dgdP = - sa * sb * pow(1.0 - rho_0, sb - 1.0) * rho_0 * kappa_0 / 1.01325;
|
|
|
|
// LDBLE ft = pow((tc - 155.0)/300.0, 4.8) + csc[1] * pow((tc - 155.0)/300.0, 16.0);
|
|
// LDBLE dfdP = ft * (-3.0 * csc[2] * pow(1000.0 - pb, 2) - 4.0 * csc[3] * pow(1000.0 - pb, 3));
|
|
// dgdP -= dfdP;
|
|
//}
|
|
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
calc_rho_0(LDBLE tc, LDBLE pa)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/* Density of pure water
|
|
Wagner and Pruss, 2002, JPCRD 31, 387, eqn. 2.6, along the saturation pressure line +
|
|
interpolation 0 - 300 oC, 0.006 - 1000 atm...
|
|
*/
|
|
if (llnl_temp.size() > 0) return OK;
|
|
if (tc > 350.)
|
|
{
|
|
if (need_temp_msg < 1)
|
|
{
|
|
std::ostringstream w_msg;
|
|
w_msg << "Fitting range for dielectric constant of pure water is 0-350 C.\n";
|
|
w_msg << "Fitting range for density along the saturation pressure line is 0-374 C,\n";
|
|
w_msg << " for higher pressures up to 1000 atm 0-300 C.\n";
|
|
w_msg << "Using temperature of 350 C for dielectric and density calculation.";
|
|
warning_msg(w_msg.str().c_str());
|
|
need_temp_msg++;
|
|
}
|
|
tc = 350.;
|
|
}
|
|
LDBLE T = tc + 273.15;
|
|
//eqn. 2.6...
|
|
LDBLE Tc = 647.096, th = 1 - T / Tc;
|
|
LDBLE b1 = 1.99274064, b2 = 1.09965342, b3 = -0.510839303,
|
|
b4 = -1.75493479, b5 = -45.5170352, b6 = -6.7469445e5;
|
|
rho_0_sat = 322.0 * (1.0 + b1 * pow(th, (LDBLE) 1./3.) + b2 * pow(th, (LDBLE) 2./3.) + b3 * pow(th, (LDBLE) 5./3.) +\
|
|
b4 * pow(th, (LDBLE) 16./3.) + b5 * pow(th, (LDBLE) 43./3.) + b6 * pow(th, (LDBLE) 110./3));
|
|
//pressure...
|
|
LDBLE p0 = 5.1880000E-02 + tc * (-4.1885519E-04 + tc * ( 6.6780748E-06 + tc * (-3.6648699E-08 + tc * 8.3501912E-11)));
|
|
LDBLE p1 = -6.0251348E-06 + tc * ( 3.6696407E-07 + tc * (-9.2056269E-09 + tc * ( 6.7024182E-11 + tc * -1.5947241E-13)));
|
|
LDBLE p2 = -2.2983596E-09 + tc * (-4.0133819E-10 + tc * ( 1.2619821E-11 + tc * (-9.8952363E-14 + tc * 2.3363281E-16)));
|
|
LDBLE p3 = 7.0517647E-11 + tc * ( 6.8566831E-12 + tc * (-2.2829750E-13 + tc * ( 1.8113313E-15 + tc * -4.2475324E-18)));
|
|
/* The minimal pressure equals the saturation pressure... */
|
|
if (ah2o_x <= 1.0)
|
|
p_sat = exp(11.6702 - 3816.44 / (T - 46.13)) * ah2o_x;
|
|
else
|
|
p_sat = exp(11.6702 - 3816.44 / (T - 46.13));
|
|
//ah2o_x0 = ah2o_x; // for updating rho in model(): compare with new ah2o_x
|
|
if (pa < p_sat || (use.Get_solution_ptr() && use.Get_solution_ptr()->Get_patm() < p_sat))
|
|
{
|
|
pa = p_sat;
|
|
}
|
|
if (!use.Get_gas_phase_in())
|
|
patm_x = pa;
|
|
pa -= (p_sat - 1e-6);
|
|
rho_0 = rho_0_sat + pa * (p0 + pa * (p1 + pa * (p2 + sqrt(pa) * p3)));
|
|
if (rho_0 < 0.01)
|
|
rho_0 = 0.01;
|
|
|
|
/* compressibility, d(ln(rho)) / d(P), 1/atm... */
|
|
kappa_0 = (p0 + pa * (2 * p1 + pa * (3 * p2 + sqrt(pa) * 3.5 * p3))) / rho_0;
|
|
|
|
return (rho_0 / 1e3);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
compute_gfw(const char *string, LDBLE * gfw)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Input: string contains a chemical formula
|
|
* Output: gfw contains the calculated gfw
|
|
*/
|
|
std::string str(string);
|
|
std::map<std::string, double>::iterator it;
|
|
it = gfw_map.find(str);
|
|
if (it != gfw_map.end())
|
|
{
|
|
*gfw = it->second;
|
|
return OK;
|
|
}
|
|
|
|
int i;
|
|
char token[MAX_LENGTH];
|
|
const char* cptr;
|
|
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
Utilities::strcpy_safe(token, MAX_LENGTH, string);
|
|
cptr = token;
|
|
if (get_elts_in_species(&cptr, 1.0) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
*gfw = 0.0;
|
|
for (i = 0; i < count_elts; i++)
|
|
{
|
|
if (elt_list[i].elt->gfw <= 0.0)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
*gfw += elt_list[i].coef * (elt_list[i].elt)->gfw;
|
|
}
|
|
gfw_map[str] = *gfw;
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
copy_token(char *token_ptr, const char **cptr, int *length)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Copies from **cptr to *token_ptr until first space is encountered.
|
|
*
|
|
* Arguments:
|
|
* *token_ptr output, place to store token
|
|
*
|
|
* **cptr input, character string to read token from
|
|
* output, next position after token
|
|
*
|
|
* length output, length of token
|
|
*
|
|
* Returns:
|
|
* UPPER,
|
|
* LOWER,
|
|
* DIGIT,
|
|
* EMPTY,
|
|
* UNKNOWN.
|
|
*/
|
|
int i, return_value;
|
|
char c;
|
|
|
|
/*
|
|
* Read to end of whitespace
|
|
*/
|
|
while (isspace((int) (c = **cptr)))
|
|
(*cptr)++;
|
|
/*
|
|
* Check what we have
|
|
*/
|
|
if (isupper((int) c) || c == '[')
|
|
{
|
|
return_value = UPPER;
|
|
}
|
|
else if (islower((int) c))
|
|
{
|
|
return_value = LOWER;
|
|
}
|
|
else if (isdigit((int) c) || c == '.' || c == '-')
|
|
{
|
|
return_value = DIGIT;
|
|
}
|
|
else if (c == '\0')
|
|
{
|
|
return_value = EMPTY;
|
|
}
|
|
else
|
|
{
|
|
return_value = UNKNOWN;
|
|
}
|
|
/*
|
|
* Begin copying to token
|
|
*/
|
|
i = 0;
|
|
while ((!isspace((int) (c = **cptr))) &&
|
|
/* c != ',' && */
|
|
c != ';' && c != '\0')
|
|
{
|
|
token_ptr[i] = c;
|
|
(*cptr)++;
|
|
i++;
|
|
}
|
|
token_ptr[i] = '\0';
|
|
*length = i;
|
|
return (return_value);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
copy_token(std::string &token, const char **cptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Copies from **cptr to *token until first space is encountered.
|
|
*
|
|
* Arguments:
|
|
* &token_ptr output, place to store token
|
|
*
|
|
* **cptr input, character string to read token from
|
|
* output, next position after token
|
|
*
|
|
* Returns:
|
|
* UPPER,
|
|
* LOWER,
|
|
* DIGIT,
|
|
* EMPTY,
|
|
* UNKNOWN.
|
|
*/
|
|
int return_value;
|
|
char c;
|
|
|
|
/*
|
|
* Read to end of whitespace
|
|
*/
|
|
token.clear();
|
|
while (isspace((int) (c = **cptr)))
|
|
(*cptr)++;
|
|
/*
|
|
* Check what we have
|
|
*/
|
|
if (isupper((int) c) || c == '[')
|
|
{
|
|
return_value = UPPER;
|
|
}
|
|
else if (islower((int) c))
|
|
{
|
|
return_value = LOWER;
|
|
}
|
|
else if (isdigit((int) c) || c == '.' || c == '-')
|
|
{
|
|
return_value = DIGIT;
|
|
}
|
|
else if (c == '\0')
|
|
{
|
|
return_value = EMPTY;
|
|
}
|
|
else
|
|
{
|
|
return_value = UNKNOWN;
|
|
}
|
|
/*
|
|
* Begin copying to token
|
|
*/
|
|
char c_char[2];
|
|
c_char[1] = '\0';
|
|
while ((!isspace((int) (c = **cptr))) &&
|
|
/* c != ',' && */
|
|
c != ';' && c != '\0')
|
|
{
|
|
c_char[0] = c;
|
|
token.append(c_char);
|
|
(*cptr)++;
|
|
}
|
|
return (return_value);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
dup_print(const char* cptr, int emphasis)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* print character string to output and logfile
|
|
* if emphasis == TRUE the print is set off by
|
|
* a row of dashes before and after the character string.
|
|
*
|
|
*/
|
|
int l;
|
|
|
|
if (pr.headings == FALSE)
|
|
return (OK);
|
|
std::string save_in(cptr);
|
|
l = (int) strlen(cptr);
|
|
if (emphasis == TRUE)
|
|
{
|
|
std::string dash;
|
|
dash.resize(l, '-');
|
|
output_msg(sformatf("%s\n%s\n%s\n\n", dash.c_str(), save_in.c_str(), dash.c_str()));
|
|
log_msg(sformatf("%s\n%s\n%s\n\n", dash.c_str(), save_in.c_str(), dash.c_str()));
|
|
}
|
|
else
|
|
{
|
|
output_msg(sformatf("%s\n\n", save_in.c_str()));
|
|
log_msg(sformatf("%s\n\n", save_in.c_str()));
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
equal(LDBLE a, LDBLE b, LDBLE eps)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Checks equality between two LDBLE precision numbers
|
|
*/
|
|
if (fabs(a - b) <= eps)
|
|
return (TRUE);
|
|
return (FALSE);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
void * Phreeqc::
|
|
free_check_null(void *ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
if (ptr != NULL)
|
|
{
|
|
PHRQ_free(ptr);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_token(const char** eqnaddr, std::string& string, LDBLE* l_z, int* l)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function finds next species in equation, coefficient has already
|
|
* been removed. Also determines charge on the species.
|
|
*
|
|
* Arguments:
|
|
* *eqnaddr input, pointer to position in eqn to start parsing
|
|
* output, pointer to a pointer to next position in eqn to start
|
|
* parsing.
|
|
* *string input pointer to place to store token
|
|
* *l_z charge on token
|
|
* *l length of token
|
|
*
|
|
* Returns:
|
|
* ERROR,
|
|
* OK.
|
|
*/
|
|
{
|
|
int i, j;
|
|
int ltoken, lcharge;
|
|
char c;
|
|
const char* cptr, * ptr1, * rest;
|
|
char charge[MAX_LENGTH];
|
|
|
|
string.clear();
|
|
rest = *eqnaddr;
|
|
cptr = *eqnaddr;
|
|
i = 0;
|
|
/*
|
|
* Find end of token or beginning of charge
|
|
*/
|
|
while (((c = *cptr) != '+') && (c != '-') && (c != '=') && (c != '\0'))
|
|
{
|
|
string.push_back(c);
|
|
i++;
|
|
if (c == '[')
|
|
{
|
|
cptr++;
|
|
while ((c = *cptr) != ']')
|
|
{
|
|
if (c == '\0')
|
|
{
|
|
error_string = sformatf(
|
|
"No final bracket \"]\" for element name, %s.",
|
|
string.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
string.push_back(c);
|
|
i++;
|
|
cptr++;
|
|
}
|
|
string.push_back(c);
|
|
i++;
|
|
}
|
|
|
|
cptr++;
|
|
}
|
|
ltoken = i;
|
|
/*
|
|
* Check for an empty string
|
|
*/
|
|
if (i == 0)
|
|
{
|
|
error_string = sformatf("NULL string detected in get_token, %s.", rest);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* End of token is = or \0, charge is zero
|
|
*/
|
|
if (c == '=' || c == '\0')
|
|
{
|
|
*eqnaddr = cptr;
|
|
lcharge = 0;
|
|
*l_z = 0.0;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Copy characters into charge until next species or end is detected
|
|
*/
|
|
j = 0;
|
|
ptr1 = cptr;
|
|
while ((isalpha((int)(c = *ptr1)) == FALSE) &&
|
|
(c != '(') &&
|
|
(c != ')') &&
|
|
(c != ']') && (c != '[') && (c != '=') && (c != '\0'))
|
|
{
|
|
charge[j++] = c;
|
|
/* error if no more space */
|
|
if (j >= MAX_LENGTH)
|
|
{
|
|
error_msg("The charge on a species has exceeded MAX_LENGTH characters.",
|
|
CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
ptr1++;
|
|
}
|
|
/*
|
|
* Go back to last + or - if not end of side,
|
|
* everything before the last + or - in charge is part of the charge
|
|
*/
|
|
if ((c != '=') && (c != '\0'))
|
|
{
|
|
while (((c = *ptr1) != '+') && (c != '-'))
|
|
{
|
|
j--;
|
|
ptr1--;
|
|
}
|
|
}
|
|
charge[j] = '\0';
|
|
lcharge = j;
|
|
*eqnaddr = ptr1;
|
|
/*
|
|
* Charge has been written, now need to check if charge has legal format
|
|
*/
|
|
if (get_charge(charge, MAX_LENGTH, l_z) == OK)
|
|
{
|
|
string.append(charge);
|
|
}
|
|
else
|
|
{
|
|
return (ERROR);
|
|
}
|
|
}
|
|
*l = ltoken + lcharge;
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
isamong(char c, const char *s_l)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function checks if c is among the characters in the string s
|
|
*
|
|
* Arguments:
|
|
* c input, character to check
|
|
* *s string of characters
|
|
*
|
|
* Returns:
|
|
* TRUE if c is in set,
|
|
* FALSE if c in not in set.
|
|
*/
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; s_l[i] != '\0'; i++)
|
|
{
|
|
if (c == s_l[i])
|
|
{
|
|
return (TRUE);
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
islegit(const char c)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function checks for legal characters for chemical equations
|
|
*
|
|
* Argument:
|
|
* c input, character to check
|
|
*
|
|
* Returns:
|
|
* TRUE if c is in set,
|
|
* FALSE if c in not in set.
|
|
*/
|
|
{
|
|
if (isalpha((int) c) || isdigit((int) c) || isamong(c, "+-=().:_[]"))
|
|
{
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
malloc_error(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
error_msg("NULL pointer returned from malloc or realloc.", CONTINUE);
|
|
error_msg("Program terminating.", STOP);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
print_centered(const char *string)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, l, l1, l2;
|
|
char token[MAX_LENGTH];
|
|
|
|
l = (int) strlen(string);
|
|
l1 = (79 - l) / 2;
|
|
l2 = 79 - l - l1;
|
|
for (i = 0; i < l1; i++)
|
|
token[i] = '-';
|
|
token[i] = '\0';
|
|
Utilities::strcat_safe(token, MAX_LENGTH, string);
|
|
for (i = 0; i < l2; i++)
|
|
token[i + l1 + l] = '-';
|
|
token[79] = '\0';
|
|
output_msg(sformatf("%s\n\n", token));
|
|
return (OK);
|
|
}
|
|
bool Phreeqc::
|
|
replace(const char *str1, const char *str2, std::string & str)
|
|
{
|
|
size_t pos = str.find(str1);
|
|
if (pos != std::string::npos)
|
|
{
|
|
size_t l = strlen(str1);
|
|
str.replace(pos, l, str2);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
replace(const char *str1, const char *str2, char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Function replaces str1 with str2 in str
|
|
*
|
|
* Arguments:
|
|
* str1 search str for str1
|
|
* str2 replace str1 if str1 found in str
|
|
* str string to be searched
|
|
*
|
|
* Returns
|
|
* TRUE if string was replaced
|
|
* FALSE if string was not replaced
|
|
*/
|
|
int l, l1, l2;
|
|
char* ptr_start;
|
|
|
|
ptr_start = strstr(str, str1);
|
|
/*
|
|
* Str1 not found, return
|
|
*/
|
|
if (ptr_start == NULL)
|
|
return (FALSE);
|
|
/*
|
|
* Str1 found, replace Str1 with Str2
|
|
*/
|
|
l = (int) strlen(str);
|
|
l1 = (int) strlen(str1);
|
|
l2 = (int) strlen(str2);
|
|
/*
|
|
* Make gap in str long enough for str2
|
|
*/
|
|
/* The plus one includes the terminating NULL */
|
|
memmove(ptr_start + l2, ptr_start + l1, l - (ptr_start - str + l1) + 1);
|
|
/*
|
|
* Copy str2 into str
|
|
*/
|
|
memcpy(ptr_start, str2, l2);
|
|
return (TRUE);
|
|
}
|
|
void Phreeqc::
|
|
replace(std::string &stds, const char* str1, const char* str2)
|
|
{
|
|
size_t pos, l;
|
|
l = strlen(str1);
|
|
while ((pos = stds.find(str1)) != std::string::npos) {
|
|
stds.replace(pos, l, str2);
|
|
}
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
space(void **ptr, int i, int *max, int struct_size)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Routine has 4 functions, allocate space, reallocate space, test to
|
|
* determine whether space is available, and free space.
|
|
*
|
|
* Arguments:
|
|
* ptr pointer to malloced space
|
|
* i value for test
|
|
* i = INIT, allocates space
|
|
* i >= 0 && i < max, space is available, return
|
|
* i >= max, reallocate space
|
|
* i = FREE, free space.
|
|
* max maximum value for i with available space
|
|
* struct size size of structure to be allocated
|
|
*/
|
|
/*
|
|
* Return if space exists
|
|
*/
|
|
if ((i >= 0) && (i + 1 < *max))
|
|
{
|
|
return;
|
|
}
|
|
/*
|
|
* Realloc space
|
|
*/
|
|
if (i + 1 >= *max)
|
|
{
|
|
if (*max > 1000)
|
|
{
|
|
*max += 1000;
|
|
}
|
|
else
|
|
{
|
|
*max *= 2;
|
|
}
|
|
if (i + 1 > *max)
|
|
*max = i + 1;
|
|
*ptr = PHRQ_realloc(*ptr, (size_t) (*max) * struct_size);
|
|
if (*ptr == NULL)
|
|
malloc_error();
|
|
return;
|
|
}
|
|
/*
|
|
* Allocate space
|
|
*/
|
|
if (i == INIT)
|
|
{
|
|
/* free(*ptr); */
|
|
*ptr = PHRQ_malloc((size_t) (*max) * struct_size);
|
|
if (*ptr == NULL)
|
|
malloc_error();
|
|
return;
|
|
}
|
|
/*
|
|
* Free space
|
|
*/
|
|
/*
|
|
if ( i == FREE ) {
|
|
free(*ptr);
|
|
return;
|
|
}
|
|
*/
|
|
/*
|
|
* Error
|
|
*/
|
|
error_msg("Illegal argument to function space.", CONTINUE);
|
|
error_msg("Program terminating.", STOP);
|
|
return;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
squeeze_white(char *s_l)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Delete all white space from string s
|
|
*
|
|
* Argument:
|
|
* *s_l input, character string, possibly containing white space
|
|
* output, character string with all white space removed
|
|
*
|
|
* Return: void
|
|
*/
|
|
{
|
|
int i, j;
|
|
|
|
for (i = j = 0; s_l[i] != '\0'; i++)
|
|
{
|
|
if (!isspace((int) s_l[i]))
|
|
s_l[j++] = s_l[i];
|
|
}
|
|
s_l[j] = '\0';
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
str_tolower(char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Replaces string, str, with same string, lower case
|
|
*/
|
|
char* ptr;
|
|
ptr = str;
|
|
while (*ptr != '\0')
|
|
{
|
|
*ptr = (char) tolower(*ptr);
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
str_toupper(char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Replaces string, str, with same string, lower case
|
|
*/
|
|
char* ptr;
|
|
ptr = str;
|
|
while (*ptr != '\0')
|
|
{
|
|
*ptr = (char) toupper(*ptr);
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
strcmp_nocase(const char *str1, const char *str2)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Compare two strings disregarding case
|
|
*/
|
|
int c1, c2;
|
|
while ((c1 = tolower(*str1++)) == (c2 = tolower(*str2++)))
|
|
{
|
|
if (c1 == '\0')
|
|
return (0);
|
|
}
|
|
if (c1 < c2)
|
|
return (-1);
|
|
return (1);
|
|
}
|
|
void Phreeqc::str_tolower(std::string &name)
|
|
{
|
|
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
strcmp_nocase_arg1(const char *str1, const char *str2)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Compare two strings disregarding case
|
|
*/
|
|
int c1, c2;
|
|
while ((c1 = tolower(*str1++)) == (c2 = *str2++))
|
|
{
|
|
if (c1 == '\0')
|
|
return (0);
|
|
}
|
|
if (c1 < c2)
|
|
return (-1);
|
|
return (1);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
char * Phreeqc::
|
|
#if !defined(NDEBUG) && defined(WIN32_MEMORY_DEBUG)
|
|
_string_duplicate(const char *token, const char *szFileName, int nLine)
|
|
#else
|
|
string_duplicate(const char *token)
|
|
#endif
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int l;
|
|
char *str;
|
|
|
|
if (token == NULL)
|
|
return NULL;
|
|
l = (int) strlen(token);
|
|
#if !defined(NDEBUG) && defined(WIN32_MEMORY_DEBUG)
|
|
str = (char *) _malloc_dbg((size_t) (l + 1) * sizeof(char), _NORMAL_BLOCK, szFileName, nLine);
|
|
#else
|
|
str = (char *) PHRQ_malloc(((size_t)l + 1) * sizeof(char));
|
|
#endif
|
|
|
|
if (str == NULL)
|
|
malloc_error();
|
|
strcpy(str, token);
|
|
return (str);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
const char * Phreeqc::
|
|
string_hsave(const char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Save character string str
|
|
*
|
|
* Arguments:
|
|
* str input string to save.
|
|
*
|
|
* Returns:
|
|
* starting address of saved string (str)
|
|
*/
|
|
if (str == NULL) return (NULL);
|
|
std::map<std::string, std::string *>::const_iterator it;
|
|
it = strings_map.find(str);
|
|
if (it != strings_map.end())
|
|
{
|
|
return (it->second->c_str());
|
|
}
|
|
|
|
std::string *stdstr = new std::string(str);
|
|
strings_map[*stdstr] = stdstr;
|
|
return(stdstr->c_str());
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
void Phreeqc::
|
|
strings_map_clear()
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Save character string str
|
|
*
|
|
* Arguments:
|
|
* str input string to save.
|
|
*
|
|
* Returns:
|
|
* starting address of saved string (str)
|
|
*/
|
|
std::map<std::string, std::string *>::iterator it;
|
|
for (it = strings_map.begin(); it != strings_map.end(); it++)
|
|
{
|
|
delete it->second;
|
|
}
|
|
strings_map.clear();
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
under(LDBLE xval)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Exponentiate a number, x, but censor large and small numbers
|
|
* log values less than MIN_LM are set to 0
|
|
* log values greater than MAX_LM are set to 10**MAX_LM
|
|
*/
|
|
/* if (xval < MIN_LM) { */
|
|
if (xval < -40.)
|
|
{
|
|
return (0.0);
|
|
}
|
|
if (xval > MAX_LM)
|
|
{
|
|
return ( MAX_M );
|
|
}
|
|
return (pow ((LDBLE) 10.0, xval));
|
|
}
|
|
#ifndef PHREEQCI_GUI
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
status(int count, const char *str, bool rk_string)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
char sim_str[20];
|
|
char state_str[45];
|
|
char spin_str[2];
|
|
clock_t t2;
|
|
|
|
if (pr.status == FALSE || phast == TRUE)
|
|
return (OK);
|
|
|
|
if (state == INITIALIZE)
|
|
{
|
|
screen_string = sformatf("\n%-80s", "Initializing...");
|
|
screen_msg(screen_string.c_str());
|
|
status_on = true;
|
|
return (OK);
|
|
}
|
|
#ifdef NPP
|
|
t2 = clock();
|
|
if (((state < ADVECTION && reaction_step < count_total_steps) ||
|
|
(state == ADVECTION && (advection_step < count_ad_shifts || cell_no < count_cells)) ||
|
|
(state == TRANSPORT && (transport_step < count_shifts || (mixrun < nmix /*&&
|
|
cell_no < count_cells*/))))
|
|
&& (int) (1e3 / CLOCKS_PER_SEC * (t2 - status_timer)) < status_interval)
|
|
return (OK);
|
|
#endif
|
|
|
|
switch (state)
|
|
{
|
|
case INITIALIZE:
|
|
break;
|
|
case TRANSPORT:
|
|
if (str != NULL)
|
|
{
|
|
if (rk_string)
|
|
{
|
|
|
|
screen_string = screen_string.substr(0, 43);
|
|
screen_string.append(str);
|
|
status_string = screen_string;
|
|
}
|
|
else
|
|
{
|
|
screen_string = "\r";
|
|
screen_string.append(str);
|
|
status_string = screen_string;
|
|
}
|
|
status_on = true;
|
|
}
|
|
case PHAST:
|
|
break;
|
|
default:
|
|
// if str not NULL, print it
|
|
if (str != NULL && !rk_string)
|
|
{
|
|
screen_string = "\r";
|
|
screen_string.append(str);
|
|
status_string = screen_string;
|
|
}
|
|
else
|
|
// print state
|
|
{
|
|
std::string stdstr;
|
|
if (str != NULL && rk_string)
|
|
{
|
|
stdstr = str;
|
|
}
|
|
snprintf(sim_str, sizeof(sim_str), "\rSimulation %d.", simulation);
|
|
snprintf(state_str, sizeof(state_str), " ");
|
|
snprintf(spin_str, sizeof(spin_str), " ");
|
|
switch (state)
|
|
{
|
|
default:
|
|
break;
|
|
case INITIAL_SOLUTION:
|
|
snprintf(state_str, sizeof(state_str), "Initial solution %d.", use.Get_solution_ptr()->Get_n_user());
|
|
break;
|
|
case INITIAL_EXCHANGE:
|
|
snprintf(state_str, sizeof(state_str), "Initial exchange %d.", use.Get_exchange_ptr()->Get_n_user());
|
|
break;
|
|
case INITIAL_SURFACE:
|
|
snprintf(state_str, sizeof(state_str), "Initial surface %d.", use.Get_surface_ptr()->Get_n_user());
|
|
break;
|
|
case INVERSE:
|
|
snprintf(state_str, sizeof(state_str), "Inverse %d. Models = %d.", use.Get_inverse_ptr()->n_user, count);
|
|
break;
|
|
case REACTION:
|
|
if (use.Get_kinetics_in() == TRUE)
|
|
{
|
|
snprintf(state_str, sizeof(state_str), "Kinetic step %d.", reaction_step);
|
|
}
|
|
else
|
|
{
|
|
snprintf(state_str, sizeof(state_str), "Reaction step %d.", reaction_step);
|
|
}
|
|
break;
|
|
case ADVECTION:
|
|
snprintf(state_str, sizeof(state_str), "Advection, shift %d.", advection_step);
|
|
break;
|
|
}
|
|
spinner++;
|
|
if (spinner == 1)
|
|
{
|
|
spin_str[0] = '/';
|
|
}
|
|
else if (spinner == 2)
|
|
{
|
|
spin_str[0] = '-';
|
|
}
|
|
else
|
|
{
|
|
spin_str[0] = '\\';
|
|
spinner = 0;
|
|
}
|
|
if (use.Get_kinetics_in() == TRUE)
|
|
{
|
|
screen_string = sformatf("%-15s%-27s%38s", sim_str, state_str, stdstr.c_str());
|
|
status_string = screen_string;
|
|
}
|
|
else
|
|
{
|
|
screen_string = sformatf("%-15s%-27s%1s%45s", sim_str, state_str, spin_str, stdstr.c_str());
|
|
status_string = screen_string;
|
|
}
|
|
}
|
|
status_on = true;
|
|
break;
|
|
}
|
|
|
|
#ifndef NPP
|
|
t2 = clock();
|
|
if ((int) (1e3 / CLOCKS_PER_SEC * (t2 - status_timer)) > status_interval)
|
|
#endif
|
|
{
|
|
status_timer = t2;
|
|
screen_msg(status_string.c_str());
|
|
status_string.clear();
|
|
}
|
|
return (OK);
|
|
}
|
|
#endif /*PHREEQCI_GUI */
|
|
# include <assert.h>
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
string_trim(char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Function trims white space from left and right of string
|
|
*
|
|
* Arguments:
|
|
* str string to trime
|
|
*
|
|
* Returns
|
|
* TRUE if string was changed
|
|
* FALSE if string was not changed
|
|
* EMPTY if string is all whitespace
|
|
*/
|
|
int i, l, start, end, length;
|
|
char* ptr_start;
|
|
|
|
l = (int) strlen(str);
|
|
/*
|
|
* leading whitespace
|
|
*/
|
|
for (i = 0; i < l; i++)
|
|
{
|
|
if (isspace((int) str[i]))
|
|
continue;
|
|
break;
|
|
}
|
|
if (i == l)
|
|
return (EMPTY);
|
|
start = i;
|
|
ptr_start = &(str[i]);
|
|
/*
|
|
* trailing whitespace
|
|
*/
|
|
for (i = l - 1; i >= 0; i--)
|
|
{
|
|
if (isspace((int) str[i]))
|
|
continue;
|
|
break;
|
|
}
|
|
end = i;
|
|
if (start == 0 && end == l)
|
|
return (FALSE);
|
|
length = end - start + 1;
|
|
memmove((void *) str, (void *) ptr_start, (size_t) length);
|
|
str[length] = '\0';
|
|
|
|
return (TRUE);
|
|
}
|
|
void Phreeqc::string_trim_left(std::string& str)
|
|
{
|
|
const std::string& chars = "\t\n ";
|
|
str.erase(0, str.find_first_not_of(chars));
|
|
}
|
|
void Phreeqc::string_trim_right(std::string& str)
|
|
{
|
|
const std::string& chars = "\t\n ";
|
|
str.erase(str.find_last_not_of(chars) + 1);
|
|
}
|
|
void Phreeqc::string_trim(std::string& str)
|
|
{
|
|
const std::string& chars = "\t\n ";
|
|
str.erase(0, str.find_first_not_of(chars));
|
|
str.erase(str.find_last_not_of(chars) + 1);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
string_trim_right(char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Function trims white space from right of string
|
|
*
|
|
* Arguments:
|
|
* str string to trime
|
|
*
|
|
* Returns
|
|
* TRUE if string was changed
|
|
* FALSE if string was not changed
|
|
* EMPTY if string is all whitespace
|
|
*/
|
|
int i, l, end, length;
|
|
|
|
l = (int) strlen(str);
|
|
for (i = l - 1; i >= 0; i--)
|
|
{
|
|
if (isspace((int) str[i]))
|
|
continue;
|
|
break;
|
|
}
|
|
end = i;
|
|
length = end + 1;
|
|
str[length] = '\0';
|
|
if (end == 0)
|
|
return (EMPTY);
|
|
if (end == l)
|
|
return (FALSE);
|
|
return (TRUE);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
string_trim_left(char *str)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Function trims white space from left of string
|
|
*
|
|
* Arguments:
|
|
* str string to trime
|
|
*
|
|
* Returns
|
|
* TRUE if string was changed
|
|
* FALSE if string was not changed
|
|
* EMPTY if string is all whitespace
|
|
*/
|
|
int i, l, start, end, length;
|
|
char* ptr_start;
|
|
|
|
l = (int) strlen(str);
|
|
/*
|
|
* leading whitespace
|
|
*/
|
|
for (i = 0; i < l; i++)
|
|
{
|
|
if (isspace((int) str[i]))
|
|
continue;
|
|
break;
|
|
}
|
|
if (i == l)
|
|
return (EMPTY);
|
|
start = i;
|
|
ptr_start = &(str[i]);
|
|
end = l;
|
|
if (start == 0 && end == l)
|
|
return (FALSE);
|
|
length = end - start + 1;
|
|
memmove((void *) str, (void *) ptr_start, (size_t) length);
|
|
str[length] = '\0';
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
char * Phreeqc::
|
|
string_pad(const char *str, int i)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Function returns new string padded to width i
|
|
* or returns str if longer
|
|
* Arguments:
|
|
* str string to pad
|
|
*
|
|
* Returns
|
|
* new string of with i
|
|
*/
|
|
int j, l, max;
|
|
char *str_ptr;
|
|
|
|
l = (int) strlen(str);
|
|
max = l;
|
|
if (l < i)
|
|
max = i;
|
|
str_ptr = (char *) PHRQ_malloc((((size_t)max + 1) * sizeof(char)));
|
|
if (str_ptr == NULL)
|
|
malloc_error();
|
|
else
|
|
strcpy(str_ptr, str);
|
|
if (i > l)
|
|
{
|
|
for (j = l; j < i; j++)
|
|
{
|
|
str_ptr[j] = ' ';
|
|
}
|
|
str_ptr[i] = '\0';
|
|
}
|
|
return (str_ptr);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_input_errors()
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
if (input_error == 0)
|
|
{
|
|
return phrq_io->Get_io_error_count();
|
|
}
|
|
return input_error;
|
|
}
|