iphreeqc/phreeqcpp/read.cpp
Darth Vader 3e1c0d11a2 Squashed 'src/' changes from ce34aa5e..7bae85a3
7bae85a3 Merge commit '80bf22d292021bc23620baa144f0a685fa73a82f'
80bf22d2 Squashed 'phreeqcpp/' changes from b576c75..c369020
3fd5b896 59 compiler error on macos (#60)

git-subtree-dir: src
git-subtree-split: 7bae85a32f92ccc7ebb8e658fd4f4d16b20217c0
2024-11-19 01:18:43 +00:00

10246 lines
251 KiB
C++

#include <complex>
#include <assert.h>
#include <time.h>
#include "Utils.h"
#include "Phreeqc.h"
#include "phqalloc.h"
#include "Pressure.h"
#include "Temperature.h"
#include "Parser.h"
#include "cxxMix.h"
#include "Exchange.h"
#include "GasPhase.h"
#include "Reaction.h"
#include "PPassemblage.h"
#include "SSassemblage.h"
#include "cxxKinetics.h"
#include "Solution.h"
#include "SelectedOutput.h"
#include "UserPunch.h"
#if defined(PHREEQCI_GUI)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_input(void)
/* ---------------------------------------------------------------------- */
{
int i, j, l;
const char* cptr;
char token[2 * MAX_LENGTH];
#define LAST_C_KEYWORD 61
parse_error = 0;
input_error = 0;
next_keyword = Keywords::KEY_NONE;
count_warnings = 0;
Rxn_new_exchange.clear();
Rxn_new_gas_phase.clear();
Rxn_new_kinetics.clear(); // not used
Rxn_new_mix.clear(); // not used
Rxn_new_pp_assemblage.clear();
Rxn_new_pressure.clear(); // not used
Rxn_new_reaction.clear(); // not used
Rxn_new_solution.clear();
Rxn_new_ss_assemblage.clear();
Rxn_new_surface.clear();
Rxn_new_temperature.clear(); // not used
phrq_io->Set_echo_on(true);
/*
* Initialize keyword counters
*/
for (i = 0; i < Keywords::KEY_COUNT_KEYWORDS; i++)
{
keycount[i] = 0;
}
/*
* Initialize use and save pointers
*/
use.init();
save.solution = FALSE;
save.mix = FALSE;
save.reaction = FALSE;
save.kinetics = FALSE;
save.pp_assemblage = FALSE;
save.exchange = FALSE;
save.surface = FALSE;
save.gas_phase = FALSE;
save.ss_assemblage = FALSE;
title_x.clear();
while ((i = check_line("Subroutine Read", FALSE, TRUE, TRUE, TRUE)) != KEYWORD)
{
/* empty, eof, keyword, print */
if (i == EOF)
return (EOF);
error_string = sformatf(
"Unknown input, no keyword has been specified.");
warning_msg(error_string);
}
for (;;)
{
if (next_keyword > 0)
{
if (next_keyword != Keywords::KEY_DATABASE && !reading_database())
{
first_read_input = FALSE;
}
}
// mark keyword read
if (next_keyword > 0 && next_keyword < Keywords::KEY_COUNT_KEYWORDS)
{
keycount[next_keyword]++;
}
switch (next_keyword)
{
case Keywords::KEY_NONE: /* Have not read line with keyword */
error_string = sformatf( "Unknown input, no keyword has been specified.");
warning_msg(error_string);
while ((j = check_line("No keyword", FALSE, TRUE, TRUE, TRUE)) != KEYWORD && j != EOF)
{
warning_msg(error_string);
}
break;
case Keywords::KEY_END:
goto END_OF_SIMULATION_INPUT;
case Keywords::KEY_SOLUTION_SPECIES: /* Read aqueous model */
read_species();
break;
case Keywords::KEY_SOLUTION_MASTER_SPECIES: /* Read master species */
read_master_species();
break;
case Keywords::KEY_SOLUTION: /* Read solution data */
read_solution();
break;
case Keywords::KEY_PHASES:
read_phases();
break;
case Keywords::KEY_EQUILIBRIUM_PHASES:
read_pp_assemblage();
break;
case Keywords::KEY_REACTION:
read_reaction();
break;
case Keywords::KEY_MIX:
read_mix();
break;
case Keywords::KEY_RATE_PARAMETERS_PK:
read_rate_parameters_pk();
break;
case Keywords::KEY_RATE_PARAMETERS_SVD:
read_rate_parameters_svd();
break;
case Keywords::KEY_RATE_PARAMETERS_HERMANSKA:
read_rate_parameters_hermanska();
break;
case Keywords::KEY_MEAN_GAMMAS:
read_mean_gammas();
break;
case Keywords::KEY_GAS_BINARY_PARAMETERS:
read_gas_binary_parameters();
break;
case Keywords::KEY_SOLUTION_MIX:
//read_solution_mix();
read_entity_mix(Rxn_solution_mix_map);
break;
case Keywords::KEY_EXCHANGE_MIX:
read_entity_mix(Rxn_exchange_mix_map);
break;
case Keywords::KEY_GAS_PHASE_MIX:
read_entity_mix(Rxn_gas_phase_mix_map);
break;
case Keywords::KEY_KINETICS_MIX:
read_entity_mix(Rxn_kinetics_mix_map);
break;
case Keywords::KEY_PPASSEMBLAGE_MIX:
read_entity_mix(Rxn_pp_assemblage_mix_map);
break;
case Keywords::KEY_SSASSEMBLAGE_MIX:
read_entity_mix(Rxn_ss_assemblage_mix_map);
break;
case Keywords::KEY_SURFACE_MIX:
read_entity_mix(Rxn_surface_mix_map);
break;
case Keywords::KEY_USE:
read_use();
break;
case Keywords::KEY_SAVE:
read_save();
break;
case Keywords::KEY_EXCHANGE_SPECIES:
read_exchange_species();
break;
case Keywords::KEY_EXCHANGE_MASTER_SPECIES:
read_exchange_master_species();
break;
case Keywords::KEY_EXCHANGE:
read_exchange();
break;
case Keywords::KEY_SURFACE_SPECIES:
read_surface_species();
break;
case Keywords::KEY_SURFACE_MASTER_SPECIES:
read_surface_master_species();
break;
case Keywords::KEY_SURFACE:
read_surface();
break;
case Keywords::KEY_REACTION_TEMPERATURE:
read_temperature();
break;
case Keywords::KEY_INVERSE_MODELING:
read_inverse();
break;
case Keywords::KEY_GAS_PHASE:
read_gas_phase();
break;
case Keywords::KEY_TRANSPORT:
read_transport();
break;
case Keywords::KEY_KNOBS:
read_debug();
break;
case Keywords::KEY_SELECTED_OUTPUT:
read_selected_output();
break;
case Keywords::KEY_PRINT:
read_print();
break;
case Keywords::KEY_TITLE:
read_title();
break;
case Keywords::KEY_ADVECTION:
read_advection();
break;
case Keywords::KEY_KINETICS:
read_kinetics();
break;
case Keywords::KEY_INCREMENTAL_REACTIONS:
read_incremental_reactions();
break;
case Keywords::KEY_RATES:
read_rates();
break;
case Keywords::KEY_SOLUTION_SPREAD:
read_solution_spread();
break;
case Keywords::KEY_USER_PRINT:
read_user_print();
break;
case Keywords::KEY_USER_PUNCH:
read_user_punch();
break;
case Keywords::KEY_SOLID_SOLUTIONS:
read_solid_solutions();
break;
case Keywords::KEY_USER_GRAPH:
#if defined PHREEQ98
read_user_graph();
#elif defined MULTICHART
read_user_graph_handler();
# else
for (;;)
{
j = check_line("Reading user_graph", FALSE, TRUE, TRUE, TRUE);
if (j == EOF || j == KEYWORD)
{
break;
}
}
#endif
break;
case Keywords::KEY_LLNL_AQUEOUS_MODEL_PARAMETERS:
read_llnl_aqueous_model_parameters();
break;
case Keywords::KEY_DATABASE:
if (reading_database())
{
/* warning_msg("DATABASE is ignored in the database file."); */
}
else if (first_read_input == FALSE)
{
error_msg("DATABASE must be the first keyword in the input file.", CONTINUE);
input_error++;
}
else
{
cptr = line;
copy_token(token, &cptr, &l);
#if defined(SWIG_SHARED_OBJ)
warning_msg("DATABASE keyword is ignored by IPhreeqc.");
#else
user_database = cptr;
string_trim(user_database);
if (user_database.size() == 0)
{
error_msg("DATABASE file name is missing.", CONTINUE);
input_error++;
}
first_read_input = FALSE;
#endif
}
j = check_line("Reading after DATABASE", FALSE, TRUE, TRUE, TRUE);
break;
case Keywords::KEY_NAMED_EXPRESSIONS:
read_named_logk();
break;
case Keywords::KEY_ISOTOPES:
read_isotopes();
break;
case Keywords::KEY_CALCULATE_VALUES:
read_calculate_values();
break;
case Keywords::KEY_ISOTOPE_RATIOS:
read_isotope_ratios();
break;
case Keywords::KEY_ISOTOPE_ALPHAS:
read_isotope_alphas();
break;
case Keywords::KEY_COPY:
read_copy();
break;
case Keywords::KEY_PITZER:
read_pitzer();
break;
case Keywords::KEY_SIT:
read_sit();
break;
case Keywords::KEY_SOLUTION_RAW:
Utilities::Rxn_read_raw(Rxn_solution_map, Rxn_new_solution, this);
break;
case Keywords::KEY_EXCHANGE_RAW:
Utilities::Rxn_read_raw(Rxn_exchange_map, Rxn_new_exchange, this);
break;
case Keywords::KEY_SURFACE_RAW:
Utilities::Rxn_read_raw(Rxn_surface_map, Rxn_new_surface, this);
break;
case Keywords::KEY_EQUILIBRIUM_PHASES_RAW:
Utilities::Rxn_read_raw(Rxn_pp_assemblage_map, Rxn_new_pp_assemblage, this);
break;
case Keywords::KEY_KINETICS_RAW:
Utilities::Rxn_read_raw(Rxn_kinetics_map, Rxn_new_kinetics, this);
break;
case Keywords::KEY_SOLID_SOLUTIONS_RAW:
Utilities::Rxn_read_raw(Rxn_ss_assemblage_map, Rxn_new_ss_assemblage, this);
break;
case Keywords::KEY_GAS_PHASE_RAW:
Utilities::Rxn_read_raw(Rxn_gas_phase_map, Rxn_new_gas_phase, this);
break;
case Keywords::KEY_REACTION_RAW:
Utilities::Rxn_read_raw(Rxn_reaction_map, Rxn_new_reaction, this);
break;
case Keywords::KEY_MIX_RAW:
Utilities::Rxn_read_raw(Rxn_mix_map, Rxn_new_mix, this);
break;
case Keywords::KEY_REACTION_TEMPERATURE_RAW:
Utilities::Rxn_read_raw(Rxn_temperature_map, Rxn_new_temperature, this);
break;
case Keywords::KEY_DUMP:
read_dump();
break;
case Keywords::KEY_SOLUTION_MODIFY:
Utilities::Rxn_read_modify(Rxn_solution_map, Rxn_new_solution, this);
break;
case Keywords::KEY_EQUILIBRIUM_PHASES_MODIFY:
Utilities::Rxn_read_modify(Rxn_pp_assemblage_map, Rxn_new_pp_assemblage, this);
break;
case Keywords::KEY_EXCHANGE_MODIFY:
Utilities::Rxn_read_modify(Rxn_exchange_map, Rxn_new_exchange, this);
break;
case Keywords::KEY_SURFACE_MODIFY:
Utilities::Rxn_read_modify(Rxn_surface_map, Rxn_new_surface, this);
break;
case Keywords::KEY_SOLID_SOLUTIONS_MODIFY:
Utilities::Rxn_read_modify(Rxn_ss_assemblage_map, Rxn_new_ss_assemblage, this);
break;
case Keywords::KEY_GAS_PHASE_MODIFY:
Utilities::Rxn_read_modify(Rxn_gas_phase_map, Rxn_new_gas_phase, this);
break;
case Keywords::KEY_KINETICS_MODIFY:
Utilities::Rxn_read_modify(Rxn_kinetics_map, Rxn_new_kinetics, this);
break;
case Keywords::KEY_DELETE:
read_delete();
break;
case Keywords::KEY_RUN_CELLS:
read_run_cells();
break;
case Keywords::KEY_REACTION_MODIFY:
Utilities::Rxn_read_modify(Rxn_reaction_map, Rxn_new_reaction, this);
break;
case Keywords::KEY_REACTION_TEMPERATURE_MODIFY:
Utilities::Rxn_read_modify(Rxn_temperature_map, Rxn_new_temperature, this);
break;
//case LAST_C_KEYWORD + 22: //reaction_temperature_modify
// keyword[LAST_C_KEYWORD + 22].keycount++;
// read_reaction_temperature_modify();
// break;
case Keywords::KEY_REACTION_PRESSURE:
read_reaction_pressure();
break;
case Keywords::KEY_REACTION_PRESSURE_RAW:
Utilities::Rxn_read_raw(Rxn_pressure_map, Rxn_new_pressure, this);
break;
case Keywords::KEY_REACTION_PRESSURE_MODIFY:
Utilities::Rxn_read_modify(Rxn_pressure_map, Rxn_new_pressure, this);
break;
default:
error_msg("Error in keyword switch", STOP);
break;
}
}
END_OF_SIMULATION_INPUT:
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_exchange_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Read data for exchange species, parse equations
*/
int i;
int association;
char token[MAX_LENGTH];
const char* cptr;
class phase *phase_ptr;
class species *s_ptr;
const class elt_list *next_elt;
//LDBLE exchange_coef;
LDBLE offset;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"no_check", /* 0 */
"check", /* 1 */
"mb", /* 2 */
"mass_balance", /* 3 */
"log_k", /* 4 */
"logk", /* 5 */
"delta_h", /* 6 */
"deltah", /* 7 */
"analytical_expression", /* 8 */
"a_e", /* 9 */
"ae", /* 10 */
"mole_balance", /* 11 */
"gamma", /* 12 */
"davies", /* 13 */
"offset", /* 14 */
"llnl_gamma", /* 15 */
"add_logk", /* 16 */
"add_log_k", /* 17 */
"add_constant", /* 18 */
"vm" /* 19, molar volume, must replace delta_v */
};
int count_opt_list = 20;
association = TRUE;
s_ptr = NULL;
/*
* Read eqn from file and call parser
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in EXCHANGE_SPECIES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* no_check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = FALSE;
break;
case 1: /* check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = TRUE;
break;
case 2: /* mb */
case 3: /* mass_balance */
case 11: /* mole_balance */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
count_elts = 0;
paren_count = 0;
copy_token(token, &next_char, &i);
s_ptr->mole_balance = string_hsave(token);
cptr = token;
get_secondary_in_species(&cptr, 1.0);
s_ptr->next_secondary.clear();
s_ptr->next_secondary = elt_list_vsave();
/* debug
for (i = 0; i < count_elts; i++) {
output_msg(sformatf("%s\t%f\n", elt_list[i].elt->name,
elt_list[i].coef));
}
*/
opt_save = OPTION_DEFAULT;
break;
case 4: /* log_k */
case 5: /* logk */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_log_k_only(next_char, &s_ptr->logk[0]);
opt_save = OPTION_DEFAULT;
break;
case 6: /* delta_h */
case 7: /* deltah */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_delta_h_only(next_char, &s_ptr->logk[1],
&s_ptr->original_units);
opt_save = OPTION_DEFAULT;
break;
case 8: /* analytical_expression */
case 9: /* a_e */
case 10: /* ae */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_analytical_expression_only(next_char, &(s_ptr->logk[T_A1]));
opt_save = OPTION_DEFAULT;
break;
case 12: /* gamma */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->exch_gflag = 2;
s_ptr->a_f = 0;
i = sscanf(next_char, SCANFORMAT SCANFORMAT SCANFORMAT, &s_ptr->dha,
&s_ptr->dhb, &s_ptr->a_f);
if (i < 2)
{
error_string = sformatf( "Expecting 2 activity-"
"coefficient parameters, a and b.");
warning_msg(error_string);
}
if (s_ptr->dha == 0 && s_ptr->dhb == 0)
{
s_ptr->dhb = 99.9;
s_ptr->exch_gflag = 1;
}
opt_save = OPTION_DEFAULT;
break;
case 13: /* davies */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->exch_gflag = 1;
s_ptr->dha = 0;
s_ptr->dhb = 99.9;
opt_save = OPTION_DEFAULT;
break;
case 14: /* offset */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
if (sscanf(next_char, SCANFORMAT, &offset) != 1)
{
error_msg("No offset for log K given", STOP);
}
s_ptr->logk[0] += offset;
opt_save = OPTION_DEFAULT;
break;
case 15: /* llnl_gamma */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->exch_gflag = 7; /* llnl D-H */
i = sscanf(next_char, SCANFORMAT, &s_ptr->dha);
if (i < 1)
{
error_string = sformatf(
"Expecting activity-coefficient parameter, a.");
warning_msg(error_string);
}
opt_save = OPTION_DEFAULT;
break;
case 16: /* add_logk */
case 17: /* add_log_k */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
/* read name */
if (copy_token(token, &next_char, &i) == EMPTY)
{
input_error++;
error_string = sformatf(
"Expected the name of a NAMED_EXPRESSION.");
error_msg(error_string, CONTINUE);
break;
}
s_ptr->add_logk[count_add_logk].name = string_hsave(token);
/* read coef */
i = sscanf(next_char, SCANFORMAT,
&s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
s_ptr->add_logk[count_add_logk].coef = 1;
}
opt_save = OPTION_DEFAULT;
}
break;
case 18: /* add_constant */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
i = sscanf(next_char, SCANFORMAT,
&s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
input_error++;
error_string = sformatf(
"Expected the constant to add for log_K definition.");
error_msg(error_string, CONTINUE);
break;
}
/* set name */
s_ptr->add_logk[count_add_logk].name =
string_hsave("XconstantX");
/* read coef */
opt_save = OPTION_DEFAULT;
}
break;
case 19: /* vm, molar volume */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_vm_only(next_char, &s_ptr->logk[vm0],
&s_ptr->original_deltav_units);
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT:
/*
* Get exchange species information and parse equation
*/
{
s_ptr = NULL;
std::vector<class elt_list> new_elt_list;
if (parse_eq(line, new_elt_list, association) == ERROR)
{
parse_error++;
error_msg("Parsing equation.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
/*
* Get pointer to each species in the reaction, store new species if necessary
*/
trxn.token[0].s = s_store(trxn.token[0].name, trxn.token[0].z, TRUE);
for (i = 1; i < count_trxn; i++)
{
trxn.token[i].s = s_store(trxn.token[i].name, trxn.token[i].z, FALSE);
}
/*
* Save element list and carbon, hydrogen, and oxygen in species
*/
trxn.token[0].s->next_elt = new_elt_list;
next_elt = &trxn.token[0].s->next_elt[0];
for (; next_elt->elt != NULL; next_elt++)
{
if (strcmp(next_elt->elt->name, "C") == 0)
{
trxn.token[0].s->carbon = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "H") == 0)
{
trxn.token[0].s->h = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "O") == 0)
{
trxn.token[0].s->o = next_elt->coef;
}
}
/*
* Copy reaction to reaction for species
*/
trxn_copy(trxn.token[0].s->rxn);
/*
* Set type for species
*/
trxn.token[0].s->type = EX;
s_ptr = trxn.token[0].s;
/*
* Set gamma data
*/
s_ptr->gflag = 4;
s_ptr->exch_gflag = 3;
s_ptr->dha = 0.0;
s_ptr->dhb = 0.0;
opt_save = OPTION_DEFAULT;
/*
* Save as a phase for inverse modeling only
*/
phase_ptr = phase_store(s_ptr->name);
if (phase_ptr == NULL)
{
input_error++;
error_string = sformatf("Copying exchange to phases.");
error_msg(error_string, CONTINUE);
}
else
{
phase_ptr->formula = s_ptr->name;
phase_ptr->check_equation = FALSE;
phase_ptr->type = EX;
phase_ptr->next_elt = s_ptr->next_elt;
phase_ptr->rxn = s_ptr->rxn;
}
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_exchange(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads exchange data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int n_user;
LDBLE conc;
const char* cptr;
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"equilibrate", /* 0 */
"equil", /* 1 */
"pitzer_exchange_gammas", /* 2 */
"exchange_gammas", /* 3 */
"gammas", /* 4 */
"equilibrium" /* 5 */
};
int count_opt_list = 6;
/*
* kin_exch is for exchangers, related to kinetically reacting minerals
* they are defined if "sites" is followed by mineral name:
* Z Manganite ('equi' or 'kine') 0.25
* ^Name ^equi or kinetic mineral ^switch ^prop.factor
*/
/*
* Default values + n_user, description
*/
cxxExchange temp_exchange;
cptr = line;
temp_exchange.read_number_description(cptr);
n_user = temp_exchange.Get_n_user();
cxxExchComp *comp_ptr = NULL;
temp_exchange.Set_new_def(true);
/*
* Set use data
*/
if (use.Get_exchange_in() == FALSE)
{
use.Set_exchange_in(true);
use.Set_n_exchange_user(n_user);
}
/*
* Read exchange data
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in EXCHANGE keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* equilibrate */
case 1: /* equil */
case 5: /* equilibrium */
/*
* Read solution to equilibrate with
*/
for (;;)
{
std::string token;
int i = copy_token(token, &next_char);
if (i == DIGIT)
{
int n_solution;
(void)sscanf(token.c_str(), "%d", &n_solution);
temp_exchange.Set_n_solution(n_solution);
temp_exchange.Set_new_def(true);
temp_exchange.Set_solution_equilibria(true);
break;
}
if (i == EMPTY)
{
error_msg
("Expected a solution number with which to equilibrate exchanger.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
break;
case 2: /* pitzer_exchange_gammas */
case 3: /* exchange_gammas */
case 4: /* gammas */
temp_exchange.Set_pitzer_exchange_gammas(
get_true_false(next_char, TRUE) == TRUE);
break;
case OPTION_DEFAULT:
{
std::string token;
cptr = line;
int i = copy_token(token, &cptr);
/*
* Species formula is stored in token
*/
if (i != UPPER && token[0] != '[')
{ /* maybe a bit more clear? */
error_string = sformatf(
"Expected exchanger name to begin with a capital letter, but found:\n %s",
line_save);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
cxxExchComp temp_comp(this->phrq_io);
temp_exchange.Get_exchange_comps().push_back(temp_comp);
comp_ptr = &(temp_exchange.Get_exchange_comps().back());
comp_ptr->Set_formula(token.c_str());
prev_next_char = cptr;
std::string token1;
i = copy_token(token1, &cptr);
if (i == DIGIT)
{
/*
* Read exchange concentration
*/
/* exchanger conc. is read directly .. */
if (sscanf(token1.c_str(), SCANFORMAT, &conc) < 1)
{
error_string = sformatf(
"Expected concentration of exchanger, but found:\n %s",
line_save);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
prev_next_char = cptr;
int j = copy_token(token1, &cptr);
if (j == UPPER || j == LOWER)
{
comp_ptr->Set_rate_name(token1.c_str());
if (copy_token(token1, &cptr) != DIGIT)
{
error_string = sformatf(
"Expected a coefficient to relate exchange to kinetic reaction, but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
LDBLE p;
(void)sscanf(token1.c_str(), SCANFORMAT, &p);
comp_ptr->Set_phase_proportion(p);
}
/*
* Read equilibrium phase name or kinetics rate name
*/
}
else if (i != EMPTY)
{
/* exchanger conc. is related to mineral or kinetics */
comp_ptr->Set_phase_name(token1.c_str());
prev_next_char = cptr;
int j = copy_token(token1, &cptr);
if (j != DIGIT)
{
if (token1[0] == 'K' || token1[0] == 'k')
{
comp_ptr->Set_rate_name(comp_ptr->Get_phase_name().c_str());
comp_ptr->Set_phase_name("");
}
else if (token1[0] != 'E' && token1[0] != 'e')
{
error_string = sformatf(
"Character string expected to be 'equilibrium_phase' or 'kinetics'\n to relate exchange to mineral or kinetic reaction, but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
prev_next_char = cptr;
j = copy_token(token1, &cptr);
}
if (j != DIGIT)
{
error_string = sformatf(
"Expected a coefficient to relate exchanger to mineral or kinetic reaction, but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
LDBLE p;
(void)sscanf(token1.c_str(), SCANFORMAT, &p);
comp_ptr->Set_phase_proportion(p);
/* real conc must be defined in tidy_model */
conc = 1.0;
}
else
{
error_msg
("Expected concentration of exchanger, mineral name, or kinetic reaction name.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
/*
* Accumulate elements in elt_list
*/
count_elts = 0;
paren_count = 0;
std::string formula = token.c_str();
cptr = formula.c_str();
get_elts_in_species(&cptr, conc);
/*
* save formula for adjusting number of exchange sites
*/
cptr = formula.c_str();
std::string name;
LDBLE z;
int l;
get_token(&cptr, name, &z, &l);
comp_ptr->Set_formula_z(z);
/*
* Save elt_list
*/
comp_ptr->Set_totals(elt_list_NameDouble());
comp_ptr->Set_charge_balance(0.0);
}
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
Rxn_exchange_map[n_user] = temp_exchange;
Rxn_new_exchange.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_exchange_master_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads master species data from data file or input file
*/
int j, l;
const char* cptr, *cptr1;
LDBLE l_z;
class element *elts_ptr;
class species *s_ptr;
char token[MAX_LENGTH];
for (;;)
{
j = check_line("Exchange species equation", FALSE, TRUE, TRUE, TRUE);
if (j == EOF || j == KEYWORD)
{
break;
}
/*
* Get element name with valence, allocate space, store
*/
cptr = line;
/*
* Get element name and save pointer to character string
*/
if (copy_token(token, &cptr, &l) != UPPER && token[0] != '[')
{
parse_error++;
error_msg("Reading element for master species.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
if (token[0] == '[') {
cptr1 = token;
get_elt(&cptr, element, &l);
Utilities::strcpy_safe(token, MAX_LENGTH, element);
}
*/
replace("(+", "(", token);
/*
* Delete master if it exists
*/
master_delete(token);
/*
* Increase pointer array, if necessary, and malloc space
*/
size_t count_master = master.size();
master.resize(count_master + 1);
master[count_master] = master_alloc();
/*
* Set type to EX
*/
master[count_master]->type = EX;
/*
* Save element name
*/
master[count_master]->elt = element_store(token);
/*
* Save pointer to species data for master species
*/
if ((copy_token(token, &cptr, &l) != UPPER) &&
token[0] != '[' && (strcmp_nocase_arg1(token, "e-") != 0))
{
parse_error++;
error_msg("Reading master species name.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
s_ptr = s_search(token);
if (s_ptr != NULL)
{
master[count_master]->s = s_ptr;
}
else
{
cptr1 = token;
std::string token1;
get_token(&cptr1, token1, &l_z, &l);
master[count_master]->s = s_store(token1.c_str(), l_z, FALSE);
}
/*
* MAKE LISTS OF PRIMARY AND SECONDARY MASTER SPECIES
*/
master[count_master]->primary = TRUE;
if (strcmp(master[count_master]->elt->name, "E") != 0)
{
elts_ptr = element_store(master[count_master]->elt->name);
elts_ptr->gfw = 0.0;
}
}
return (j);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_gas_phase(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads gas phase data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int i, j, l;
int n_user;
const char* cptr;
char token[MAX_LENGTH];
cxxGasPhase temp_gas_phase(this->phrq_io);
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"pressure", /* 0 */
"volume", /* 1 */
"temp", /* 2 */
"temperature", /* 3 */
"fixed_pressure", /* 4 */
"fixed_volume", /* 5 */
"equilibrium", /* 6 */
"equilibrate", /* 7 */
"equil" /* 8 */
};
int count_opt_list = 9;
cptr = line;
temp_gas_phase.read_number_description(cptr);
n_user = temp_gas_phase.Get_n_user();
temp_gas_phase.Set_new_def(true);
/*
* Set use data to first read
*/
if (use.Get_gas_phase_in() == FALSE)
{
use.Set_gas_phase_in(true);
use.Set_n_gas_phase_user(n_user);
}
/*
* Read phases
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in GAS_PHASE keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* pressure */
(void)sscanf(next_char, SCANFORMAT, &dummy);
temp_gas_phase.Set_total_p(dummy);
break;
case 1: /* Volume */
(void)sscanf(next_char, SCANFORMAT, &dummy);
temp_gas_phase.Set_volume(dummy);
break;
case 2: /* Temperature */
case 3:
j = sscanf(next_char, SCANFORMAT, &dummy);
if (j == 1)
{
temp_gas_phase.Set_temperature(dummy + 273.15);
}
break;
case 4: /* fixed_pressure */
temp_gas_phase.Set_type(cxxGasPhase::GP_PRESSURE);
break;
case 5: /* fixed_volume */
temp_gas_phase.Set_type(cxxGasPhase::GP_VOLUME);
break;
case 6: /* equilibrate */
case 7: /* equilibrium */
case 8: /* equil */
/*
* Read solution to equilibrate with
*/
for (;;)
{
i = copy_token(token, &next_char, &l);
if (i == DIGIT)
{
(void)sscanf(token, "%d", &l);
temp_gas_phase.Set_n_solution(l);
temp_gas_phase.Set_new_def(true);
temp_gas_phase.Set_solution_equilibria(true);
break;
}
if (i == EMPTY)
{
error_msg
("Expected a solution number with which to equilibrate gas phase.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
break;
case OPTION_DEFAULT:
{
cxxGasComp temp_comp;
/*
* Read name
*/
cptr = line;
copy_token(token, &cptr, &l);
temp_comp.Set_phase_name(token);
if ((j = copy_token(token, &cptr, &l)) == EMPTY)
{
temp_comp.Set_p_read(NAN);
temp_gas_phase.Get_gas_comps().push_back(temp_comp);
break;
}
/*
* Read initial partial pressure of gas
*/
j = sscanf(token, SCANFORMAT, &dummy);
if (j != 1)
{
error_msg("Expected partial pressure of gas in gas phase.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else
{
temp_comp.Set_p_read(dummy);
temp_gas_phase.Get_gas_comps().push_back(temp_comp);
}
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
// sort components
std::map<std::string, cxxGasComp> gc;
for (size_t i = 0; i < temp_gas_phase.Get_gas_comps().size(); i++)
{
cxxGasComp *gc_ptr = &(temp_gas_phase.Get_gas_comps()[i]);
gc[gc_ptr->Get_phase_name()] = *gc_ptr;
}
std::vector<cxxGasComp> vgc;
std::map<std::string, cxxGasComp>::iterator it = gc.begin();
for ( ; it != gc.end(); it++)
{
vgc.push_back(it->second);
}
temp_gas_phase.Set_gas_comps(vgc);
Rxn_gas_phase_map[n_user] = temp_gas_phase;
Rxn_new_gas_phase.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_inverse(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads data for mass_balance calculations
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int n, j;
int n_user, n_user_end;
const char* cptr;
char *description;
LDBLE range_max, inv_tol, water_uncertainty;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"solutions", /* 0 */
"uncertainty", /* 1 */
"uncertainties", /* 2 */
"balances", /* 3 */
"phase_data", /* 4 */
"range", /* 5 */
"minimal", /* 6 */
"minimum", /* 7 */
"balance", /* 8 */
"bal", /* 9 */
"sol", /* 10 */
"phases", /* 11 */
"ranges", /* 12 */
"tolerance", /* 13 */
"u_water", /* 14 */
"uncertainty_water", /* 15 */
"force", /* 16 */
"force_solution", /* 17 */
"force_solutions", /* 18 */
"isotopes", /* 19 */
"mineral_water", /* 20 */
"phase", /* 21 */
"multiple_precision", /* 22 */
"mp_tolerance", /* 23 */
"censor_mp", /* 24 */
"lon_netpath", /* 25 */
"pat_netpath" /* 26 */
};
int count_opt_list = 27;
cptr = line;
/*
* Read solution number and description
*/
read_number_description(cptr, &n_user, &n_user_end, &description);
/*
* Malloc space for solution data
*/
if (inverse_search(n_user, &n) != NULL)
{
inverse_delete(n);
}
inverse_alloc();
n = count_inverse - 1;
/*
* Initialize structure and use
*/
inverse[n].new_def = TRUE;
inverse[n].n_user = n_user;
inverse[n].range = FALSE;
inverse[n].range_max = 1000.;
inverse[n].tolerance = 1e-10;
inverse[n].minimal = FALSE;
inverse[n].description = description;
inverse[n].water_uncertainty = 0.0;
inverse[n].mineral_water = TRUE;
inverse[n].mp = FALSE;
inverse[n].mp_tolerance = 1e-12;
inverse[n].mp_censor = 1e-20;
inverse[n].netpath = NULL;
inverse[n].pat = NULL;
/*
* Read data for inverse modeling
*/
opt_save = OPTION_ERROR;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = opt;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in INVERSE_MODELING keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* solutions */
case 10: /* solution */
read_vector_ints(&next_char, inverse[n].solns, TRUE);
inverse[n].count_solns = (int)inverse[n].solns.size();
opt_save = OPTION_ERROR;
break;
case 1: /* uncertainty */
case 2: /* uncertainties */
read_vector_doubles(&next_char, inverse[n].uncertainties);
opt_save = OPTION_ERROR;
break;
case 3: /* balances */
case 8: /* balance */
case 9: /* bal */
read_inv_balances(&(inverse[n]), next_char);
break;
case 4: /* phase_data */
case 11: /* phases */
case 21: /* phase */
read_inv_phases(&(inverse[n]), next_char);
break;
case 5: /* range */
case 12: /* ranges */
inverse[n].range = TRUE;
j = sscanf(next_char, SCANFORMAT, &range_max);
if (j == 1)
{
inverse[n].range_max = range_max;
}
opt_save = OPTION_ERROR;
break;
case 6: /* minimal */
case 7: /* minimum */
inverse[n].minimal = TRUE;
opt_save = OPTION_ERROR;
break;
case 13: /* tolerance */
j = sscanf(next_char, SCANFORMAT, &inv_tol);
if (j == 1)
{
inverse[n].tolerance = inv_tol;
}
opt_save = OPTION_ERROR;
break;
case 14: /* u_water */
case 15: /* uncertainty_water */
j = sscanf(next_char, SCANFORMAT, &water_uncertainty);
if (j == 1)
{
inverse[n].water_uncertainty = water_uncertainty;
}
opt_save = OPTION_ERROR;
break;
case 16: /* force */
case 17: /* force_solution */
case 18: /* force_solutions */
inverse[n].force_solns.clear();
read_vector_t_f(&next_char, inverse[n].force_solns);
opt_save = OPTION_ERROR;
break;
case 19: /* isotope values */
read_inv_isotopes(&(inverse[n]), next_char);
break;
case 20: /* mineral_water */
inverse[n].mineral_water = get_true_false(next_char, TRUE);
opt_save = OPTION_ERROR;
break;
case 22: /* multiple_precision */
inverse[n].mp = get_true_false(next_char, TRUE);
opt_save = OPTION_ERROR;
break;
case 23: /* mp_tolerance */
j = sscanf(next_char, SCANFORMAT, &inv_tol);
if (j == 1)
{
inverse[n].mp_tolerance = fabs(inv_tol);
}
opt_save = OPTION_ERROR;
break;
case 24: /* censor_mp */
j = sscanf(next_char, SCANFORMAT, &inv_tol);
if (j == 1)
{
inverse[n].mp_censor = fabs(inv_tol);
}
opt_save = OPTION_ERROR;
break;
case 25: /* lon_netpath */
{
std::string temp_name(next_char);
string_trim(temp_name);
if (temp_name.size() > 0)
{
inverse[n].netpath = string_hsave(temp_name.c_str());
}
else
{
inverse[n].netpath = string_hsave("netpath");
}
opt_save = OPTION_ERROR;
}
break;
case 26: /* pat_netpath */
{
std::string temp_name(next_char);
string_trim(temp_name);
if (temp_name.size() > 0)
{
inverse[n].pat = string_hsave(temp_name.c_str());
}
else
{
inverse[n].pat = string_hsave("netpath");
}
opt_save = OPTION_ERROR;
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
/*
* Default: soln 1 -> soln 2
*/
if (inverse[n].count_solns == 0)
{
inverse[n].solns.push_back(1);
inverse[n].solns.push_back(2);
inverse[n].count_solns = 2;
}
/*
* Sort isotopes
*/
if (inverse[n].isotopes.size() > 1)
{
qsort(&inverse[n].isotopes[0],
inverse[n].isotopes.size(),
sizeof(class inv_isotope), inverse_isotope_compare);
}
if (inverse[n].i_u.size() > 1)
{
qsort(&inverse[n].i_u[0],
inverse[n].i_u.size(),
(size_t) sizeof(class inv_isotope), inverse_isotope_compare);
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_inv_balances(class inverse *inverse_ptr, const char* cptr)
/* ---------------------------------------------------------------------- */
{
int j, l;
char token[MAX_LENGTH];
/*
* Read element name
*/
j = copy_token(token, &cptr, &l);
if (j == EMPTY)
{
return (OK);
}
else if (j == LOWER && strcmp_nocase_arg1(token, "ph") != 0)
{
error_msg("Expecting element name.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else if (strcmp_nocase_arg1(token, "ph") != 0)
{
size_t count_elts = inverse_ptr->elts.size();
inverse_ptr->elts.resize(count_elts + 1);
replace("(+", "(", token);
inverse_ptr->elts[count_elts].name = string_hsave(token);
/*
* Read element uncertainties
*/
read_vector_doubles(&cptr, inverse_ptr->elts[count_elts].uncertainties);
}
else if (strcmp_nocase_arg1(token, "ph") == 0)
{
inverse_ptr->ph_uncertainties.clear();
read_vector_doubles(&cptr, inverse_ptr->ph_uncertainties);
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_inv_isotopes(class inverse *inverse_ptr, const char* cptr)
/* ---------------------------------------------------------------------- */
{
int i, j, l, l1, l2;
LDBLE isotope_number;
char token[MAX_LENGTH], token1[MAX_LENGTH];
const char* cptr1, *ptr2;
const char * redox_name, *element_name;
/*
* Read element name
*/
cptr1 = cptr;
j = copy_token(token, &cptr1, &l);
/*
* cptr1 is start of uncertainties
*/
if (j == EMPTY)
{
return (OK);
}
else if (j != DIGIT)
{
error_msg("Expecting isotope to begin with isotope number.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
/*
* Read isotope name
*/
ptr2 = token;
get_num(&ptr2, &isotope_number);
if (ptr2[0] == '\0' || isupper((int) ptr2[0]) == FALSE)
{
error_msg("Expecting element name.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
/* redox state name with parentheses */
redox_name = string_hsave(ptr2);
copy_token(token, &ptr2, &l1);
replace("(", " ", token);
ptr2 = token;
/* element name, without parentheses */
copy_token(token1, &ptr2, &l2);
element_name = string_hsave(token1);
/*
* add element name to inv_ptr->isotopes
*/
for (i = 0; i < inverse_ptr->isotopes.size(); i++)
{
if (element_name == inverse_ptr->isotopes[i].elt_name)
break;
}
if (i == inverse_ptr->isotopes.size())
{
size_t count_isotopes = inverse_ptr->isotopes.size();
inverse_ptr->isotopes.resize(count_isotopes + 1);
inverse_ptr->isotopes[count_isotopes].isotope_number = isotope_number;
inverse_ptr->isotopes[count_isotopes].elt_name = element_name;
inverse_ptr->isotopes[count_isotopes].uncertainties.clear();
}
/*
* add redox state name to inv_ptr->i_u
*/
size_t count_i_u = inverse_ptr->i_u.size();
inverse_ptr->i_u.resize(count_i_u + 1);
inverse_ptr->i_u[count_i_u].elt_name = redox_name;
inverse_ptr->i_u[count_i_u].isotope_number = isotope_number;
/*
* Read isotope uncertainties
*/
read_vector_doubles(&cptr1, inverse_ptr->i_u[count_i_u].uncertainties);
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_inv_phases(class inverse *inverse_ptr, const char* cptr)
/* ---------------------------------------------------------------------- */
{
int j, l;
char token[MAX_LENGTH], token1[MAX_LENGTH];
const char* cptr1;
std::vector <cxxSolutionIsotope> isotopes;
/*
* Read phase name
*/
j = copy_token(token, &cptr, &l);
if (j == EMPTY)
return (OK);
size_t count_phases = inverse_ptr->phases.size();
inverse_ptr->phases.resize(count_phases + 1);
inverse_ptr->phases[count_phases].name = string_hsave(token);
/*
* Read constraint, force, and isotopes
*/
inverse_ptr->phases[count_phases].constraint = EITHER;
inverse_ptr->phases[count_phases].force = FALSE;
for (;;)
{
cxxSolutionIsotope temp_isotope;
j = copy_token(token, &cptr, &l);
if (j == EMPTY)
break;
Utilities::strcpy_safe(token1, MAX_LENGTH, token);
str_tolower(token1);
if (token1[0] == 'p')
{
inverse_ptr->phases[count_phases].constraint = PRECIPITATE;
}
else if (token1[0] == 'd')
{
inverse_ptr->phases[count_phases].constraint = DISSOLVE;
}
else if (token[0] == 'f')
{
inverse_ptr->phases[count_phases].force = TRUE;
}
else if (j == DIGIT)
{
/*
* read isotope data
*/
cptr1 = token;
/* isotope number */
get_num(&cptr1, &dummy);
temp_isotope.Set_isotope_number(dummy);
if (cptr1[0] == '\0' || isupper((int) cptr1[0]) == FALSE)
{
error_string = sformatf( "Expecting element name: %s.", cptr1);
error_msg(error_string, CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
/* element name */
temp_isotope.Set_elt_name(cptr1);
/* ratio */
j = copy_token(token, &cptr, &l);
if (j != DIGIT)
{
error_msg("Expecting isotope ratio for phase.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
(void)sscanf(token, SCANFORMAT, &dummy);
temp_isotope.Set_ratio(dummy);
/* read and store isotope ratio uncertainty */
prev_next_char = cptr;
if (copy_token(token, &cptr, &l) != DIGIT)
{
input_error++;
error_string = sformatf(
"Expected numeric value for uncertainty in isotope ratio, but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
continue;
}
(void)sscanf(token, SCANFORMAT, &dummy);
temp_isotope.Set_ratio_uncertainty(dummy);
temp_isotope.Set_ratio_uncertainty_defined(true);
isotopes.push_back(temp_isotope);
}
else
{
error_string = sformatf(
"Unknown option for inverse modeling phase.");
warning_msg(error_string);
}
}
if (isotopes.size() > 0)
{
inverse_ptr->phases[count_phases].isotopes.resize(isotopes.size());
for (size_t i = 0; i < isotopes.size(); i++)
{
class isotope *iso_ptr = &(inverse_ptr->phases[count_phases].isotopes[i]);
iso_ptr->isotope_number = isotopes[i].Get_isotope_number();
iso_ptr->elt_name = string_hsave(isotopes[i].Get_elt_name().c_str());
iso_ptr->isotope_name = string_hsave(isotopes[i].Get_isotope_name().c_str());
iso_ptr->total = isotopes[i].Get_total();
iso_ptr->ratio = isotopes[i].Get_ratio();
if (isotopes[i].Get_ratio_uncertainty_defined())
iso_ptr->ratio_uncertainty = isotopes[i].Get_ratio_uncertainty();
else
iso_ptr->ratio_uncertainty = NAN;
iso_ptr->x_ratio_uncertainty = isotopes[i].Get_x_ratio_uncertainty();
iso_ptr->coef = isotopes[i].Get_coef();
iso_ptr->master = NULL;
iso_ptr->primary = NULL;
}
}
else
{
inverse_ptr->phases[count_phases].isotopes.clear();
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_kinetics(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads kinetics data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
/*
* Read kinetics
*/
const char* cptr;
std::string token;
int n_user;
LDBLE step;
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"tol", /* 0 */
"m", /* 1 */
"m0", /* 2 */
"parms", /* 3 */
"formula", /* 4 */
"steps", /* 5 */
"step_divide", /* 6 */
"parameters", /* 7 */
"runge-kutta", /* 8 */
"runge_kutta", /* 9 */
"rk", /* 10 */
"bad_step_max", /* 11 */
"cvode", /* 12 */
"cvode_steps", /* 13 */
"cvode_order", /* 14 */
"time_steps" /* 15 */
};
int count_opt_list = 16;
cxxKinetics temp_kinetics(this->phrq_io);
cptr = line;
temp_kinetics.read_number_description(cptr);
n_user = temp_kinetics.Get_n_user();
cxxKineticsComp *kinetics_comp_ptr = NULL;
std::string stdunits;
/*
* Set use data to first read
*/
if (use.Get_kinetics_in() == FALSE)
{
use.Set_kinetics_in(true);
use.Set_n_kinetics_user(n_user);
}
/*
* Read kinetics data
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* allocate space, read new name */
if (kinetics_comp_ptr)
{
temp_kinetics.Get_kinetics_comps().push_back(*kinetics_comp_ptr);
delete kinetics_comp_ptr;
}
kinetics_comp_ptr = new cxxKineticsComp;
cptr = line;
copy_token(token, &cptr);
kinetics_comp_ptr->Set_rate_name(token.c_str());
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in KINETICS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* tolerance */
if (kinetics_comp_ptr == NULL)
{
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
else
{
prev_next_char = next_char;
if (copy_token(token, &next_char) == DIGIT)
{
char* ptr;
kinetics_comp_ptr->Set_tol(strtod(token.c_str(), &ptr));
}
else
{
error_string = sformatf(
"Expecting numerical value for tolerance, but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 1: /* m */
if (kinetics_comp_ptr == NULL)
{
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
else
{
prev_next_char = next_char;
if (copy_token(token, &next_char) == DIGIT)
{
char* ptr;
kinetics_comp_ptr->Set_m(strtod(token.c_str(), &ptr));
}
else
{
error_string = sformatf(
"Expecting numerical value for moles of reactant (m), but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 2: /* m0 */
if (kinetics_comp_ptr == NULL)
{
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
else
{
prev_next_char = next_char;
if (copy_token(token, &next_char) == DIGIT)
{
char* ptr;
kinetics_comp_ptr->Set_m0(strtod(token.c_str(), &ptr));
}
else
{
error_string = sformatf(
"Expecting numerical value for initial moles of reactant (m0), but found:\n %s",
prev_next_char);
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 3: /* parms */
case 7: /* parameters */
if (kinetics_comp_ptr == NULL)
{
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
else
{
int j;
while ((j = copy_token(token, &next_char)) != EMPTY)
{
/*
* Store a LDBLE parameter
*/
if (j == DIGIT)
{
char* ptr;
kinetics_comp_ptr->Get_d_params().push_back(strtod(token.c_str(), &ptr));
}
else
{
/*
* Store a character parameter
*/
kinetics_comp_ptr->Get_c_params().push_back(token);
}
}
}
break;
case 4: /* formula */
if (kinetics_comp_ptr == NULL)
{
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
else
{
/*
* Store reactant name, default coefficient
*/
cptr = next_char;
bool have_name = false;
std::string name;
LDBLE coef = 1;
while (copy_token(token, &cptr) != EMPTY)
{
coef = 1;
if (isalpha((int) token[0]) || (token[0] == '(')
|| (token[0] == '['))
{
if (have_name)
{
kinetics_comp_ptr->Get_namecoef().add(name.c_str(), coef);
}
name = token;
have_name = true;
}
else
{
if (!have_name)
{
error_string = sformatf( "No phase or chemical formula has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
/*
* Store relative coefficient
*/
int j = sscanf(token.c_str(), SCANFORMAT, &coef);
if (j == 1)
{
kinetics_comp_ptr->Get_namecoef().add(name.c_str(), coef);
have_name = false;
}
else
{
error_msg
("Reading relative coefficient of reactant.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
}
if (have_name)
{
kinetics_comp_ptr->Get_namecoef().add(name.c_str(), coef);
}
}
break;
case 5: /* steps */
case 15: /* time_steps */
/*
* Read one or more kinetics time increments
*/
{
int j;
while ((j = copy_token(token, &next_char)) != EMPTY)
{
if (j == DIGIT)
{
/* Read next step increment(s) */
/* multiple, equal timesteps 15 aug. 2005 */
if (Utilities::replace("*", " ", token))
{
int k;
if (sscanf(token.c_str(), "%d" SCANFORMAT, &k, &step) == 2)
{
for (int i = 0; i < k; i++)
{
temp_kinetics.Get_steps().push_back(step);
}
}
else
{
input_error++;
error_msg
("Format error in multiple, equal KINETICS timesteps.\nCorrect is (for example): 20 4*10 2*5 3\n",
CONTINUE);
}
}
else
{
char* ptr;
step = strtod(token.c_str(), &ptr);
temp_kinetics.Get_steps().push_back(step);
}
}
else
{
Utilities::str_tolower(token);
if (token.substr(0,1) == "i" )
{
/*
* Read number of increments
*/
if (temp_kinetics.Get_steps().size() != 1)
{
error_msg
("To define equal time increments, only one total time should be defined.",
CONTINUE);
input_error++;
break;
}
temp_kinetics.Set_equalIncrements(true);
do
{
int i = 1;
j = sscanf(token.c_str(), "%d", &i);
if (j == 1)
{
temp_kinetics.Set_count(abs(i));
break;
}
else if (j == 1 && i < 0)
{
error_msg
("Expecting positive number for number of equal "
"time increments for kinetics.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
while (copy_token(token, &next_char) != EMPTY);
}
else
{
stdunits = token;
}
}
}
}
break;
case 6: /* step_divide */
if (copy_token(token, &next_char) == DIGIT)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_kinetics.Set_step_divide(dummy);
}
else
{
error_string = sformatf(
"Expecting numerical value for step_divide.");
error_msg(error_string, CONTINUE);
input_error++;
}
break;
case 8: /* runge-kutta */
case 9: /* runge_kutta */
case 10: /* rk */
{
int j = copy_token(token, &next_char);
if (j == DIGIT)
{
char* ptr;
temp_kinetics.Set_rk((int) strtod(token.c_str(), &ptr));
}
else if (j == EMPTY)
{
}
else
{
error_string = sformatf(
"Expecting order for Runge-Kutta method.");
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 11: /* bad_step_max */
{
int j = copy_token(token, &next_char);
if (j == DIGIT)
{
char* ptr;
temp_kinetics.Set_bad_step_max((int) strtod(token.c_str(), &ptr));
}
else if (j == EMPTY)
{
}
else
{
error_string = sformatf( "Expecting maximal bad steps number.");
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 12: /* cvode */
temp_kinetics.Set_use_cvode(get_true_false(next_char, TRUE) == TRUE);
break;
case 13: /* cvode_steps */
{
int j = copy_token(token, &next_char);
if (j == DIGIT)
{
char* ptr;
temp_kinetics.Set_cvode_steps((int) strtod(token.c_str(), &ptr));
}
else if (j == EMPTY)
{
}
else
{
error_string = sformatf(
"Expecting maximum number of steps for one call to cvode.");
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
case 14: /* cvode_order */
{
int j = copy_token(token, &next_char);
if (j == DIGIT)
{
char* ptr;
temp_kinetics.Set_cvode_order((int) strtod(token.c_str(), &ptr));
}
else if (j == EMPTY)
{
}
else
{
error_string = sformatf(
"Expecting number of terms (order) used in cvode (1-5).");
error_msg(error_string, CONTINUE);
input_error++;
}
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
// save last comp
if (kinetics_comp_ptr)
{
temp_kinetics.Get_kinetics_comps().push_back(*kinetics_comp_ptr);
delete kinetics_comp_ptr;
}
/*
* Default reactant
*/
for (size_t i = 0; i < temp_kinetics.Get_kinetics_comps().size(); i++)
{
cxxKineticsComp *kinetics_comp_ptr = &(temp_kinetics.Get_kinetics_comps()[i]);
if (kinetics_comp_ptr->Get_namecoef().size() == 0)
{
kinetics_comp_ptr->Get_namecoef().add(kinetics_comp_ptr->Get_rate_name().c_str(), 1.0);
}
}
/*
* Default 1 sec
*/
if (temp_kinetics.Get_steps().size() == 0)
{
temp_kinetics.Get_steps().push_back(1.0);
}
else if (stdunits.size() > 0)
{
std::vector<LDBLE>::iterator it;
for (it = temp_kinetics.Get_steps().begin(); it != temp_kinetics.Get_steps().end(); it++)
{
*it = Utilities::convert_time(*it, stdunits, "s");
}
}
/*
* set defaults for moles
*/
for (size_t i = 0; i < temp_kinetics.Get_kinetics_comps().size(); i++)
{
cxxKineticsComp *kinetics_comp_ptr = &(temp_kinetics.Get_kinetics_comps()[i]);
if (kinetics_comp_ptr->Get_m0() < 0)
{
if (kinetics_comp_ptr->Get_m() < 0)
{
kinetics_comp_ptr->Set_m0(1);
}
else
{
kinetics_comp_ptr->Set_m0(kinetics_comp_ptr->Get_m());
}
}
if (kinetics_comp_ptr->Get_m() < 0)
{
kinetics_comp_ptr->Set_m(kinetics_comp_ptr->Get_m0());
}
}
Rxn_kinetics_map[n_user] = temp_kinetics;
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_rate_parameters_pk(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads kinetics data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
std::string token;
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"xxxx", /* 0 */
};
int count_opt_list = 0;
/*
* Read rate parameters
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* add to rate_parameters_pk map */
{
std::string min_name;
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
min_name = token;
str_tolower(min_name);
}
std::vector<double> v;
read_vector_doubles(&next_char, v);
rate_parameters_pk[min_name] = v;
}
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in KINETICS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_mean_gammas(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads MEAN_GAMMAS data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
std::string token;
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"xxxx", /* 0 */
};
int count_opt_list = 0;
/*
* Read rate parameters
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* add to mean_gammas map */
{
std::string salt_name;
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
salt_name = token;
str_tolower(salt_name);
}
cxxNameDouble nd;
/*
* Store reactant name, default coefficient
*/
const char* cptr = next_char;
bool have_name = false;
std::string name;
LDBLE coef = 1;
while (copy_token(token, &cptr) != EMPTY)
{
coef = 1;
if (isalpha((int)token[0]) || (token[0] == '(')
|| (token[0] == '['))
{
if (have_name)
{
nd.add(name.c_str(), coef);
}
name = token;
have_name = true;
}
else
{
if (!have_name)
{
error_string = sformatf("No species name has been defined.");
error_msg(error_string, CONTINUE);
input_error++;
}
/*
* Store relative coefficient
*/
int j = sscanf(token.c_str(), SCANFORMAT, &coef);
if (j == 1)
{
nd.add(name.c_str(), coef);
have_name = false;
}
else
{
error_msg("Reading relative coefficient of reactant.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
//if (have_name)
//{
// nd.add(name.c_str(), coef);
//}
}
//read_vector_doubles(&next_char, v);
mean_gammas[salt_name] = nd;
}
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in MEAN_GAMMAS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_gas_binary_parameters(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads GAS_BINARY_PARAMETERS data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
std::string token;
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"xxxx", /* 0 */
};
int count_opt_list = 0;
/*
* Read rate parameters
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* add to gas_binary_parameters map */
{
bool error = false;
std::string gas1, gas2;
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
gas1 = token;
}
else
{
error = true;
}
j = copy_token(token, &next_char);
if (j != EMPTY)
{
gas2 = token;
}
else
{
error = true;
}
j = copy_token(token, &next_char);
double d;
if (j != EMPTY)
{
j = sscanf(token.c_str(), SCANFORMAT, &d);
}
else
{
error = true;
}
if (!error)
{
gas_binary_parameters[std::make_pair(gas1, gas2)] = d;
gas_binary_parameters[std::make_pair(gas2, gas1)] = d;
}
else
{
error_msg("Error reading gas binary parameter", CONTINUE);
}
}
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in GAS_BINARY_PARAMETERS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_rate_parameters_svd(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads kinetics data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
std::string token;
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"xxxx", /* 0 */
};
int count_opt_list = 0;
/*
* Read rate parameters
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* add to rate_parameters_svd map */
{
std::string min_name;
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
min_name = token;
str_tolower(min_name);
}
std::vector<double> v;
read_vector_doubles(&next_char, v);
rate_parameters_svd[min_name] = v;
}
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in KINETICS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_rate_parameters_hermanska(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads kinetics data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
std::string token;
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"xxxx", /* 0 */
};
int count_opt_list = 0;
/*
* Read rate parameters
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT: /* add to rate_parameters_hermanska map */
{
std::string min_name;
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
min_name = token;
str_tolower(min_name);
}
std::vector<double> v;
read_vector_doubles(&next_char, v);
rate_parameters_hermanska[min_name] = v;
}
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in KINETICS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
bool Phreeqc::
read_vector_doubles(const char** cptr, std::vector<double>& v)
/* ---------------------------------------------------------------------- */
{
/*
* Reads a list of LDBLE numbers until end of line is reached or
* a LDBLE cannot be read from a token.
*/
double value;
std::istringstream iss(*cptr);
while (iss >> value)
{
v.push_back(value);
}
return true;
}
/* ---------------------------------------------------------------------- */
bool Phreeqc::
read_vector_ints(const char** cptr, std::vector<int>& v, int positive)
/* ---------------------------------------------------------------------- */
{
/*
* Reads a list of int numbers until end of line is reached or
* an int cannot be read from a token.
*/
int value;
std::istringstream iss(*cptr);
while (iss >> value)
{
v.push_back(value);
if (value <= 0 && positive == TRUE)
{
error_msg("Expected an integer greater than zero.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return false;
}
}
return true;
}
/* ---------------------------------------------------------------------- */
int * Phreeqc::
read_list_ints_range(const char **cptr, int *count_ints, int positive, int *int_list)
/* ---------------------------------------------------------------------- */
{
/*
* Reads a list of int numbers until end of line is reached or
* an int cannot be read from a token.
*
* Arguments:
* cptr entry: points to line to read from
* exit: points to next non-int token or end of line
*
* count_ints entry: number of ints already in list
*
* positive entry: if TRUE, expects to read only positive integers
*
* Returns:
* pointer to a list of count_ints ints
*/
char token[MAX_LENGTH];
int value, value1, value2;
int i, l;
const char* cptr_save;
if (int_list == NULL)
{
int_list = (int *) PHRQ_malloc(sizeof(int));
if (int_list == NULL)
{
malloc_error();
return (NULL);
}
*count_ints = 0;
}
cptr_save = *cptr;
while (copy_token(token, cptr, &l) != EMPTY)
{
if (sscanf(token, "%d", &value) == 1)
{
/* Read an integer */
(*count_ints)++;
int_list =
(int *) PHRQ_realloc(int_list,
(size_t) (*count_ints) * sizeof(int));
if (int_list == NULL)
{
malloc_error();
return (NULL);
}
int_list[(*count_ints) - 1] = value;
if (value <= 0 && positive == TRUE)
{
error_msg("Expected an integer greater than zero.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
/* Read range of integers */
if (replace("-", " ", token) == TRUE)
{
if (sscanf(token, "%d %d", &value1, &value2) != 2)
{
error_msg("Expected an integer range n-m.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else if (value2 < value1)
{
error_msg("Expected an integer range n-m, with n <= m.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else if (value2 <= 0 && positive == TRUE)
{
error_msg("Expected an integer greater than zero.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else
{
for (i = value1 + 1; i <= value2; i++)
{
(*count_ints)++;
int_list =
(int *) PHRQ_realloc(int_list,
(size_t) (*count_ints) *
sizeof(int));
if (int_list == NULL)
{
malloc_error();
return (NULL);
}
int_list[(*count_ints) - 1] = i;
}
}
}
cptr_save = *cptr;
}
else
{
*cptr = cptr_save;
break;
}
}
return (int_list);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_list_ints_range(const char** cptr, bool positive, std::vector<int> &int_list)
/* ---------------------------------------------------------------------- */
{
/*
* Reads a list of int numbers until end of line is reached or
* an int cannot be read from a token.
*
* Arguments:
* cptr entry: points to line to read from
* exit: points to next non-int token or end of line
*
* count_ints entry: number of ints already in list
*
* positive entry: if TRUE, expects to read only positive integers
*
* Returns:
* pointer to a list of count_ints ints
*/
char token[MAX_LENGTH];
int value, value1, value2;
int i, l;
const char* cptr_save;
int count_start = (int)int_list.size();
cptr_save = *cptr;
while (copy_token(token, cptr, &l) != EMPTY)
{
if (sscanf(token, "%d", &value) == 1)
{
/* Read an integer */
int_list.push_back(value);
if (value <= 0 && positive)
{
error_msg("Expected an integer greater than zero.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
/* Read range of integers */
if (replace("-", " ", token) == TRUE)
{
if (sscanf(token, "%d %d", &value1, &value2) != 2)
{
error_msg("Expected an integer range n-m.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else if (value2 < value1)
{
error_msg("Expected an integer range n-m, with n <= m.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else if (value2 <= 0 && positive == TRUE)
{
error_msg("Expected an integer greater than zero.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else
{
for (i = value1 + 1; i <= value2; i++)
{
int_list.push_back(i);
}
}
}
cptr_save = *cptr;
}
else
{
*cptr = cptr_save;
break;
}
}
return ((int )int_list.size() - count_start);
}
/* ---------------------------------------------------------------------- */
bool Phreeqc::
read_vector_t_f(const char** cptr, std::vector<bool>& v)
/* ---------------------------------------------------------------------- */
{
/*
* Reads a list of true and false until end of line is reached or
* until non- t or f is found
*/
std::string token;
while (copy_token(token, cptr) != EMPTY)
{
str_tolower(token);
if (token[0] == 't')
{
v.push_back(true);
}
else if (token[0] == 'f')
{
v.push_back(false);
}
else
{
error_msg("Expected TRUE or FALSE.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return false;
}
}
return true;
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_log_k_only(const char* cptr_in, LDBLE * log_k)
/* ---------------------------------------------------------------------- */
{
/*
* Read log k
*/
*log_k = 0.0;
std::string stds(cptr_in);
replace(stds, "=", " ");
//replace("=", " ", cptr);
if (sscanf(stds.c_str(), SCANFORMAT, log_k) < 1)
{
input_error++;
error_msg("Expecting log k.", CONTINUE);
return (ERROR);
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_t_c_only(const char* cptr_in, LDBLE *t_c)
/* ---------------------------------------------------------------------- */
{
*t_c = 0.0;
std::string stds(cptr_in);
replace(stds, "=", " ");
//replace("=", " ", cptr);
if (sscanf(stds.c_str(), SCANFORMAT, t_c) < 1)
{
input_error++;
error_msg("Expecting numeric value for critical temperature T_c (K)", CONTINUE);
return (ERROR);
}
return OK;
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_p_c_only(const char* cptr, LDBLE * p_c)
/* ---------------------------------------------------------------------- */
{
*p_c = 0.0;
std::string stds(cptr);
replace(stds, "=", " ");
if (sscanf(stds.c_str(), SCANFORMAT, p_c) < 1)
{
input_error++;
error_msg("Expecting numeric value for critical pressure P_c (atm)", CONTINUE);
return (ERROR);
}
return OK;
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_omega_only(const char* cptr, LDBLE *omega)
/* ---------------------------------------------------------------------- */
{
*omega = 0.0;
std::string stds(cptr);
replace(stds, "=", " ");
if (sscanf(stds.c_str(), SCANFORMAT, omega) < 1)
{
input_error++;
error_msg("Expecting numeric value for acentric factor Omega", CONTINUE);
return (ERROR);
}
return OK;
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_aq_species_vm_parms(const char* cptr, LDBLE * delta_v)
/* ---------------------------------------------------------------------- */
{
int j;
/*
* Read supcrt parms and Ionic strength terms
*/
for (j = 0; j < 10; j++)
{
delta_v[j] = 0.0;
}
delta_v[9] = 1.0;
/* Vmax, dmax...
delta_v[10] = 999.0;
delta_v[11] = 1.0; */
j = sscanf(cptr, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT/* SCANFORMAT SCANFORMAT*/ ,
/* a1..a4 */
&(delta_v[0]), &(delta_v[1]), &(delta_v[2]), &(delta_v[3]),
/* wref */
&(delta_v[4]),
/* b_Av */
&(delta_v[5]),
/* c1..c4 */
&(delta_v[6]), &(delta_v[7]), &(delta_v[8]), &(delta_v[9])/*,
//vmP, exP
&(delta_v[10]), &(delta_v[11])*/);
if (j < 1)
{
input_error++;
error_msg("Expecting numeric values for calculating the species molar volume.",
CONTINUE);
return (ERROR);
}
/* multiply with factors. a1 is in cal/mol/bar. a2 in cal/mol, a3, a4 in cal K/mol
41.84004 converts cal/mol/bar to cm3/mol. */
delta_v[0] *= 41.84004e-1;
delta_v[1] *= 41.84004e2;
delta_v[2] *= 41.84004;
delta_v[3] *= 41.84004e4;
/* wref in cal/mol/bar */
delta_v[4] *= 1e5;
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_vm_only(const char* cptr, LDBLE * delta_v, DELTA_V_UNIT * units)
/* ---------------------------------------------------------------------- */
{
int j, l;
char token[MAX_LENGTH];
/*
* Read analytical expression
*/
for (j = 0; j < 9; j++)
{
delta_v[j] = 0.0;
}
j = sscanf(cptr, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT,
&(delta_v[0]), &(delta_v[1]), &(delta_v[2]), &(delta_v[3]),
&(delta_v[4]), &(delta_v[5]), &(delta_v[6]), &(delta_v[7]));
if (j < 1)
{
input_error++;
error_msg("Expecting numeric value for the phase's molar volume, vm.",
CONTINUE);
return (ERROR);
}
/*
* Read delta V units
*/
*units = cm3_per_mol;
do
{
j = copy_token(token, &cptr, &l);
} while (j == DIGIT);
if (j == EMPTY)
{
return (OK);
}
LDBLE factor = 1.0;
if (j == UPPER || j == LOWER)
{
str_tolower(token);
if (strstr(token, "cm3") != NULL)
{
/* cm3/mol */
;
}
else if (strstr(token, "dm3") != NULL)
{
/* Convert dm3/mol to cm3/mol */
factor = 1e3;
}
else if (strstr(token, "m3") != NULL)
{
/* Convert m3/mol to cm3/mol */
factor = 1e6;
}
for (int i = 0; i < 8; i++)
{
delta_v[i] *= factor;
}
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_phase_vm(const char* cptr, LDBLE * delta_v, DELTA_V_UNIT * units)
/* ---------------------------------------------------------------------- */
{
int j, l;
char token[MAX_LENGTH];
/*
* Read analytical expression
*/
for (j = 0; j < 1; j++)
{
delta_v[j] = 0.0;
}
j = sscanf(cptr, SCANFORMAT /*SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT*/,
&(delta_v[0])/*, &(delta_v[1]), &(delta_v[2]), &(delta_v[3]),
&(delta_v[4]), &(delta_v[5]), &(delta_v[6]), &(delta_v[7])*/);
if (j < 1)
{
input_error++;
error_msg("Expecting numeric value for the phase's molar volume, vm.",
CONTINUE);
return (ERROR);
}
/*
* Read delta V units
*/
*units = cm3_per_mol;
do
{
j = copy_token(token, &cptr, &l);
} while (j == DIGIT);
if (j == EMPTY)
{
return (OK);
}
LDBLE factor = 1.0;
if (j == UPPER || j == LOWER)
{
str_tolower(token);
if (strstr(token, "cm3") != NULL)
{
/* cm3/mol */
;
}
else if (strstr(token, "dm3") != NULL)
{
/* Convert dm3/mol to cm3/mol */
factor = 1e3;
*units = dm3_per_mol;
}
else if (strstr(token, "m3") != NULL)
{
/* Convert m3/mol to cm3/mol */
factor = 1e6;
*units = m3_per_mol;
}
for (int i = 0; i < 1; i++)
{
delta_v[i] *= factor;
}
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_delta_h_only(const char* cptr_in, LDBLE * delta_h, DELTA_H_UNIT * units)
/* ---------------------------------------------------------------------- */
{
int j, l, kilo, joul;
char token[MAX_LENGTH];
/*
* Read delta H
*/
*delta_h = 0.0;
std::string stds(cptr_in);
replace(stds, "=", " ");
const char* cptr = stds.c_str();
j = copy_token(token, &cptr, &l);
if (j == EMPTY)
{
input_error++;
error_msg("Expecting numeric value for delta H.", CONTINUE);
return (ERROR);
}
if (sscanf(token, SCANFORMAT, delta_h) < 1)
{
input_error++;
error_msg("Expecting numeric value for delta H.", CONTINUE);
return (ERROR);
}
/*
* Read delta H units
*/
j = copy_token(token, &cptr, &l);
*units = kjoules;
kilo = TRUE;
joul = TRUE;
if (j == EMPTY)
{
return (OK);
}
if (j == UPPER || j == LOWER)
{
str_tolower(token);
if (strstr(token, "k") != token)
{
/* convert to kilo */
kilo = FALSE;
*delta_h /= 1000.;
}
if (strstr(token, "c") != NULL)
{
/* convert to joules */
*delta_h *= JOULES_PER_CALORIE;
joul = FALSE;
}
}
if (kilo == TRUE && joul == TRUE)
{
*units = kjoules;
}
else if (kilo == FALSE && joul == TRUE)
{
*units = joules;
}
else if (kilo == TRUE && joul == FALSE)
{
*units = kcal;
}
else if (kilo == FALSE && joul == FALSE)
{
*units = cal;
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_analytical_expression_only(const char* cptr, LDBLE * log_k)
/* ---------------------------------------------------------------------- */
{
int j;
int num_terms = T_A6 - T_A1 + 1;
/*
* Read analytical expression
*/
for (j = 0; j < num_terms; j++)
{
log_k[j] = 0.0;
}
j = sscanf(cptr, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT,
&(log_k[0]), &(log_k[1]), &(log_k[2]), &(log_k[3]),
&(log_k[4]), &(log_k[5]));
if (j < 1)
{
input_error++;
error_msg("Expecting numeric values for analytical expression.",
CONTINUE);
return (ERROR);
}
return (OK);
}
/* VP: Density Start */
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_millero_abcdef (const char* cptr, LDBLE * abcdef)
/* ---------------------------------------------------------------------- */
{
int j;
/*
* Read a, b, c, d, e, f, and kappa parameters for Millero density model.
*/
for (j = 0; j < 7; j++)
{
abcdef[j] = 0.0;
}
j = sscanf (cptr, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT,
&(abcdef[0]), &(abcdef[1]), &(abcdef[2]), &(abcdef[3]), &(abcdef[4]), &(abcdef[5]), &(abcdef[6]));
if (j < 1)
{
input_error++;
error_msg ("Expecting numeric values for analytical expression.",
CONTINUE);
return (ERROR);
}
return (OK);
}
/* VP: Density End */
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_viscosity_parms(const char* cptr, LDBLE * Jones_Dole)
/* ---------------------------------------------------------------------- */
{
int j;
/*
* Read .
*/
for (j = 0; j <= 9; j++)
{
Jones_Dole[j] = 0.0;
}
j = sscanf (cptr, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT,
&(Jones_Dole[0]), &(Jones_Dole[1]), &(Jones_Dole[2]), &(Jones_Dole[3]), &(Jones_Dole[4]), &(Jones_Dole[5]), &(Jones_Dole[6]), &(Jones_Dole[7]), &(Jones_Dole[8]), &(Jones_Dole[9]));
if (j < 1)
{
input_error++;
error_msg ("Expecting numeric values for viscosity calculation.",
CONTINUE);
return (ERROR);
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_incremental_reactions(void)
/* ---------------------------------------------------------------------- */
{
/*
* Define flow only
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int j, l;
const char* cptr;
char token[MAX_LENGTH];
cptr = line;
/* read keyword */
copy_token(token, &cptr, &l);
/* read true or false */
incremental_reactions = get_true_false(cptr, TRUE);
/*
* find next keyword
*/
while ((j =
check_line("Subroutine Read", FALSE, TRUE, TRUE,
FALSE)) != KEYWORD)
{
/* empty, eof, keyword, print */
if (j == EOF)
return (EOF);
error_string = sformatf( "Unknown input: %s", line);
error_msg(error_string, CONTINUE);
input_error++;
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_master_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads master species data from data file or input file
*/
int j, i, l;
const char* cptr, *cptr1;
LDBLE l_z;
class element *elts_ptr;
class species *s_ptr;
char token[MAX_LENGTH];
elts_ptr = NULL;
for (;;)
{
j = check_line("Master species", FALSE, TRUE, TRUE, TRUE);
if (j == EOF || j == KEYWORD)
{
break;
}
/*
* Get element name with valence, allocate space, store
*/
cptr = line;
/*
* Get element name and save pointer to character string
*/
if (copy_token(token, &cptr, &l) != UPPER && token[0] != '[')
{
parse_error++;
error_msg("Reading element for master species.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
if (token[0] == '[') {
cptr1 = token;
get_elt(&cptr, element, &l);
Utilities::strcpy_safe(token, MAX_LENGTH, element);
}
*/
replace("(+", "(", token);
/*
* Delete master if it exists
*/
master_delete(token);
/*
* Increase pointer array, if necessary, and malloc space
*/
size_t count_master = master.size();
master.resize(count_master + 1);
master[count_master] = master_alloc();
/*
* Set type to AQ
*/
master[count_master]->type = AQ;
/*
* Save element name
*/
master[count_master]->elt = element_store(token);
std::string ename = token;
/*
* Save pointer to species data for master species
*/
if ((copy_token(token, &cptr, &l) != UPPER) &&
token[0] != '[' && (strcmp_nocase_arg1(token, "e-") != 0))
{
parse_error++;
error_msg("Reading master species name.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
s_ptr = s_search(token);
if (s_ptr != NULL)
{
master[count_master]->s = s_ptr;
}
else
{
cptr1 = token;
std::string token1;
get_token(&cptr1, token1, &l_z, &l);
master[count_master]->s = s_store(token1.c_str(), l_z, FALSE);
}
std::string sname = token;
replace("("," ", ename);
std::istringstream iss(ename);
iss >> ename;
if (ename != "e" && ename != "E" && ename != "Alkalinity" && std::string::npos == sname.find(ename))
{
input_error++;
std::ostringstream oss;
oss << "Master species, " << sname << " must contain the element, " << ename;
error_msg(oss.str().c_str(), CONTINUE);
continue;
}
/*
* Read alkalinity for species
*/
copy_token(token, &cptr, &l);
i = sscanf(token, SCANFORMAT, &master[count_master]->alk);
if (i != 1)
{
input_error++;
if (elts_ptr != NULL)
{
error_string = sformatf(
"Expected alkalinity for master species, %s, in master species input.",
elts_ptr->name);
}
else
{
error_string = sformatf(
"Expected alkalinity for master species in master species input.");
}
error_msg(error_string, CONTINUE);
continue;
}
/*
* Read default gfw for species
*/
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, SCANFORMAT, &master[count_master]->gfw);
}
else if (i == UPPER)
{
master[count_master]->gfw_formula = string_hsave(token);
}
else
{
input_error++;
if (elts_ptr != NULL)
{
error_string = sformatf(
"Expected gram formula weight for master species, %s, in master species input.",
elts_ptr->name);
}
else
{
error_string = sformatf(
"Expected gram formula weight for master species in master species input.");
}
error_msg(error_string, CONTINUE);
continue;
}
/*
* MAKE LISTS OF PRIMARY AND SECONDARY MASTER SPECIES
*/
if (strchr(master[count_master]->elt->name, '(') == NULL)
{
master[count_master]->primary = TRUE;
/* Read gram formula weight for primary */
if (strcmp(master[count_master]->elt->name, "E") != 0)
{
elts_ptr = master[count_master]->elt;
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, SCANFORMAT, &elts_ptr->gfw);
}
else
{
input_error++;
if (elts_ptr != NULL)
{
error_string = sformatf(
"Expected gram formula weight for element, %s.",
elts_ptr->name);
}
else
{
error_string = sformatf(
"Expected gram formula weight for element.");
}
error_msg(error_string, CONTINUE);
continue;
}
}
}
else
{
master[count_master]->primary = FALSE;
}
}
gfw_map.clear();
return (j);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_mix(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads mixing fractions
*/
int n_user;
int return_value;
int n_solution;
LDBLE fraction;
int j, i, l;
const char* cptr;
char token[MAX_LENGTH];
cxxMix temp_mix;
cptr = line;
temp_mix.read_number_description(cptr);
n_user = temp_mix.Get_n_user();
/*
* Set use data to first read
*/
if (use.Get_mix_in() == FALSE)
{
use.Set_mix_in(true);
use.Set_n_mix_user(n_user);
}
/*
* Read mixture data
*/
for (;;)
{
return_value = check_line("Mixture data", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
if (return_value == EOF || return_value == KEYWORD)
{
break;
}
cptr = line;
/*
* Read n_user
*/
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, "%d ", &n_solution);
}
else
{
input_error++;
error_msg("Expected a solution number in mix input.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
* Read fraction for solution
*/
copy_token(token, &cptr, &l);
j = sscanf(token, SCANFORMAT, &fraction);
if (j != 1)
{
input_error++;
error_msg("Expected a mixing fraction.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
* Save data
*/
temp_mix.Add(n_solution ,fraction);
}
if (temp_mix.Get_mixComps().size() == 0)
{
input_error++;
error_msg
("Must define at least one solution number and mixing fraction for MIX input.",
CONTINUE);
}
Rxn_mix_map[n_user] = temp_mix;
// copy if needed
if (temp_mix.Get_n_user_end() > n_user)
{
int i;
for (i = n_user + 1; i <= temp_mix.Get_n_user_end(); i++)
{
Utilities::Rxn_copy(Rxn_mix_map, n_user, i);
}
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_entity_mix(std::map<int, cxxMix> &mix_map)
/* ---------------------------------------------------------------------- */
{
/*
* Reads mixing fractions
*/
int return_value;
int n_solution;
LDBLE fraction;
int j, i, l;
const char* cptr;
char token[MAX_LENGTH];
cxxMix temp_mix;
/*
* Read mix number
*/
cptr = line;
temp_mix.read_number_description(line);
/*
* Read mixture data
*/
for (;;)
{
return_value = check_line("Mix raw data", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
if (return_value == EOF || return_value == KEYWORD)
{
break;
}
cptr = line;
/*
* Read n_user
*/
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, "%d ", &n_solution);
}
else
{
input_error++;
error_msg("Expected a number in mix input.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
* Read fraction for entity
*/
copy_token(token, &cptr, &l);
j = sscanf(token, SCANFORMAT, &fraction);
if (j != 1)
{
input_error++;
error_msg("Expected a mixing fraction.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
/*
* Save data
*/
temp_mix.Add(n_solution ,fraction);
}
if (temp_mix.Get_mixComps().size() == 0)
{
input_error++;
error_msg
("Must define at least one number and mixing fraction for mix input.",
CONTINUE);
}
mix_map[temp_mix.Get_n_user()] = temp_mix;
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_number_description(const char* cptr, int *n_user,
int *n_user_end, char **description, int allow_negative)
/* ---------------------------------------------------------------------- */
{
int l, n;
char token[MAX_LENGTH];
const char* cptr1;
/*
* Read user number, allow negative numbers Oct 3, 2011
*/
copy_token(token, &cptr, &l); // keyword
cptr1 = cptr;
copy_token(token, &cptr, &l);
if (!isdigit(token[0]) && token[0] != '-')
{
*n_user = 1;
*n_user_end = 1;
}
else
{
if (replace("-", " ", &token[1]))
{
n = sscanf(token, "%d%d", n_user, n_user_end);
if (n != 2)
{
if (n == 0)
{
*n_user_end = *n_user = 1;
}
else
{
*n_user_end = *n_user;
}
if (next_keyword >= 0)
{
error_string = sformatf( "Reading number range for %s.", Keywords::Keyword_name_search(next_keyword).c_str());
}
else
{
error_string = sformatf( "Reading number range for keyword.");
}
error_msg(error_string, CONTINUE);
input_error++;
}
cptr1 = cptr;
}
else
{
n = sscanf(token, "%d", n_user);
if (n != 1)
{
if (next_keyword >= 0)
{
error_string = sformatf( "Reading number range for %s.", Keywords::Keyword_name_search(next_keyword).c_str());
}
else
{
error_string = sformatf( "Reading number range for keyword.");
}
error_msg(error_string, CONTINUE);
input_error++;
}
*n_user_end = *n_user;
cptr1 = cptr;
};
}
if (*n_user < 0 && allow_negative == FALSE)
{
error_string = sformatf( "Negative number in number range not allowed for keyword.");
error_msg(error_string, CONTINUE);
input_error++;
}
/*
* Read description
*/
for (; isspace((int) cptr1[0]); cptr1++);
*description = string_duplicate(cptr1);
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_phases(void)
/* ---------------------------------------------------------------------- */
{
/*
* Read data for phases, parse equations
*/
int j, i, l;
int association;
const char* cptr;
char token[MAX_LENGTH];
char token1[MAX_LENGTH];
class phase *phase_ptr;
class rxn_token *token_ptr;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"no_check", /* 0 */
"check", /* 1 */
"log_k", /* 2 */
"logk", /* 3 */
"delta_h", /* 4 */
"deltah", /* 5 */
"analytical_expression", /* 6 */
"a_e", /* 7 */
"ae", /* 8 */
"add_logk", /* 9 */
"add_log_k", /* 10 */
"add_constant", /* 11 */
"t_c", /* 12 */
"p_c", /* 13 */
"omega", /* 14 */
"vm" /* 15, molar volume, must replace delta_v */
};
int count_opt_list = 16;
association = FALSE;
/*
* Read eqn from file and call parser
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
phase_ptr = NULL;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in PHASES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* no_check */
if (phase_ptr == NULL)
break;
phase_ptr->check_equation = FALSE;
break;
case 1: /* check */
if (phase_ptr == NULL)
break;
phase_ptr->check_equation = TRUE;
break;
case 2: /* log_k */
case 3: /* logk */
if (phase_ptr == NULL)
break;
read_log_k_only(next_char, &phase_ptr->logk[0]);
opt_save = OPTION_DEFAULT;
break;
case 4: /* delta_h */
case 5: /* deltah */
if (phase_ptr == NULL)
break;
read_delta_h_only(next_char, &phase_ptr->logk[1],
&phase_ptr->original_units);
opt_save = OPTION_DEFAULT;
break;
case 6: /* analytical_expression */
case 7: /* a_e */
case 8: /* ae */
if (phase_ptr == NULL)
break;
read_analytical_expression_only(next_char, &(phase_ptr->logk[T_A1]));
opt_save = OPTION_DEFAULT;
break;
case 9: /* add_logk */
case 10: /* add_log_k */
{
if (phase_ptr == NULL)
break;
size_t count_add_logk = phase_ptr->add_logk.size();
phase_ptr->add_logk.resize(count_add_logk + 1);
/* read name */
if (copy_token(token, &next_char, &i) == EMPTY)
{
input_error++;
error_string = sformatf(
"Expected the name of a NAMED_EXPRESSION.");
error_msg(error_string, CONTINUE);
break;
}
phase_ptr->add_logk[count_add_logk].name =
string_hsave(token);
/* read coef */
i = sscanf(next_char, SCANFORMAT,
&phase_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
phase_ptr->add_logk[count_add_logk].coef = 1;
}
opt_save = OPTION_DEFAULT;
}
break;
case 11: /* add_constant */
{
if (phase_ptr == NULL)
break;
size_t count_add_logk = phase_ptr->add_logk.size();
phase_ptr->add_logk.resize(count_add_logk + 1);
i = sscanf(next_char, SCANFORMAT,
&phase_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
input_error++;
error_string = sformatf(
"Expected the constant to add for log_K definition.");
error_msg(error_string, CONTINUE);
break;
}
/* set name */
phase_ptr->add_logk[count_add_logk].name =
string_hsave("XconstantX");
opt_save = OPTION_DEFAULT;
}
break;
case 12: /* T_c */
if (phase_ptr == NULL)
break;
read_t_c_only(next_char, &phase_ptr->t_c);
opt_save = OPTION_DEFAULT;
break;
case 13: /* P_c */
if (phase_ptr == NULL)
break;
read_p_c_only(next_char, &phase_ptr->p_c);
opt_save = OPTION_DEFAULT;
break;
case 14: /* Omega */
if (phase_ptr == NULL)
break;
read_omega_only(next_char, &phase_ptr->omega);
opt_save = OPTION_DEFAULT;
break;
case 15: /* vm, molar volume */
if (phase_ptr == NULL)
break;
read_phase_vm(next_char, &(phase_ptr->logk[vm0]),
&phase_ptr->original_deltav_units);
phase_ptr->delta_v[1] = phase_ptr->logk[vm0];
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT:
{
/*
* Get element name and save pointer to character string
*/
phase_ptr = NULL;
cptr = line;
copy_token(token, &cptr, &l);
/*
* Get and parse equation
*/
j = check_line("Phase equation", FALSE, TRUE, TRUE, TRUE);
if (j == EOF || j == KEYWORD)
{
return_value = j;
break;
}
if (j == OPTION)
{
parse_error++;
error_string = sformatf("Expecting equation for phase %s.", token);
error_msg(error_string, CONTINUE);
error_msg("Parsing equation.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
std::vector<class elt_list> new_elt_list;
if (parse_eq(line, new_elt_list, association) == ERROR)
{
parse_error++;
error_msg("Parsing equation.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
phase_ptr = phase_store(token);
/*
* Get pointer to each species in the reaction, store new species if necessary
*/
Utilities::strcpy_safe(token1, MAX_LENGTH, trxn.token[0].name);
replace("(g)", "", token1);
replace("(s)", "", token1);
replace("(G)", "", token1);
replace("(S)", "", token1);
phase_ptr->formula = string_hsave(token1);
for (i = 1; i < count_trxn; i++)
{
if ((strstr(trxn.token[i].name, "(s)") == NULL) &&
(strstr(trxn.token[i].name, "(g)") == NULL) &&
(strstr(trxn.token[i].name, "(S)") == NULL) &&
(strstr(trxn.token[i].name, "(G)") == NULL))
{
Utilities::strcpy_safe(token1, MAX_LENGTH, trxn.token[i].name);
replace("(aq)", "", token1);
replace("(AQ)", "", token1);
replace("H2O(l)", "H2O", token1);
replace("(H2O(L)", "H2O", token1);
trxn.token[i].s = s_store(token1, trxn.token[i].z, FALSE);
}
else
{
trxn.token[i].s = NULL;
}
}
/*
* Save element list
*/
phase_ptr->next_elt = new_elt_list;
/*
* Copy reaction to reaction for phase, first token (token[0]) is not used
* except to check that coef of phase formula = 1.0
*/
trxn_copy(phase_ptr->rxn);
token_ptr = &phase_ptr->rxn.token[0];
token_ptr[0].name = trxn.token[1].name;
token_ptr[i].s = NULL;
token_ptr[i].name = NULL;
/*
* Set type for phase
*/
phase_ptr->type = SOLID;
opt_save = OPTION_DEFAULT;
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_pp_assemblage(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads pp_assemblage data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int j;
int return_value;
int n_user;
const char* cptr;
std::string token;
int opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"force_equality" /* 0 */
};
int count_opt_list = 1;
/*
* Find pp_assemblage or realloc space for pp_assemblage
*/
cxxPPassemblage temp_pp_assemblage;
cptr = line;
temp_pp_assemblage.read_number_description(cptr);
n_user = temp_pp_assemblage.Get_n_user();
cxxPPassemblageComp *comp = NULL;
std::map<std::string, cxxPPassemblageComp> comps;
temp_pp_assemblage.Set_new_def(true);
/*
* Set use data to first read
*/
if (use.Get_pp_assemblage_in() == FALSE)
{
use.Set_pp_assemblage_in(true);
use.Set_n_pp_assemblage_user(n_user);
}
/*
* Read equilibrium phase data
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in EQUILIBRIUM_PHASES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* force_equality */
if (comp == NULL)
{
error_msg
("Force_equality defined before equilibrium phase has been defined.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
else
{
comp->Set_force_equality(get_true_false(next_char, TRUE) == TRUE);
}
break;
case OPTION_DEFAULT:
/*
* Make space, set default
*/
if (comp)
{
comps[comp->Get_name()] = *comp;
}
delete comp;
comp = new cxxPPassemblageComp;
/*
* Read name
*/
cptr = line;
copy_token(token, &cptr);
comp->Set_name(token.c_str());
if ((j = copy_token(token, &cptr)) == EMPTY)
continue;
/*
* Read saturation index
*/
j = sscanf(token.c_str(), SCANFORMAT, &dummy);
comp->Set_si(dummy);
comp->Set_si_org(dummy);
if (j != 1)
{
error_msg("Expected saturation index.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
continue;
}
/*
* Adding a reaction to the phase boundary
*/
if ((j = copy_token(token, &cptr)) == EMPTY)
continue;
if (j == UPPER || j == LOWER)
{
comp->Set_add_formula(token.c_str());
j = copy_token(token, &cptr);
}
/*
* Read amount
*/
if (j == EMPTY)
continue;
j = sscanf(token.c_str(), SCANFORMAT, &dummy);
if (dummy < 0)
{
error_string = sformatf( "Moles of mineral < 0, reset to 0.");
dummy = 0;
warning_msg(error_string);
}
comp->Set_moles(dummy);
if (j != 1)
{
error_msg("Expected amount of mineral.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
continue;
}
if ((j = copy_token(token, &cptr)) == EMPTY)
continue;
Utilities::str_tolower(token);
if (strstr(token.c_str(), "d") == token.c_str())
{
comp->Set_dissolve_only(true);
comp->Set_precipitate_only(false);
} else if (strstr(token.c_str(), "p") == token.c_str())
{
comp->Set_precipitate_only(true);
comp->Set_dissolve_only(false);
}
else
{
error_msg
("Unexpected data at end of equilibrium-phase definition.",
CONTINUE);
input_error++;
continue;
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
if (comp)
{
comps[comp->Get_name()] = *comp;
delete comp;
comp = NULL;
}
temp_pp_assemblage.Set_pp_assemblage_comps(comps);
Rxn_pp_assemblage_map[n_user] = temp_pp_assemblage;
Rxn_new_pp_assemblage.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_reaction(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads reaction data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
/*
* Read reaction
*/
int l;
const char* cptr;
char token[MAX_LENGTH];
int return_value;
int n_user;
/*
* Defaults
*/
cxxReaction temp_reaction;
cptr = line;
temp_reaction.read_number_description(cptr);
n_user = temp_reaction.Get_n_user();
/*
* Set use data to first read
*/
if (use.Get_reaction_in() == FALSE)
{
use.Set_reaction_in(true);
use.Set_n_reaction_user(n_user);
}
/*
* Read reaction data
*/
for (;;)
{
/*
* Read line
*/
return_value = check_line("Reaction data", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
if (return_value == EOF || return_value == KEYWORD)
{
break;
}
cptr = line;
copy_token(token, &cptr, &l);
if (isalpha((int) token[0]) || (token[0] == '(') || (token[0] == '['))
{
/*
* Read reactant information
*/
read_reaction_reactants(&temp_reaction);
}
else
{
/*
* Read steps information
*/
read_reaction_steps(&temp_reaction);
}
}
/*
* Default 1 mol of reaction
*/
if (temp_reaction.Get_steps().size() == 0)
{
std::vector<LDBLE> v;
v.push_back(1.0);
temp_reaction.Set_steps(v);
}
if (temp_reaction.Get_equalIncrements())
{
if (temp_reaction.Get_countSteps() == 0)
{
temp_reaction.Set_countSteps(1);
}
}
Rxn_reaction_map[n_user] = temp_reaction;
// copy if needed
Utilities::Rxn_copies(Rxn_reaction_map, n_user, temp_reaction.Get_n_user_end());
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_reaction_reactants(cxxReaction *reaction_ptr)
/* ---------------------------------------------------------------------- */
{
/*
* Read reactants, may be a chemical formula or a pure_phase name
* followed by relative reaction coefficient, default 1.0.
*
*/
std::string token, last_token;
LDBLE coef;
const char* cptr;
/*
* Read one or more reactants
*/
cptr = line;
while (copy_token(token, &cptr) != EMPTY)
{
/*
* Store reactant name, default coefficient
*/
if (isalpha((int) token[0]) || (token[0] == '(') || (token[0] == '['))
{
reaction_ptr->Get_reactantList()[token] = 1.0;
last_token = token;
/*
* Store relative coefficient
*/
}
else
{
int j = sscanf(token.c_str(), SCANFORMAT, &coef);
if (j == 1 && last_token.size() > 0)
{
reaction_ptr->Get_reactantList()[last_token] = coef;
}
else
{
error_msg("Reading relative coefficient of reactant.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_reaction_steps(cxxReaction *reaction_ptr)
/* ---------------------------------------------------------------------- */
{
/*
* Read amount(s) of irrev reactions in one of three forms:
*
* 6 millimoles in 6 steps or
*
* 1 2 3 4 5 6 millimoles or
*
* 6*1 millimoles
* INCREMENTAL_REACTIONS
*/
const char* cptr;
std::string token, token1;
cptr = line;
/*
* Read one or more reaction increments
*/
for (;;)
{
if (copy_token(token, &cptr) == EMPTY)
{
return (OK);
}
/*
* Read next step increment
*/
/* begin modif 29 july 2005... */
if (replace("*", " ", token))
{
int n;
LDBLE value;
if (sscanf(token.c_str(), "%d" SCANFORMAT, &n, &value) == 2)
{
for (int i = 0; i < n; i++)
{
reaction_ptr->Get_steps().push_back(value);
}
}
else
{
input_error++;
error_msg
("Format error in multiple, equal REACTION steps.\nCorrect is (for example): 0.2 4*0.1 2*0.5 0.3\n",
CONTINUE);
}
}
else
{
LDBLE step;
int j = sscanf(token.c_str(), SCANFORMAT, &step);
if (j == 1)
{
reaction_ptr->Get_steps().push_back(step);
}
else
{
break;
}
}
/* ...end modif 29 july 2005 */
}
/*
* Read units
*/
token1 = token;
token1.append("/l");
std::string t1 = token1;
if (check_units(t1, false, false, NULL, false) == OK)
{
replace("/l", "", t1);
if (strstr(t1.c_str(), "Mol") == NULL)
{
error_string = sformatf( "Units of steps not in moles, %s.", token.c_str());
error_msg(error_string, CONTINUE);
input_error++;
return (ERROR);
}
else
{
reaction_ptr->Set_units(t1.c_str());
}
if (copy_token(token, &cptr) == EMPTY)
{
return (OK);
}
}
/*
* Read number of equal increments, store as negative integer
*/
if (reaction_ptr->Get_reaction_steps() != 1)
{
error_msg
("To define equal increments, only one reaction increment should be defined.",
CONTINUE);
input_error++;
return (ERROR);
}
do
{
int i;
int j = sscanf(token.c_str(), "%d", &i);
if (j == 1 && i > 0)
{
reaction_ptr->Set_countSteps(i);
reaction_ptr->Set_equalIncrements(true);
return (OK);
}
else if (j == 1 && i <= 0)
{
break;
}
}
while (copy_token(token, &cptr) != EMPTY);
error_msg("Expecting positive number for number of equal "
"increments to add.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_save(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads solution, mix, irreversible reaction, and pure phases to use
* in reaction calculation
*/
int i, l, n, n_user, n_user_end;
const char* cptr;
char token[MAX_LENGTH];
/*
* Read "save"
*/
cptr = line;
copy_token(token, &cptr, &l);
/*
* Read keyword
*/
copy_token(token, &cptr, &l);
check_key(token);
/*
* Read number
*/
for (;;)
{
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
replace("-", " ", token);
n = sscanf(token, "%d%d", &n_user, &n_user_end);
if (n == 1)
{
n_user_end = n_user;
}
if (n_user < 0)
{
error_msg("Number must be a positive integer.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
break;
}
else if (i == EMPTY)
{
error_string = sformatf( "No number given, 1 assumed.");
warning_msg(error_string);
n_user = 1;
n_user_end = 1;
break;
}
}
switch (next_keyword)
{
case Keywords::KEY_SOLUTION: /* Solution */
save.solution = TRUE;
save.n_solution_user = n_user;
save.n_solution_user_end = n_user_end;
break;
case Keywords::KEY_EQUILIBRIUM_PHASES: /* Pure phases */
save.pp_assemblage = TRUE;
save.n_pp_assemblage_user = n_user;
save.n_pp_assemblage_user_end = n_user_end;
break;
case Keywords::KEY_EXCHANGE: /* exchange */
save.exchange = TRUE;
save.n_exchange_user = n_user;
save.n_exchange_user_end = n_user_end;
break;
case Keywords::KEY_SURFACE: /* surface */
save.surface = TRUE;
save.n_surface_user = n_user;
save.n_surface_user_end = n_user_end;
break;
case Keywords::KEY_GAS_PHASE: /* gas_phase */
save.gas_phase = TRUE;
save.n_gas_phase_user = n_user;
save.n_gas_phase_user_end = n_user_end;
break;
case Keywords::KEY_SOLID_SOLUTIONS: /* solid_solutions */
save.ss_assemblage = TRUE;
save.n_ss_assemblage_user = n_user;
save.n_ss_assemblage_user_end = n_user_end;
break;
default:
input_error++;
error_msg
("Expecting keyword solution, equilibrium_phases, exchange, surface, gas_phase, or solid_solutions.",
CONTINUE);
error_msg(line_save, CONTINUE);
check_line("End of save", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (ERROR);
}
check_line("End of save", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_selected_output(void)
/* ---------------------------------------------------------------------- */
{
/*
* Read data for to output to flat file
*/
int value;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"file", /* 0 */
"totals", /* 1 */
"molalities", /* 2 */
"activities", /* 3 */
"pure_phases", /* 4 */
"si", /* 5 */
"saturation_indices", /* 6 */
"gases", /* 7 */
"equilibrium_phases", /* 8 */
"equilibria", /* 9 */
"equilibrium", /* 10 */
"pure", /* 11 */
"inverse", /* 12 */
"kinetic_reactants", /* 13 */
"kinetics", /* 14 */
"solid_solutions", /* 15 */
"inverse_modeling", /* 16 */
"reset", /* 17 */
"simulation", /* 18 */
"sim", /* 19 */
"state", /* 20 */
"solution", /* 21 */
"soln", /* 22 */
"distance", /* 23 */
"dist", /* 24 */
"time", /* 25 */
"step", /* 26 */
"reaction", /* 27 */
"rxn", /* 28 */
"temperature", /* 29 */
"temp", /* 30 */
"ph", /* 31 */
"pe", /* 32 */
"alkalinity", /* 33 */
"alk", /* 34 */
"ionic_strength", /* 35 */
"mu", /* 36 */
"water", /* 37 */
"high_precision", /* 38 */
"user_punch", /* 39 */
"mol", /* 40 */
"kin", /* 41 */
"charge_balance", /* 42 */
"percent_error", /* 43 */
"selected_out", /* 44 */
"selected_output", /* 45 */
"isotopes", /* 46 */
"calculate_values", /* 47 */
"equilibrium_phase", /* 48 */
"active", /* 49 */
"new_line" /* 50 */
};
int count_opt_list = 51;
int i, l;
char token[MAX_LENGTH];
std::string file_name;
const char* cptr;
int n_user;
SelectedOutput temp_selected_output;
cptr = line;
temp_selected_output.read_number_description(cptr);
n_user = temp_selected_output.Get_n_user();
temp_selected_output.Set_new_def(false);
temp_selected_output.Set_file_name(n_user);
// find if it exists
std::map< int, SelectedOutput >::iterator so = SelectedOutput_map.find(n_user);
if (n_user == 1 && so != SelectedOutput_map.end())
{
// n_user = 1, old definition, keep old definition
SelectedOutput & so_ref = so->second;
temp_selected_output.Set_active ( so_ref.Get_active() );
temp_selected_output.Set_new_line ( so_ref.Get_new_line() );
temp_selected_output.Set_inverse ( so_ref.Get_inverse() );
temp_selected_output.Set_sim ( so_ref.Get_sim() );
temp_selected_output.Set_state ( so_ref.Get_state() );
temp_selected_output.Set_soln ( so_ref.Get_soln() );
temp_selected_output.Set_dist ( so_ref.Get_dist() );
temp_selected_output.Set_time ( so_ref.Get_time() );
temp_selected_output.Set_step ( so_ref.Get_step() );
temp_selected_output.Set_rxn ( so_ref.Get_rxn() );
temp_selected_output.Set_temp ( so_ref.Get_temp() );
temp_selected_output.Set_ph ( so_ref.Get_ph() );
temp_selected_output.Set_pe ( so_ref.Get_pe() );
temp_selected_output.Set_alk ( so_ref.Get_alk() );
temp_selected_output.Set_mu ( so_ref.Get_mu() );
temp_selected_output.Set_water ( so_ref.Get_water() );
temp_selected_output.Set_high_precision ( so_ref.Get_high_precision() );
temp_selected_output.Set_user_punch ( so_ref.Get_user_punch() );
temp_selected_output.Set_charge_balance ( so_ref.Get_charge_balance() );
temp_selected_output.Set_percent_error ( so_ref.Get_percent_error() );
temp_selected_output.Set_have_punch_name ( so_ref.Get_have_punch_name() );
temp_selected_output.Set_file_name ( so_ref.Get_file_name() );
}
else if (n_user == 1 && so == SelectedOutput_map.end())
{
// n_user = 1, new definition, do nothing use; constructor default
temp_selected_output.Set_new_def(true);
}
else
{
// n_user != 1 then reset false
temp_selected_output.Reset(false);
if (so == SelectedOutput_map.end())
{
temp_selected_output.Set_new_def(true);
}
}
CParser parser(this->phrq_io);
/*
* Read eqn from file and call parser
*/
opt_save = OPTION_ERROR;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = opt;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SELECTED_OUTPUT keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* file name */
{
temp_selected_output.Set_new_def(true);
std::string temp_name(next_char);
string_trim(temp_name);
if (temp_name.size() > 0)
{
file_name = temp_name;
temp_selected_output.Set_file_name(file_name);
temp_selected_output.Set_have_punch_name(true);
}
opt_save = OPTION_ERROR;
}
break;
case 1: /* totals */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
if (i != UPPER && token[0] != '[')
{
error_string = sformatf( "Expected element name to"
" begin with upper case letter.");
warning_msg(error_string);
}
else
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_totals().push_back(t_pair);
}
}
break;
case 2: /* molalities */
case 40: /* mol */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
if (i != UPPER && token[0] != '(' && (token[0] != '['))
{
error_string = sformatf( "Expected species name to"
" begin with upper case letter.");
warning_msg(error_string);
}
else
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_molalities().push_back(t_pair);
}
}
break;
case 3: /* activities */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
if (i != UPPER && token[0] != '(' && (token[0] != '['))
{
error_string = sformatf( "Expected species name to"
" begin with upper case letter.");
warning_msg(error_string);
}
else
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_activities().push_back(t_pair);
}
}
break;
case 4: /* pure_phases */
case 8: /* equilibrium_phases */
case 9: /* equilibria */
case 10: /* equilibrium */
case 11: /* pure */
case 48: /* equilibrium_phase */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_pure_phases().push_back(t_pair);
}
break;
case 5: /* si */
case 6: /* saturation_index */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_si().push_back(t_pair);
}
break;
case 7: /* gases */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_gases().push_back(t_pair);
}
break;
case 12: /* inverse */
case 16: /* inverse_modeling */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_inverse(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 13: /* kinetic_reactants */
case 14: /* kinetics */
case 41: /* kin */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_kinetics().push_back(t_pair);
}
break;
case 15: /* solid_solutions */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_s_s().push_back(t_pair);
}
break;
case 46: /* isotopes */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
if (i != UPPER && token[0] != '[')
{
error_string = sformatf( "Expected element name to"
" begin with upper case letter.");
warning_msg(error_string);
}
else
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_isotopes().push_back(t_pair);
}
}
break;
case 47: /* calculate_values */
temp_selected_output.Set_new_def(true);
while ((i = copy_token(token, &next_char, &l)) != EMPTY)
{
std::pair< std::string, void *> t_pair(token, ((void *)0));
temp_selected_output.Get_calculate_values().push_back(t_pair);
}
break;
case 17: /* reset */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
/* matches print order */
temp_selected_output.Reset(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 18: /* simulation */
case 19: /* sim */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_sim(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 20: /* state */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_state(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 21: /* solution */
case 22: /* soln */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_soln(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 23: /* distance */
case 24: /* dist */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_dist(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 25: /* time */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_time(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 26: /* step */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_step(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 27: /* reaction */
case 28: /* rxn */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_rxn(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 29: /* temperature */
case 30: /* temp */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_temp(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 31: /* ph */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_ph(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 32: /* pe */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_pe(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 33: /* alkalinity */
case 34: /* alk */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_alk(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 35: /* ionic strength */
case 36: /* mu */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_mu(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 37: /* water */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_water(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 38: /* high_precision */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_high_precision(value!=FALSE);
//if (n_user == 1)
//{
// high_precision = (value != FALSE);
//}
if (value == TRUE)
{
convergence_tolerance = 1e-12;
}
opt_save = OPTION_ERROR;
break;
case 39: /* user_punch */
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_user_punch(value!=FALSE);
if (so != SelectedOutput_map.end())
{
so->second.Set_user_punch(value!=FALSE);
} opt_save = OPTION_ERROR;
break;
case 42: /* charge_balance */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_charge_balance(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 43: /* percent_error */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_percent_error(value!=FALSE);
opt_save = OPTION_ERROR;
break;
case 44: /* selected_out */
case 45: /* selected_output */
//warning_msg("Use PRINT; -selected_output, not SELECTED_OUTPUT; -selected_output");
//value = get_true_false(next_char, TRUE);
//temp_selected_output.Set_active(value!=FALSE);
//opt_save = OPTION_ERROR;
//break;
case 49: /* active */
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_active(value!=FALSE);
if (so != SelectedOutput_map.end())
{
so->second.Set_active(value!=FALSE);
}
opt_save = OPTION_ERROR;
break;
case 50: /* new_line */
temp_selected_output.Set_new_def(true);
value = get_true_false(next_char, TRUE);
temp_selected_output.Set_new_line(value != FALSE);
opt_save = OPTION_ERROR;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
if (temp_selected_output.Get_new_def() || so == SelectedOutput_map.end())
{
// delete if exists
if (so != SelectedOutput_map.end())
{
SelectedOutput_map.erase(so);
}
// store new selected output
SelectedOutput_map[n_user] = temp_selected_output;
if (punch_open(SelectedOutput_map[n_user].Get_file_name().c_str(), n_user))
{
if (phrq_io)
{
SelectedOutput_map[n_user].Set_punch_ostream(phrq_io->Get_punch_ostream());
phrq_io->Set_punch_ostream(NULL);
}
}
else
{
error_string = sformatf( "Can`t open file, %s.", SelectedOutput_map[n_user].Get_file_name().c_str());
input_error++;
error_msg(error_string, CONTINUE);
}
}
//if (!have_punch_name)
//{
// punch_close();
// if (!punch_open("selected.out"))
// {
// error_string = sformatf( "Can`t open file, %s.", "selected.out");
// input_error++;
// error_msg(error_string, CONTINUE);
// }
//}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_solution(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads solution data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int n_user;
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"temp", /* 0 */
"temperature", /* 1 */
"dens", /* 2 */
"density", /* 3 */
"units", /* 4 */
"redox", /* 5 */
"ph", /* 6 */
"pe", /* 7 */
"unit", /* 8 */
"isotope", /* 9 */
"water", /* 10 */
"press", /* 11 */
"pressure", /* 12 */
"potential" /* 13 */
};
int count_opt_list = 14;
cxxSolution temp_solution;
const char* cptr = line;
temp_solution.read_number_description(cptr);
n_user = temp_solution.Get_n_user();
temp_solution.Set_new_def(true);
temp_solution.Create_initial_data();
cxxISolution *isoln_ptr = temp_solution.Get_initial_data();
CParser parser(this->phrq_io);
if (!use.Get_solution_in())
{
use.Set_solution_in(true);
use.Set_n_solution_user(n_user);
}
/*
* Read concentration data
*/
std::string token;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
cptr = next_char;
if (copy_token(token, &cptr) == CParser::TT_DIGIT)
{
opt = 9;
}
}
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SOLUTION keyword.", PHRQ_io::OT_CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* temperature */
case 1:
if (sscanf(next_char, SCANFORMAT, &dummy) == 1)
{
temp_solution.Set_tc(dummy);
}
break;
case 2: /* density */
case 3:
{
copy_token(token, &next_char);
if (sscanf(token.c_str(), SCANFORMAT, &dummy) != 1)
{
error_msg("Expecting numeric value for density.", PHRQ_io::OT_CONTINUE);
error_msg(line_save, PHRQ_io::OT_CONTINUE);
input_error++;
}
else
{
temp_solution.Set_density(dummy);
}
int j = copy_token(token, &next_char);
if (j != EMPTY)
{
if (token[0] != 'c' && token[0] != 'C')
{
error_msg("Only option following density is c[alculate].", PHRQ_io::OT_CONTINUE);
error_msg(line_save, PHRQ_io::OT_CONTINUE);
input_error++;
}
else
{
isoln_ptr->Set_calc_density(true);
}
}
}
break;
case 4: /* units */
case 8: /* unit */
if (copy_token(token, &next_char) == CParser::TT_EMPTY)
break;
{
if (check_units(token, false, false, "mMol/kgw", false) == CParser::PARSER_OK)
{
isoln_ptr->Set_units(token);
}
else
{
input_error++;
}
}
break;
case 5: /* redox */
if (copy_token(token, &next_char) == CParser::TT_EMPTY)
break;
if (parser.parse_couple(token) == CParser::PARSER_OK)
{
const char * str = string_hsave(token.c_str());
//isoln_ptr->Set_default_pe(token);
isoln_ptr->Set_default_pe(str);
CReaction temp_chem_reaction;
isoln_ptr->Get_pe_reactions()[token] = temp_chem_reaction;
}
else
{
input_error++;
}
break;
case 6: /* ph */
{
cxxISolutionComp temp_comp(this->phrq_io);
if (temp_comp.read(line, &temp_solution) == CParser::PARSER_ERROR)
{
input_error++;
break;
}
temp_solution.Set_ph(temp_comp.Get_input_conc());
if (temp_comp.Get_equation_name().size() == 0)
{
break;
}
temp_comp.Set_description("H(1)");
isoln_ptr->Get_comps()[temp_comp.Get_description()] = temp_comp;
}
break;
case 7: /* pe */
{
cxxISolutionComp temp_comp(this->phrq_io);
if (temp_comp.read(line, &temp_solution) == CParser::PARSER_ERROR)
{
input_error++;
break;
}
temp_solution.Set_pe(temp_comp.Get_input_conc());
if (temp_comp.Get_equation_name().size() == 0)
{
break;
}
temp_comp.Set_description("E");
isoln_ptr->Get_comps()[temp_comp.Get_description()] = temp_comp;
}
break;
case 9: /* isotope */
{
cxxSolutionIsotope temp_isotope;
if (copy_token(token, &next_char) != CParser::TT_DIGIT)
{
input_error++;
error_string = sformatf( "Expected isotope name to"
" begin with an isotopic number.");
error_msg(error_string, PHRQ_io::OT_CONTINUE);
error_string = sformatf( "In read_solution\n");
error_msg(error_string, PHRQ_io::OT_CONTINUE);
error_string = sformatf( "\t%s\t%s\n", "token: ", token.c_str());
error_msg(error_string, PHRQ_io::OT_CONTINUE);
error_string = sformatf( "\t%s\t%s\n", "next_char: ", next_char);
error_msg(error_string, PHRQ_io::OT_CONTINUE);
error_string = sformatf( "\t%s\t%s\n", "line_save: ", line_save);
error_msg(error_string, PHRQ_io::OT_CONTINUE);
continue;
}
temp_isotope.Set_isotope_name(token.c_str());
/* read and save element name */
{
std::string temp_iso_name = token.c_str();
const char* cptr1 = temp_iso_name.c_str();
get_num(&cptr1, &dummy);
temp_isotope.Set_isotope_number(dummy);
if (cptr1[0] == '\0' || isupper((int) cptr1[0]) == FALSE)
{
error_msg("Expecting element name.", PHRQ_io::OT_CONTINUE);
error_msg(line_save, PHRQ_io::OT_CONTINUE);
input_error++;
return (CParser::PARSER_ERROR);
}
temp_isotope.Set_elt_name(cptr1);
}
/* read and store isotope ratio */
if (copy_token(token, &next_char) != CParser::TT_DIGIT)
{
input_error++;
error_string = sformatf(
"Expected numeric value for isotope ratio.");
error_msg(error_string, CONTINUE);
continue;
}
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_isotope.Set_ratio(dummy);
temp_isotope.Set_ratio_uncertainty(NAN);
/* read and store isotope ratio uncertainty */
int j;
if ((j = copy_token(token, &next_char)) != CParser::TT_EMPTY)
{
if (j != DIGIT)
{
input_error++;
error_string = sformatf(
"Expected numeric value for uncertainty in isotope ratio.");
error_msg(error_string, PHRQ_io::OT_CONTINUE);
continue;
}
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_isotope.Set_ratio_uncertainty(dummy);
temp_isotope.Set_ratio_uncertainty_defined(true);
}
temp_solution.Get_isotopes()[temp_isotope.Get_isotope_name()] = temp_isotope;
}
break;
case 10: /* water */
{
int j = copy_token(token, &next_char);
if (j == EMPTY)
{
temp_solution.Set_mass_water(1.0);
}
else if (j != DIGIT)
{
input_error++;
error_string = sformatf(
"Expected numeric value for mass of water in solution.");
error_msg(error_string, CONTINUE);
}
else
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_solution.Set_mass_water(dummy);
}
}
break;
case 11: /* pressure */
case 12:
{
if (sscanf(next_char, SCANFORMAT, &dummy) != 1)
{
temp_solution.Set_patm(1);
}
else
{
temp_solution.Set_patm(dummy);
}
}
break;
case 13: /* potential, Volt */
{
if (sscanf(next_char, SCANFORMAT, &dummy) != 1)
{
temp_solution.Set_potV(0);
}
else
{
temp_solution.Set_potV(dummy);
}
}
break;
case OPTION_DEFAULT:
/*
* Read concentration
*/
{
cxxISolutionComp temp_comp(this->phrq_io);
if (temp_comp.read(line, &temp_solution) == CParser::PARSER_ERROR)
{
input_error++;
break;
}
isoln_ptr->Get_comps()[temp_comp.Get_description()] = temp_comp;
if (temp_comp.Get_pe_reaction().size() > 0)
{
CReaction temp_chem_reaction;
isoln_ptr->Get_pe_reactions()[temp_comp.Get_pe_reaction()] = temp_chem_reaction;
}
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
/*
* fix up default units and default pe
*/
std::map < std::string, cxxISolutionComp >::iterator it;
for (it = isoln_ptr->Get_comps().begin(); it != isoln_ptr->Get_comps().end(); it++)
{
token = it->first;
Utilities::str_tolower(token);
if (it->second.Get_units().size() == 0)
{
it->second.Set_units(isoln_ptr->Get_units().c_str());
}
else
{
bool alk = false;
if (strstr(token.c_str(), "alk") == token.c_str())
alk = true;
std::string token1 = it->second.Get_units();
if (check_units(token1, alk, true, isoln_ptr->Get_units().c_str(), true) == CParser::PARSER_ERROR)
{
input_error++;
}
else
{
it->second.Set_units(token1.c_str());
}
}
if (it->second.Get_pe_reaction().size() == 0)
{
it->second.Set_pe_reaction(isoln_ptr->Get_default_pe());
}
}
Rxn_solution_map[n_user] = temp_solution;
Rxn_new_solution.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Read data for aqueous species, parse equations
*/
int i;
int association;
class species *s_ptr;
const class elt_list *next_elt;
const char* cptr;
char token[MAX_LENGTH];
//bool vm_read = false;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"no_check", /* 0 */
"check", /* 1 */
"gamma", /* 2 */
"mb", /* 3 */
"mass_balance", /* 4 */
"log_k", /* 5 */
"logk", /* 6 */
"delta_h", /* 7 */
"deltah", /* 8 */
"analytical_expression", /* 9 */
"a_e", /* 10 */
"ae", /* 11 */
"mole_balance", /* 12 */
"llnl_gamma", /* 13 */
"co2_llnl_gamma", /* 14 */
"activity_water", /* 15 */
"add_logk", /* 16 */
"add_log_k", /* 17 */
"add_constant", /* 18 */
"dw", /* 19 */
"erm_ddl", /* 20 */
/* VP: Density Start */
"millero", /* 21 */
/* VP: Density End */
"vm", /* 22, parms for molar volume, a1..a4 and w_ref, I terms */
"viscosity" /* 23, b and d parms for viscosity, (b1 + b2 * exp(-b3 * tc)) * c + (d1 * exp(-d2 * tc)) * c ^ d3 */
};
int count_opt_list = 24;
association = TRUE;
s_ptr = NULL;
/*
* Read eqn from file and call parser
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
//vm_read = false;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SOLUTION_SPECIES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* no_check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = FALSE;
break;
case 1: /* check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = TRUE;
break;
case 2: /* gamma data */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->gflag = 2; /* Wateq D-H */
i = sscanf(next_char, SCANFORMAT SCANFORMAT, &s_ptr->dha,
&s_ptr->dhb);
if (i < 2)
{
error_string = sformatf( "Expecting 2 activity-"
"coefficient parameters, a and b.");
warning_msg(error_string);
}
opt_save = OPTION_DEFAULT;
break;
case 3: /* mb */
case 4: /* mass_balance */
case 12: /* mole_balance */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
count_elts = 0;
paren_count = 0;
copy_token(token, &next_char, &i);
s_ptr->mole_balance = string_hsave(token);
cptr = token;
s_ptr->next_secondary.clear();
get_secondary_in_species(&cptr, 1.0);
s_ptr->next_secondary = elt_list_vsave();
/* debug
for (i = 0; i < count_elts; i++) {
output_msg(sformatf("%s\t%f\n", elt_list[i].elt->name,
elt_list[i].coef));
}
*/
opt_save = OPTION_DEFAULT;
break;
case 5: /* log_k */
case 6: /* logk */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_log_k_only(next_char, &s_ptr->logk[0]);
opt_save = OPTION_DEFAULT;
break;
case 7: /* delta_h */
case 8: /* deltah */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_delta_h_only(next_char, &s_ptr->logk[1],
&s_ptr->original_units);
opt_save = OPTION_DEFAULT;
break;
case 9: /* analytical_expression */
case 10: /* a_e */
case 11: /* ae */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_analytical_expression_only(next_char, &(s_ptr->logk[T_A1]));
opt_save = OPTION_DEFAULT;
break;
case 13: /* llnl_gamma */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->gflag = 7; /* llnl D-H */
i = sscanf(next_char, SCANFORMAT, &s_ptr->dha);
if (i < 1)
{
error_string = sformatf(
"Expecting activity-coefficient parameter, a.");
warning_msg(error_string);
}
opt_save = OPTION_DEFAULT;
break;
case 14: /* co2_llnl_gamma */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->gflag = 8; /* llnl CO2 D-H */
opt_save = OPTION_DEFAULT;
break;
case 15: /* activity water */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->gflag = 9; /* activity_water/55.5 for HDO, D2O, H2[O18], etc */
opt_save = OPTION_DEFAULT;
break;
case 16: /* add_logk */
case 17: /* add_log_k */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
/* read name */
if (copy_token(token, &next_char, &i) == EMPTY)
{
input_error++;
error_string = sformatf(
"Expected the name of a NAMED_EXPRESSION.");
error_msg(error_string, CONTINUE);
break;
}
s_ptr->add_logk[count_add_logk].name = string_hsave(token);
/* read coef */
i = sscanf(next_char, SCANFORMAT,
&s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
s_ptr->add_logk[count_add_logk].coef = 1;
}
opt_save = OPTION_DEFAULT;
}
break;
case 18: /* add_constant */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
i = sscanf(next_char, SCANFORMAT,
&s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
input_error++;
error_string = sformatf(
"Expected the constant to add for log_K definition.");
error_msg(error_string, CONTINUE);
break;
}
/* set name */
s_ptr->add_logk[count_add_logk].name =
string_hsave("XconstantX");
/* read coef */
opt_save = OPTION_DEFAULT;
}
break;
case 19: /* tracer diffusion coefficient */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->dw_t = 0; s_ptr->dw_a = 0; s_ptr->dw_a2 = 0; s_ptr->dw_a3 = 0; s_ptr->dw_a_visc = 0; s_ptr->dw_a_v_dif = 0;
i = sscanf(next_char, SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT SCANFORMAT,
&s_ptr->dw, &s_ptr->dw_t, &s_ptr->dw_a, &s_ptr->dw_a2, &s_ptr->dw_a_visc, &s_ptr->dw_a3, &s_ptr->dw_a_v_dif);
if (i < 1)
{
input_error++;
error_msg("Expecting numeric values for the diffusion coefficient, its temperature dependence, and coefficients for the SC calculation.",
CONTINUE);
return (ERROR);
}
s_ptr->dw_corr = s_ptr->dw;
opt_save = OPTION_DEFAULT;
break;
case 20: /* enrichment factor in the DDL */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
i = sscanf(next_char, SCANFORMAT, &s_ptr->erm_ddl);
if (s_ptr->erm_ddl < 0)
{
error_string = sformatf( "Expecting enrichment factor > 0, "
"resetting to erm_ddl = 1.");
warning_msg(error_string);
s_ptr->erm_ddl = 1.0;
}
opt_save = OPTION_DEFAULT;
break;
/* VP: Density Start */
case 21: /* Millero a, b, c, d, e and f coefficients */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
print_density = read_millero_abcdef (next_char, &(s_ptr->millero[0]));
//if (!vm_read)
//{
///* copy millero parms into logk, for calculating pressure dependency... */
// for (i = 0; i < 7; i++)
// s_ptr->logk[vm0 + i] = s_ptr->millero[i];
// s_ptr->logk[vm0 + i] = 0;
//}
opt_save = OPTION_DEFAULT;
break;
/* VP: Density End */
case 22: /* vm, supcrt parms + Ionic strength terms */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_aq_species_vm_parms(next_char, &s_ptr->logk[vma1]);
//vm_read = true;
print_density = OK;
opt_save = OPTION_DEFAULT;
break;
case 23: /* viscosity parms for the Jones-Dole eqn */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_viscosity_parms(next_char, &s_ptr->Jones_Dole[0]);
print_viscosity = OK;
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT:
{
/*
* Get space for species information and parse equation
*/
s_ptr = NULL;
std::vector<class elt_list> new_elt_list;
if (parse_eq(line, new_elt_list, association) == ERROR)
{
parse_error++;
error_msg("Parsing equation.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
/*
* Get pointer to each species in the reaction, store new species if necessary
*/
trxn.token[0].s =
s_store(trxn.token[0].name, trxn.token[0].z, TRUE);
for (i = 1; i < count_trxn; i++)
{
trxn.token[i].s =
s_store(trxn.token[i].name, trxn.token[i].z, FALSE);
}
/*
* Save element list and carbon, hydrogen, and oxygen in species
*/
trxn.token[0].s->next_elt = new_elt_list;
trxn.token[0].s->next_secondary.clear();
next_elt = &trxn.token[0].s->next_elt[0];
for (; next_elt->elt != NULL; next_elt++)
{
if (strcmp(next_elt->elt->name, "C") == 0)
{
trxn.token[0].s->carbon = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "H") == 0)
{
trxn.token[0].s->h = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "O") == 0)
{
trxn.token[0].s->o = next_elt->coef;
}
}
/*
* Copy reaction to reaction for species
*/
trxn_copy(trxn.token[0].s->rxn);
s_ptr = trxn.token[0].s;
/*
* Default gamma data
*/
s_ptr->dha = 0.0;
s_ptr->dhb = 0.0;
if (equal(s_ptr->z, 0.0, TOL) == TRUE)
{
s_ptr->gflag = 0; /* Uncharged */
s_ptr->dhb = 0.1;
}
else
{
s_ptr->gflag = 1; /* Davies */
}
/*
* Set type for species
*/
if (strcmp(trxn.token[0].s->name, "H+") == 0)
{
s_hplus = trxn.token[0].s;
s_hplus->type = HPLUS;
}
else if (strcmp(trxn.token[0].s->name, "H3O+") == 0)
{
s_h3oplus = trxn.token[0].s;
s_h3oplus->type = HPLUS;
}
else if (strcmp(trxn.token[0].s->name, "e-") == 0)
{
s_eminus = trxn.token[0].s;
s_eminus->type = EMINUS;
s_eminus->gflag = 3; /* Always 1 */
}
else if (strcmp(trxn.token[0].s->name, "H2O") == 0)
{
s_h2o = trxn.token[0].s;
s_h2o->type = H2O;
s_h2o->gflag = 3; /* Always 1 */
}
else if (strstr(trxn.token[0].s->name, "(s)") != NULL)
{
trxn.token[0].s->type = SOLID;
}
else if (strcmp(trxn.token[0].s->name, "H2") == 0)
{
trxn.token[0].s->type = AQ;
s_h2 = trxn.token[0].s;
}
else if (strcmp(trxn.token[0].s->name, "O2") == 0)
{
trxn.token[0].s->type = AQ;
s_o2 = trxn.token[0].s;
}
else
{
trxn.token[0].s->type = AQ;
}
opt_save = OPTION_DEFAULT;
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_use(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads solution, mix, irreversible reaction, and pure phases to use
* in reaction calculation
*/
int i, l, n_user, return_value;
const char* cptr;
char token[MAX_LENGTH], token1[MAX_LENGTH];;
/*
* Read "use"
*/
cptr = line;
copy_token(token, &cptr, &l);
/*
* Read keyword
*/
copy_token(token, &cptr, &l);
check_key(token);
if (next_keyword != Keywords::KEY_SOLUTION &&
next_keyword != Keywords::KEY_MIX &&
next_keyword != Keywords::KEY_KINETICS &&
next_keyword != Keywords::KEY_REACTION &&
next_keyword != Keywords::KEY_REACTION_TEMPERATURE &&
next_keyword != Keywords::KEY_REACTION_PRESSURE &&
next_keyword != Keywords::KEY_EQUILIBRIUM_PHASES &&
next_keyword != Keywords::KEY_EXCHANGE &&
next_keyword != Keywords::KEY_SURFACE &&
next_keyword != Keywords::KEY_GAS_PHASE &&
next_keyword != Keywords::KEY_SOLID_SOLUTIONS)
{
input_error++;
error_msg("Unknown item in USE keyword", CONTINUE);
error_msg(line_save, CONTINUE);
check_line("End of use", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (ERROR);
}
/*
* Read number
*/
Utilities::strcpy_safe(token1, MAX_LENGTH, token);
for (;;)
{
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, "%d", &n_user);
if (n_user < 0)
{
error_msg("Number must be a positive integer.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
if (strstr(token, "-") != NULL)
{
error_string = sformatf(
"USE does not accept a range of numbers, %s.", token);
warning_msg(error_string);
error_string = sformatf(
"Only %s %d will be used in the batch-reaction calculation.",
token1, n_user);
warning_msg(error_string);
error_string = sformatf(
"NOTE--USE is not needed for ADVECTION and TRANSPORT calculations.");
warning_msg(error_string);
}
break;
}
else if (i == EMPTY)
{
error_string = sformatf( "No number given, 1 assumed.");
warning_msg(error_string);
n_user = 1;
break;
}
else if (token[0] == 'N' || token[0] == 'n')
{
n_user = -2;
break;
}
}
switch (next_keyword)
{
case Keywords::KEY_SOLUTION: /* Solution */
use.Set_n_solution_user(n_user);
if (n_user >= 0)
{
use.Set_solution_in(true);
}
else
{
use.Set_solution_in(false);
}
break;
case Keywords::KEY_EQUILIBRIUM_PHASES: /* Pure phases */
use.Set_n_pp_assemblage_user(n_user);
if (n_user >= 0)
{
use.Set_pp_assemblage_in(true);
}
else
{
use.Set_pp_assemblage_in(false);
}
break;
case Keywords::KEY_REACTION: /* Reaction */
use.Set_n_reaction_user(n_user);
if (n_user >= 0)
{
use.Set_reaction_in(true);
}
else
{
use.Set_reaction_in(false);
}
break;
case Keywords::KEY_MIX: /* Mix */
use.Set_n_mix_user(n_user);
if (n_user >= 0)
{
use.Set_mix_in(true);
}
else
{
use.Set_mix_in(false);
}
break;
case Keywords::KEY_EXCHANGE: /* Ex */
use.Set_n_exchange_user(n_user);
if (n_user >= 0)
{
use.Set_exchange_in(true);
}
else
{
use.Set_exchange_in(false);
}
break;
case Keywords::KEY_SURFACE: /* Surface */
use.Set_n_surface_user(n_user);
if (n_user >= 0)
{
use.Set_surface_in(true);
}
else
{
use.Set_surface_in(false);
}
break;
case Keywords::KEY_REACTION_TEMPERATURE: /* Temperature */
use.Set_n_temperature_user(n_user);
if (n_user >= 0)
{
use.Set_temperature_in(true);
}
else
{
use.Set_temperature_in(false);
}
break;
case Keywords::KEY_REACTION_PRESSURE: /* pressure */
use.Set_n_pressure_user(n_user);
if (n_user >= 0)
{
use.Set_pressure_in(true);
}
else
{
use.Set_pressure_in(false);
}
break;
case Keywords::KEY_GAS_PHASE: /* Gas */
use.Set_n_gas_phase_user(n_user);
if (n_user >= 0)
{
use.Set_gas_phase_in(true);
}
else
{
use.Set_gas_phase_in(false);
}
break;
case Keywords::KEY_KINETICS: /* Kinetics */
use.Set_n_kinetics_user(n_user);
if (n_user >= 0)
{
use.Set_kinetics_in(true);
}
else
{
use.Set_kinetics_in(false);
}
break;
case Keywords::KEY_SOLID_SOLUTIONS: /* solid_solutions */
use.Set_n_ss_assemblage_user(n_user);
if (n_user >= 0)
{
use.Set_ss_assemblage_in(true);
}
else
{
use.Set_ss_assemblage_in(false);
}
break;
default:
input_error++;
error_msg(line_save, CONTINUE);
error_msg("Error in switch for USE.", STOP);
break;
}
return_value = check_line("End of use", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_surface_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Read data for surface species, parse equations
*/
int i, j;
int association;
char token[MAX_LENGTH];
const char* cptr;
LDBLE offset;
class species *s_ptr;
const class elt_list *next_elt;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"no_check", /* 0 */
"check", /* 1 */
"mb", /* 2 */
"mass_balance", /* 3 */
"log_k", /* 4 */
"logk", /* 5 */
"delta_h", /* 6 */
"deltah", /* 7 */
"analytical_expression", /* 8 */
"a_e", /* 9 */
"ae", /* 10 */
"mole_balance", /* 11 */
"offset", /* 12 */
"add_logk", /* 13 */
"add_log_k", /* 14 */
"add_constant", /* 15 */
"cd_music", /* 16 */
"music", /* 17 */
"vm" /* 18 */
};
int count_opt_list = 19;
association = TRUE;
/*
* Read eqn from file and call parser
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
s_ptr = NULL;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SURFACE_SPECIES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* no_check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = FALSE;
break;
case 1: /* check */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
s_ptr->check_equation = TRUE;
break;
case 2: /* mb */
case 3: /* mass_balance */
case 11: /* mole_balance */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
count_elts = 0;
paren_count = 0;
copy_token(token, &next_char, &i);
s_ptr->mole_balance = string_hsave(token);
cptr = token;
s_ptr->next_secondary.clear();
get_secondary_in_species(&cptr, 1.0);
s_ptr->next_secondary = elt_list_vsave();
/* debug
for (i = 0; i < count_elts; i++) {
output_msg(sformatf("%s\t%f\n", elt_list[i].elt->name,
elt_list[i].coef));
}
*/
opt_save = OPTION_DEFAULT;
break;
case 4: /* log_k */
case 5: /* logk */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_log_k_only(next_char, &s_ptr->logk[0]);
opt_save = OPTION_DEFAULT;
break;
case 6: /* delta_h */
case 7: /* deltah */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_delta_h_only(next_char, &s_ptr->logk[1],
&s_ptr->original_units);
opt_save = OPTION_DEFAULT;
break;
case 8: /* analytical_expression */
case 9: /* a_e */
case 10: /* ae */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_analytical_expression_only(next_char, &(s_ptr->logk[T_A1]));
opt_save = OPTION_DEFAULT;
break;
case 12: /* offset */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
if (sscanf(next_char, SCANFORMAT, &offset) != 1)
{
error_msg("No offset for log K given", STOP);
}
s_ptr->logk[0] += offset;
opt_save = OPTION_DEFAULT;
break;
case 13: /* add_logk */
case 14: /* add_log_k */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
/* read name */
if (copy_token(token, &next_char, &i) == EMPTY)
{
input_error++;
error_string = sformatf(
"Expected the name of a NAMED_EXPRESSION.");
error_msg(error_string, CONTINUE);
break;
}
s_ptr->add_logk[count_add_logk].name = string_hsave(token);
/* read coef */
i = sscanf(next_char, SCANFORMAT,
&s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
s_ptr->add_logk[count_add_logk].coef = 1;
}
opt_save = OPTION_DEFAULT;
}
break;
case 15: /* add_constant */
{
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = s_ptr->add_logk.size();
s_ptr->add_logk.resize(count_add_logk + 1);
i = sscanf(next_char, SCANFORMAT, &s_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
input_error++;
error_string = sformatf(
"Expected the constant to add for log_K definition.");
error_msg(error_string, CONTINUE);
break;
}
/* set name */
s_ptr->add_logk[count_add_logk].name =
string_hsave("XconstantX");
opt_save = OPTION_DEFAULT;
}
break;
case 16: /* cd_music */
case 17: /* music */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
for (j = 0; j < 5; j++)
{
if (copy_token(token, &next_char, &i) == EMPTY)
break;
if (sscanf(token, SCANFORMAT, &s_ptr->cd_music[j]) != 1)
break;
}
s_ptr->dz[0] = s_ptr->cd_music[0] + s_ptr->cd_music[3] * s_ptr->cd_music[4];
s_ptr->dz[1] = s_ptr->cd_music[1] + (1 - s_ptr->cd_music[3]) * s_ptr->cd_music[4];
s_ptr->dz[2] = s_ptr->cd_music[2];
for (j = 0; j < 3; j++)
{
s_ptr->rxn.dz[j] = s_ptr->dz[j];
}
opt_save = OPTION_DEFAULT;
break;
case 18: /* vm, molar volume */
if (s_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_vm_only(next_char, &s_ptr->logk[vm0],
&s_ptr->original_deltav_units);
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT:
{
/*
* Get surface species information and parse equation
*/
s_ptr = NULL;
std::vector<class elt_list> new_elt_list;
if (parse_eq(line, new_elt_list, association) == ERROR)
{
parse_error++;
error_msg("Parsing equation.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
}
/*
* Get pointer to each species in the reaction, store new species if necessary
*/
trxn.token[0].s = s_store(trxn.token[0].name, trxn.token[0].z, TRUE);
for (i = 1; i < count_trxn; i++)
{
trxn.token[i].s =
s_store(trxn.token[i].name, trxn.token[i].z, FALSE);
}
/*
* Save element list and carbon, hydrogen, and oxygen in species
*/
trxn.token[0].s->next_elt = new_elt_list;
next_elt = &trxn.token[0].s->next_elt[0];
for (; next_elt->elt != NULL; next_elt++)
{
if (strcmp(next_elt->elt->name, "C") == 0)
{
trxn.token[0].s->carbon = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "H") == 0)
{
trxn.token[0].s->h = next_elt->coef;
}
if (strcmp(next_elt->elt->name, "O") == 0)
{
trxn.token[0].s->o = next_elt->coef;
}
}
/*
* Copy reaction to reaction for species
*/
trxn_copy(trxn.token[0].s->rxn);
/*
* Set type for species
*/
trxn.token[0].s->type = SURF;
s_ptr = trxn.token[0].s;
/*
* Read gamma data
*/
s_ptr->gflag = 6;
s_ptr->dha = 0.0;
s_ptr->dhb = 0.0;
opt_save = OPTION_DEFAULT;
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_surface(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads surface data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int n_user, i1;
LDBLE conc;
const char* cptr, *cptr1;
std::string token, token1, name;
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"equilibrate", /* 0 */
"equil", /* 1 */
"diff", /* 2 */
"diffuse_layer", /* 3 */
"no_edl", /* 4 */
"no_electrostatic", /* 5 */
"only_counter_ions", /* 6 */
"donnan", /* 7 */
"cd_music", /* 8 */
"capacitances", /* 9 */
"sites", /* 10 */
"sites_units", /* 11 */
"constant_capacitance", /* 12 */
"ccm", /* 13 */
"equilibrium", /* 14 */
"site_units", /* 15 */
"ddl", /* 16 */
"donnan_factors" /* 17 */
};
int count_opt_list = 18;
/*
* kin_surf is for Surfaces, related to kinetically reacting minerals
* they are defined if "sites" is followed by mineral name:
* Surf_wOH Manganite [equilibrium_phases or kinetics] 0.25 4000
* ^Name mineral ^switch ^prop.factor ^m2/mol
*/
cxxSurface temp_surface;
cptr = line;
temp_surface.read_number_description(cptr);
n_user = temp_surface.Get_n_user();
cxxSurfaceComp *comp_ptr = NULL;
cxxSurfaceCharge *charge_ptr = NULL;
temp_surface.Set_new_def(true);
if (use.Get_surface_in() == FALSE)
{
use.Set_surface_in(true);
use.Set_n_surface_user(n_user);
}
/*
* Read surface data
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SURFACE keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* equilibrate */
case 1: /* equil */
case 14: /* equilibrium */
for (;;)
{
int i = copy_token(token, &next_char);
if (i == DIGIT)
{
int j;
(void)sscanf(token.c_str(), "%d", &j);
temp_surface.Set_solution_equilibria(true);
temp_surface.Set_n_solution(j);
break;
}
if (i == EMPTY)
{
error_msg
("Expected a solution number with which to equilibrate surface.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
break;
case 2: /* diffuse_layer */
case 3:
{
temp_surface.Set_thickness(1e-8);
temp_surface.Set_dl_type(cxxSurface::BORKOVEK_DL);
int j = sscanf(next_char, SCANFORMAT, &dummy);
if (j == 1)
{
temp_surface.Set_thickness(dummy);
}
}
break;
case 4: /* no electrostatic */
case 5:
temp_surface.Set_type(cxxSurface::NO_EDL);
break;
case 6:
temp_surface.Set_only_counter_ions(get_true_false(next_char, TRUE) == TRUE);
break;
case 7: /* donnan for DL conc's */
{
temp_surface.Set_dl_type(cxxSurface::DONNAN_DL);
LDBLE thickness = 0.0;
for (;;)
{
int i = copy_token(token, &next_char);
if (i == DIGIT)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_surface.Set_thickness(dummy);
thickness = 1;
continue;
}
else if (i != EMPTY)
{
if (token[0] == 'D' || token[0] == 'd')
{
if (thickness != 0)
{
error_msg
("You must enter EITHER thickness OR Debye lengths (1/k),\n and relative DDL viscosity, DDL limit.\nCorrect is (for example): -donnan 1e-8 viscosity 0.5 limit 0.9 correct_D true\n or (default values): -donnan debye_lengths 1 viscosity 1 limit 0.8 correct_D false",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
int j = copy_token(token1, &next_char);
if (j == DIGIT)
{
(void)sscanf(token1.c_str(), SCANFORMAT, &dummy);
temp_surface.Set_debye_lengths(dummy);
continue;
}
else if (j != EMPTY)
{
error_msg
("Expected number of Debye lengths (1/k).",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
else if (token[0] == 'C' || token[0] == 'c')
{
copy_token(token1, &next_char);
if (token1[0] == 'T' || token1[0] == 't' || token1[0] == 'F' || token1[0] == 'f')
{
temp_surface.Set_correct_D(get_true_false(token1.c_str(), TRUE) == TRUE);
continue;
} else
{
error_msg
("Expected True or False for correct_D (which brings co-ion concentrations closer to their integrated double layer value).",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
else if (token[0] == 'V' || token[0] == 'v')
{
int j = copy_token(token1, &next_char);
if (j == DIGIT)
{
(void)sscanf(token1.c_str(), SCANFORMAT, &dummy);
if(dummy == 0)
{
dummy = 1; temp_surface.Calc_DDL_viscosity(true);
}
temp_surface.Set_DDL_viscosity(dummy);
continue;
}
else if (token1[0] == 'C' || token1[0] == 'c' )
{
temp_surface.Calc_DDL_viscosity(true);
temp_surface.Set_DDL_viscosity(1.0);
continue;
}
else if (j != EMPTY)
{
error_msg
("Expected number for relative DDL viscosity.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
else if (token[0] == 'L' || token[0] == 'l')
{
int j = copy_token(token1, &next_char);
if (j == DIGIT)
{
(void)sscanf(token1.c_str(), SCANFORMAT, &dummy);
temp_surface.Set_DDL_limit(dummy);
continue;
}
else if (j != EMPTY)
{
error_msg
("Expected number for maximum of DDL water as fraction of bulk water.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
else
{
error_msg
("Expected diffuse layer thickness (m) or Debye lengths (1/k) for \n\tcalculating the thickness, and relative DDL viscosity and DDL limit.\nCorrect is (for example): -donnan 1e-8 visc 0.5\n or (default values): -donnan debye_lengths 1 visc 1 lim 0.8",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
}
else
break;
}
}
break;
case 8: /* cd_music */
temp_surface.Set_type(cxxSurface::CD_MUSIC);
break;
case 9: /* capacitances */
/*
* Read capacitance for CD_MUSIC
*/
if (charge_ptr == NULL)
{
error_msg
("Surface component has not been defined for capacitances.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
copy_token(token1, &next_char);
if (sscanf(token1.c_str(), SCANFORMAT, &dummy) == 1)
{
charge_ptr->Set_capacitance0(dummy);
}
copy_token(token1, &next_char);
if (sscanf(token1.c_str(), SCANFORMAT, &dummy) == 1)
{
charge_ptr->Set_capacitance1(dummy);
}
break;
case 10: /* sites */
case 11: /* sites_units */
case 15: /* site_units */
{
int j = copy_token(token1, &next_char);
if (j != EMPTY && (token1[0] == 'A' || token1[0] == 'a'))
{
temp_surface.Set_sites_units(cxxSurface::SITES_ABSOLUTE);
}
else if (j != EMPTY && (token1[0] == 'D' || token1[0] == 'd'))
{
temp_surface.Set_sites_units(cxxSurface::SITES_DENSITY);
}
else
{
error_msg
("Character string expected to be 'Absolute' or 'Density' to define the units of the first item in the definition of a surface component.\n",
CONTINUE);
input_error++;
break;
}
}
break;
// CCM not implemented yet
case 12: /* constant_capacitance */
case 13: /* ccm */
temp_surface.Set_type(cxxSurface::CCM);
copy_token(token1, &next_char);
if (charge_ptr == NULL)
{
error_msg("A surface must be defined before the capacitance is defined.\n",
CONTINUE);
input_error++;
break;
}
if (sscanf(token1.c_str(), SCANFORMAT, &dummy) != 1)
{
error_msg("Expected capacitance for constant_capacitance model.\n",
CONTINUE);
input_error++;
break;
}
else
{
charge_ptr->Set_capacitance0(dummy);
}
/* constant capacitance model not implemented yet */
//error_msg("Constant capacitance model not implemented.", CONTINUE);
//input_error++;
break;
case 16: /* ddl */
temp_surface.Set_type(cxxSurface::DDL);
break;
case 17: /* Donnan_factors */
temp_surface.Donnan_factors.clear();
i1 = 0;
for (;;)
{
int i = copy_token(token, &next_char);
if (i == DIGIT && i1 < 8)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
temp_surface.Donnan_factors.push_back(dummy);
i1++;
continue;
}
else if (i != EMPTY || i1 > 4)
{
error_msg
("Expected 4 numbers for the Donnan_factors of single and double-charged coounter- and co-ions,\n z1, z2, z_1, z_2",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
break;
}
break;
case OPTION_DEFAULT:
/*
* Read surface component
*/
{
cptr = line;
int i = copy_token(token, &cptr);
if (i != UPPER && token[0] != '[')
{
error_msg
("Expected surface name to begin with a capital letter.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
cxxSurfaceComp temp_comp(this->phrq_io);
temp_surface.Get_surface_comps().push_back(temp_comp);
comp_ptr = &(temp_surface.Get_surface_comps().back());
comp_ptr->Set_formula(token.c_str());
i = copy_token(token1, &cptr);
if (i == DIGIT)
{
/*
* Read surface concentration
*/
/* surface concentration is read directly */
if (sscanf(token1.c_str(), SCANFORMAT, &conc) < 1)
{
error_msg("Expected number of surface sites in moles.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
comp_ptr->Set_moles(conc);
/*
* Read equilibrium phase name or kinetics rate name
*/
}
else if (i != EMPTY)
{
/* surface conc. is related to mineral or kinetics */
comp_ptr->Set_phase_name(token1.c_str());
int j = copy_token(token1, &cptr);
/* read optional 'equilibrium_phases' or 'kinetics' */
if (j != DIGIT)
{
if (token1[0] == 'K' || token1[0] == 'k')
{
comp_ptr->Set_rate_name(comp_ptr->Get_phase_name().c_str());
comp_ptr->Set_phase_name(NULL);
}
else if (token1[0] == 'E' || token1[0] == 'e')
{
comp_ptr->Set_rate_name(NULL);
}
else
{
error_msg
("Character string expected to be 'equilibrium_phase' or 'kinetics' to relate surface to mineral or kinetic reaction.\n",
CONTINUE);
input_error++;
break;
}
j = copy_token(token1, &cptr);
}
/* read proportion */
if (j != DIGIT)
{
error_msg
("Expected a coefficient to relate surface to mineral or kinetic reaction.\n",
CONTINUE);
input_error++;
break;
}
(void)sscanf(token1.c_str(), SCANFORMAT, &dummy);
comp_ptr->Set_phase_proportion(dummy);
/* real conc must be defined in tidy_model */
conc = 1.0;
}
else
{
error_msg
("Expected concentration of surface, mineral name, or kinetic reaction name.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
break;
}
/*
* Accumulate elements in elt_list
*/
count_elts = 0;
paren_count = 0;
std::string formula = token.c_str();
cptr1 = formula.c_str();
get_elts_in_species(&cptr1, conc);
/*
* save formula for adjusting number of exchange sites
*/
cptr1 = formula.c_str();
int l;
std::string name;
get_token(&cptr1, name, &dummy, &l);
comp_ptr->Set_formula_z(dummy);
cxxNameDouble nd = elt_list_NameDouble();
comp_ptr->Set_totals(nd);
/*
* Search for charge structure
*/
cptr1 = formula.c_str();
get_elt(&cptr1, name, &l);
{
std::string::size_type pos = name.find('_');
if (pos != std::string::npos)
{
name = name.substr(0, pos);
}
}
charge_ptr = temp_surface.Find_charge(name);
if (charge_ptr == NULL)
{
cxxSurfaceCharge temp_charge(this->phrq_io);
temp_charge.Set_name(name.c_str());
if (comp_ptr->Get_phase_name().size() == 0
&& comp_ptr->Get_rate_name().size() == 0)
{
temp_charge.Set_specific_area(600.0);
temp_charge.Set_grams(0.0);
}
else
{
temp_charge.Set_specific_area(0.0);
temp_charge.Set_grams(1.0);
}
temp_surface.Get_surface_charges().push_back(temp_charge);
charge_ptr = temp_surface.Find_charge(name);
}
comp_ptr->Set_charge_name(name.c_str());
/*
* Read surface area (m2/g)
*/
copy_token(token1, &cptr);
if (sscanf(token1.c_str(), SCANFORMAT, &dummy) == 1)
{
charge_ptr->Set_specific_area(dummy);
}
else
{
break;
}
/*
* Read grams of solid (g)
*/
copy_token(token1, &cptr);
if (sscanf(token1.c_str(), SCANFORMAT, &dummy) == 1)
{
charge_ptr->Set_grams(dummy);
}
/* read Dw */
copy_token(token1, &cptr);
Utilities::str_tolower(token1);
if (strcmp(token1.c_str(), "dw") == 0)
{
int j = copy_token(token1, &cptr);
if (j != DIGIT)
{
error_msg
("Expected surface diffusion coefficient (m2/s).\n",
CONTINUE);
input_error++;
break;
}
else
{
(void)sscanf(token1.c_str(), SCANFORMAT, &dummy);
comp_ptr->Set_Dw(dummy);
if (dummy > 0)
{
temp_surface.Set_transport(true);
if (temp_surface.Get_related_rate()
|| temp_surface.Get_related_phases())
{
error_msg
("Can`t transport surfaces related to phases or rates (yet).",
CONTINUE);
input_error++;
}
}
break;
}
}
}
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
// Sort comps and charge
temp_surface.Sort_comps();
/*
* copy Dw > 0 to all comps with the same charge structure, check edl & dif for surface transport
*/
if (temp_surface.Get_transport())
{
if (temp_surface.Get_type() <= cxxSurface::NO_EDL)
{
input_error++;
error_msg
("Must use default Dzombak and Morel or -cd_music for surface transport.",
CONTINUE);
}
if (temp_surface.Get_dl_type() <= cxxSurface::NO_DL)
{
input_error++;
error_msg
("Must use -donnan or -diffuse_layer for surface transport.",
CONTINUE);
}
for (size_t i = 0; i < temp_surface.Get_surface_comps().size(); i++)
{
comp_ptr = &(temp_surface.Get_surface_comps()[i]);
if (comp_ptr->Get_Dw() > 0)
{
std::string name = comp_ptr->Get_charge_name();
for (size_t j = 0; j < temp_surface.Get_surface_comps().size(); j++)
{
cxxSurfaceComp *comp_ptr1 = &(temp_surface.Get_surface_comps()[j]);
std::string name1 = comp_ptr1->Get_charge_name();
if (name == name1)
{
comp_ptr1->Set_Dw(comp_ptr->Get_Dw());
}
}
}
}
}
/*
* Make sure surface area is defined
*/
if (temp_surface.Get_type() == cxxSurface::DDL || temp_surface.Get_type() == cxxSurface::CCM || temp_surface.Get_type() == cxxSurface::CD_MUSIC)
{
for (size_t i = 0; i < temp_surface.Get_surface_charges().size(); i++)
{
charge_ptr = &(temp_surface.Get_surface_charges()[i]);
if (charge_ptr->Get_grams() *
charge_ptr->Get_specific_area() <= 0)
{
error_string = sformatf( "Surface area not defined for %s.\n",
charge_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
}
}
/*
* Logical checks
*/
if (temp_surface.Get_type() == cxxSurface::UNKNOWN_DL)
{
error_string = sformatf( "Unknown surface type.\n");
error_msg(error_string, CONTINUE);
input_error++;
}
else if (temp_surface.Get_type() == cxxSurface::NO_EDL)
{
if (temp_surface.Get_dl_type() != cxxSurface::NO_DL)
{
error_string = sformatf(
"No electrostatic term calculations do not allow calculation of the diffuse layer composition.\n");
warning_msg(error_string);
temp_surface.Set_dl_type(cxxSurface::NO_DL);
}
}
else if (temp_surface.Get_type() == cxxSurface::DDL || temp_surface.Get_type() == cxxSurface::CCM)
{
/* all values of dl_type are valid */
}
else if (temp_surface.Get_type() == cxxSurface::CD_MUSIC)
{
if (temp_surface.Get_dl_type() == cxxSurface::BORKOVEK_DL)
{
error_string = sformatf(
"Borkovec and Westall diffuse layer calculation is not allowed with a CD_MUSIC surface.\n\tUsing Donnan diffuse layer calculation.");
warning_msg(error_string);
temp_surface.Set_dl_type(cxxSurface::DONNAN_DL);
}
if (temp_surface.Get_debye_lengths() > 0)
{
error_msg
("Variable DDL thickness is not permitted in CD_MUSIC. Fix DDL thickness\n\tfor example (default value): -donnan 1e-8",
CONTINUE);
input_error++;
}
}
temp_surface.Sort_comps();
Rxn_surface_map[n_user] = temp_surface;
Rxn_new_surface.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_surface_master_species(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads master species data from data file or input file
*/
int l, return_value;
const char* cptr, *cptr1;
LDBLE l_z;
class species *s_ptr;
char token[MAX_LENGTH], token1[MAX_LENGTH];
int opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"capacitance", /* 0 */
"cd_music_capacitance" /* 1 */
};
int count_opt_list = 0;
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SURFACE_MASTER_SPECIES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case OPTION_DEFAULT:
/*
* Get "element" name with valence, allocate space, store
*/
cptr = line;
/*
* Get element name and save pointer to character string
*/
if (copy_token(token, &cptr, &l) != UPPER && token[0] != '[')
{
parse_error++;
error_msg("Reading element for master species.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
replace("(+", "(", token);
/*
* Delete master if it exists
*/
master_delete(token);
/*
* Save values in master and species structure for surface sites
*/
size_t count_master = master.size();
master.resize(count_master + 1);
master[count_master] = master_alloc();
master[count_master]->type = SURF;
master[count_master]->elt = element_store(token);
if (copy_token(token, &cptr, &l) != UPPER && token[0] != '[')
{
parse_error++;
error_msg("Reading surface master species name.", CONTINUE);
error_msg(line_save, CONTINUE);
continue;
}
s_ptr = s_search(token);
if (s_ptr != NULL)
{
master[count_master]->s = s_ptr;
}
else
{
cptr1 = token;
std::string token1;
get_token(&cptr1, token1, &l_z, &l);
master[count_master]->s = s_store(token1.c_str(), l_z, FALSE);
}
master[count_master]->primary = TRUE;
Utilities::strcpy_safe(token, MAX_LENGTH, master[count_master]->elt->name);
count_master++;
/*
* Save values in master and species structure for surface psi
*/
Utilities::strcpy_safe(token1, MAX_LENGTH, token);
replace("_", " ", token1);
cptr1 = token1;
copy_token(token, &cptr1, &l);
Utilities::strcat_safe(token, MAX_LENGTH, "_psi");
add_psi_master_species(token);
opt_save = OPTION_DEFAULT;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
add_psi_master_species(char *token)
/* ---------------------------------------------------------------------- */
{
class species *s_ptr;
class master *master_ptr;
const char* cptr;
char token1[MAX_LENGTH] = "";
int i, n, plane;
Utilities::strcpy_safe(token1, MAX_LENGTH, token);
for (plane = SURF_PSI; plane <= SURF_PSI2; plane++)
{
strcpy(token, token1);
switch (plane)
{
case SURF_PSI:
break;
case SURF_PSI1:
strcat(token, "b");
break;
case SURF_PSI2:
strcat(token, "d");
break;
}
master_ptr = master_search(token, &n);
if (master_ptr == NULL)
{
size_t count_master = master.size();
master.resize(count_master + 1);
master[count_master] = master_alloc();
master[count_master]->type = plane;
master[count_master]->elt = element_store(token);
s_ptr = s_search(token);
if (s_ptr != NULL)
{
master[count_master]->s = s_ptr;
}
else
{
master[count_master]->s = s_store(token, 0.0, FALSE);
}
count_elts = 0;
paren_count = 0;
cptr = token;
get_elts_in_species(&cptr, 1.0);
master[count_master]->s->next_elt = elt_list_vsave();
master[count_master]->s->type = plane;
master[count_master]->primary = TRUE;
master[count_master]->s->rxn.token.resize(3);
/*
* Define reaction for psi
*/
for (i = 0; i < MAX_LOG_K_INDICES; i++)
{
master[count_master]->s->rxn.logk[i] = 0.0;
}
master[count_master]->s->rxn.token[0].s =
master[count_master]->s;
master[count_master]->s->rxn.token[0].coef = -1.0;
master[count_master]->s->rxn.token[1].s =
master[count_master]->s;
master[count_master]->s->rxn.token[1].coef = 1.0;
master[count_master]->s->rxn.token[2].s = NULL;
count_master++;
}
}
return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_title(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads title for simulation
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
const char* cptr, *cptr1;
int l;
int return_value;
char token[MAX_LENGTH];
/*
* Read anything after keyword
*/
cptr = line;
copy_token(token, &cptr, &l);
cptr1 = cptr;
title_x.clear();
if (copy_token(token, &cptr, &l) != EMPTY)
{
title_x = cptr1;
}
/*
* Read additional lines
*/
for (;;)
{
return_value = check_line("title", TRUE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
if (return_value == EOF || return_value == KEYWORD)
break;
/*
* append line to title_x
*/
if (title_x.size() > 0)
{
title_x.append("\n");
}
title_x.append(line);
}
last_title_x = title_x;
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_advection(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads advection information
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
/*
* Read advection parameters:
* number of cells;
* number of shifts;
*/
std::vector<int> punch_temp, print_temp;
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"cells", /* 0 */
"shifts", /* 1 */
"print", /* 2 */
"selected_output", /* 3 */
"punch", /* 4 */
"print_cells", /* 5 */
"selected_cells", /* 6 */
"time_step", /* 7 */
"timest", /* 8 */
"output", /* 9 */
"output_frequency", /* 10 */
"selected_output_frequency", /* 11 */
"punch_frequency", /* 12 */
"print_frequency", /* 13 */
"punch_cells", /* 14 */
"initial_time", /* 15 */
"warning", /* 16 */
"warnings" /* 17 */
};
int count_opt_list = 18;
/*
* Set use data
*/
use.Set_advect_in(true);
count_ad_cells = 0;
count_ad_shifts = 0;
print_ad_modulus = 1;
punch_ad_modulus = 1;
/*
* Read lines
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in ADVECTION keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* cells */
(void)sscanf(next_char, "%d", &count_ad_cells);
opt_save = OPTION_DEFAULT;
break;
case 1: /* shifts */
(void)sscanf(next_char, "%d", &count_ad_shifts);
opt_save = OPTION_DEFAULT;
break;
case 2: /* print */
case 5: /* print_cells */
{
(void)read_list_ints_range(&next_char, false, print_temp);
opt_save = 2;
}
break;
case 3: /* selected_output */
case 11: /* selected_output_frequency */
case 12: /* punch_frequency */
(void)sscanf(next_char, "%d", &punch_ad_modulus);
opt_save = OPTION_DEFAULT;
if (punch_ad_modulus <= 0)
{
error_string = sformatf(
"Punch frequency must be greater than 0. Frequency set to 1000.");
warning_msg(error_string);
punch_ad_modulus = 1000;
}
break;
case 4: /* punch */
case 14: /* punch_cells */
case 6: /* selected_cells */
{
(void) read_list_ints_range(&next_char, false, punch_temp);
opt_save = 4;
break;
}
case 7: /* time_step */
case 8: /* timest */
(void)sscanf(next_char, SCANFORMAT, &advection_kin_time);
{
std::string token;
int j = copy_token(token, &next_char);
j = copy_token(token, &next_char);
if (j == UPPER || j == LOWER)
{
advection_kin_time = Utilities::convert_time(advection_kin_time, token, "s");
}
}
advection_kin_time_defined = TRUE;
opt_save = OPTION_DEFAULT;
break;
case 9: /* output */
case 10: /* output_frequency */
case 13: /* print_frequency */
(void)sscanf(next_char, "%d", &print_ad_modulus);
opt_save = OPTION_DEFAULT;
if (print_ad_modulus <= 0)
{
error_string = sformatf(
"Print frequency must be greater than 0. Frequency set to 1000.");
warning_msg(error_string);
print_ad_modulus = 1000;
}
break;
case 15: /* initial_time */
char token[MAX_LENGTH];
int j;
if (copy_token(token, &next_char, &j) == DIGIT)
(void)sscanf(token, SCANFORMAT, &initial_total_time);
{
std::string stdtoken;
j = copy_token(stdtoken, &next_char);
if (j == UPPER || j == LOWER)
{
initial_total_time = Utilities::convert_time(initial_total_time, stdtoken, "s");
}
}
opt_save = OPTION_DEFAULT;
break;
case 16: /* warning */
case 17: /* warnings */
advection_warnings = get_true_false(next_char, TRUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
/*
* Fill in data for punch
*/
advection_punch.resize(count_ad_cells + 1);
if (punch_temp.size() != 0)
{
for (size_t i = 0; i < count_ad_cells; i++)
advection_punch[i] = FALSE;
for (size_t i = 0; i < punch_temp.size(); i++)
{
if (punch_temp[i] > count_ad_cells || punch_temp[i] < 1)
{
error_string = sformatf(
"Cell number for punch is out of range, %d. Request ignored.",
punch_temp[i]);
warning_msg(error_string);
}
else
{
advection_punch[punch_temp[i] - 1] = TRUE;
}
}
}
else
{
for (size_t i = 0; i < count_ad_cells; i++)
advection_punch[i] = TRUE;
}
punch_temp.clear();
/*
* Fill in data for print
*/
advection_print.resize(count_ad_cells + 1);
if (print_temp.size() != 0)
{
for (size_t i = 0; i < count_ad_cells; i++)
advection_print[i] = FALSE;
for (size_t i = 0; i < print_temp.size(); i++)
{
if (print_temp[i] > count_ad_cells || print_temp[i] < 1)
{
error_string = sformatf(
"Cell number for print is out of range, %d. Request ignored.",
print_temp[i]);
warning_msg(error_string);
}
else
{
advection_print[print_temp[i] - 1] = TRUE;
}
}
}
else
{
for (size_t i = 0; i < count_ad_cells; i++)
advection_print[i] = TRUE;
}
print_temp.clear();
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_debug(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads knobs and debugging info
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"iterations", /* 0 */
"tolerance", /* 1 */
"step_size", /* 2 */
"pe_step_size", /* 3 */
"scale_pure_phases", /* 4 */
"diagonal_scale", /* 5 */
"debug_model", /* 6 */
"debug_prep", /* 7 */
"debug_set", /* 8 */
"debug_inverse", /* 9 */
"logfile", /* 10 */
"log_file", /* 11 */
"debug_diffuse_layer", /* 12 */
"delay_mass_water", /* 13 */
"convergence_tolerance", /* 14 */
"numerical_derivatives", /* 15 */
"tries", /* 16 */
"try", /* 17 */
"numerical_fixed_volume", /* 18 */
"force_numerical_fixed_volume", /* 19 */
"equi_delay", /* 20 */
"minimum_total", /* 21 */
"min_total", /* 22 */
"debug_mass_action", /* 23 */
"debug_mass_balance" /* 24 */
};
int count_opt_list = 25;
/*
* Read parameters:
* ineq_tol;
* step_size;
* pe_step_size;
* pp_scale;
* diagonal_scale;
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in KNOBS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* iterations */
(void)sscanf(next_char, "%d", &itmax);
break;
case 1: /* tolerance */
(void)sscanf(next_char, SCANFORMAT, &ineq_tol);
break;
case 2: /* step_size */
(void)sscanf(next_char, SCANFORMAT, &step_size);
break;
case 3: /* pe_step_size */
(void)sscanf(next_char, SCANFORMAT, &pe_step_size);
break;
case 4: /* pp_scale */
(void)sscanf(next_char, SCANFORMAT, &pp_scale);
break;
case 5: /* diagonal_scale */
diagonal_scale = get_true_false(next_char, TRUE);
break;
case 6: /* debug_model */
debug_model = get_true_false(next_char, TRUE);
break;
case 7: /* debug_prep */
debug_prep = get_true_false(next_char, TRUE);
break;
case 8: /* debug_set */
debug_set = get_true_false(next_char, TRUE);
break;
case 9: /* debug_inverse */
debug_inverse = get_true_false(next_char, TRUE);
break;
case 10: /* logfile */
case 11: /* log_file */
pr.logfile = get_true_false(next_char, TRUE);
if (phast == TRUE)
{
pr.logfile = FALSE;
warning_msg("PHREEQC log file is disabled in PHAST");
}
phrq_io->Set_log_on(pr.logfile == TRUE);
break;
case 12: /* debug_diffuse_layer */
debug_diffuse_layer = get_true_false(next_char, TRUE);
break;
case 13: /* delay_mass_water */
delay_mass_water = get_true_false(next_char, TRUE);
break;
case 14: /* convergence_tolerance */
{
LDBLE ct;
(void)sscanf(next_char, SCANFORMAT, &ct);
convergence_tolerance = ct;
}
break;
case 15: /* numerical_derivatives */
numerical_deriv = get_true_false(next_char, TRUE);
break;
case 16: /* tries */
case 17: /* try */
(void)sscanf(next_char, "%d", &max_tries);
break;
case 18: /* debug_inverse */
numerical_fixed_volume = (get_true_false(next_char, TRUE) == TRUE);
break;
case 19: /* debug_inverse */
force_numerical_fixed_volume = (get_true_false(next_char, TRUE) == TRUE);
break;
case 20: /* equi_delay */
(void)sscanf(next_char, "%d", &equi_delay);
break;
case 21: /* minimum_total */
case 22: /* min_total */
(void)sscanf(next_char, SCANFORMAT, &MIN_TOTAL);
MIN_TOTAL_SS = MIN_TOTAL/100;
MIN_RELATED_SURFACE = MIN_TOTAL*100;
break;
case 23: /* debug_mass_action */
debug_mass_action = get_true_false(next_char, TRUE);
break;
case 24: /* debug_mass_balance */
debug_mass_balance = get_true_false(next_char, TRUE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_print(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads printing info
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int return_value, opt, l;
const char* next_char;
char token[MAX_LENGTH];
LDBLE num;
const char *opt_list[] = {
"reset", /* 0 */
"gas_phase", /* 1 */
"pure_phase", /* 2 */
"surface", /* 3 */
"exchange", /* 4 */
"totals", /* 5 */
"eh", /* 6 */
"species", /* 7 */
"saturation_indices", /* 8 */
"si", /* 9 same a 8 */
"reaction", /* 10 irrev, not used, pr.use */
"mix", /* 11 */
"use", /* 12 */
"selected_output", /* 13 */
"equilibrium_phases", /* 14 same as 2 */
"equilibria", /* 15 same as 2 */
"equilibrium", /* 16 same as 2 */
"pure", /* 17 same as 2 */
"other", /* 18 same as 12 */
"status", /* 19 */
"inverse", /* 20 */
"kinetics", /* 21 */
"dump", /* 22 */
"user_print", /* 23 */
"user_pr", /* 24 */
"solid_solution", /* 25 */
"solid_solutions", /* 26 */
"inverse_modeling", /* 27 */
"headings", /* 28 */
"heading", /* 29 */
"user_graph", /* 30 */
"echo_input", /* 31 */
"warning", /* 32 */
"warnings", /* 33 */
"initial_isotopes", /* 34 */
"isotope_ratios", /* 35 */
"isotope_alphas", /* 36 */
"censor_species", /* 37 */
"alkalinity", /* 38 */
"equilibrium_phase", /* 39 */
"high_precision" /* 40 */
};
int count_opt_list = 41;
int value;
/*
* Read flags:
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in PRINT keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* reset */
value = get_true_false(next_char, TRUE);
pr.kinetics = value;
pr.gas_phase = value;
pr.pp_assemblage = value;
pr.surface = value;
pr.exchange = value;
pr.totals = value;
pr.eh = value;
pr.species = value;
pr.saturation_indices = value;
pr.irrev = value;
pr.mix = value;
pr.reaction = value;
pr.use = value;
pr.inverse = value;
pr.user_print = value;
pr.ss_assemblage = value;
pr.headings = value;
pr.initial_isotopes = value;
pr.isotope_ratios = value;
pr.isotope_alphas = value;
pr.echo_input = value;
break;
case 1: /* gas_phase */
pr.gas_phase = get_true_false(next_char, TRUE);
break;
case 2: /* pure_phase */
case 14: /* equilibrium_phases */
case 15: /* equilibria */
case 16: /* equilibrium */
case 17: /* pure */
case 39: /* equilibrium_phase */
pr.pp_assemblage = get_true_false(next_char, TRUE);
break;
case 3: /* surface */
pr.surface = get_true_false(next_char, TRUE);
break;
case 4: /* exchange */
pr.exchange = get_true_false(next_char, TRUE);
break;
case 5: /* totals */
pr.totals = get_true_false(next_char, TRUE);
break;
case 6: /* eh */
pr.eh = get_true_false(next_char, TRUE);
break;
case 7: /* species */
pr.species = get_true_false(next_char, TRUE);
break;
case 8:
case 9: /* saturation_indices */
pr.saturation_indices = get_true_false(next_char, TRUE);
break;
case 10: /* reaction, not used, pr.use controls */
pr.irrev = get_true_false(next_char, TRUE);
break;
case 11: /* mix, not used, pr.use controls */
pr.mix = get_true_false(next_char, TRUE);
break;
case 12: /* use */
case 18: /* other */
pr.use = get_true_false(next_char, TRUE);
break;
case 13: /* selected_output */
pr.punch = get_true_false(next_char, TRUE);
phrq_io->Set_punch_on(pr.punch == TRUE);
break;
case 19: /* status */
{
int j;
pr.status = get_true_false(next_char, TRUE);
j = copy_token(token, &next_char, &l);
if (j == UPPER || j == LOWER)
{
j = copy_token(token, &next_char, &l);
}
if (j == DIGIT)
{
const char * tptr = token;
get_num(&tptr, &num);
num = floor(num);
if (num < 0.0) num = 0.0;
//status_interval = (int) floor(num);
status_interval = (clock_t) num;
}
}
//if (status_interval < 0)
// status_interval = 0;
break;
case 20: /* inverse */
case 27: /* inverse_modeling */
pr.inverse = get_true_false(next_char, TRUE);
break;
case 21: /* kinetics */
pr.kinetics = get_true_false(next_char, TRUE);
break;
case 22: /* dump */
pr.dump = get_true_false(next_char, TRUE);
phrq_io->Set_dump_on(pr.dump == TRUE);
break;
case 23: /* user_print */
case 24: /* user_pr */
pr.user_print = get_true_false(next_char, TRUE);
break;
case 25: /* solid_solution */
case 26: /* solid_solutions */
pr.ss_assemblage = get_true_false(next_char, TRUE);
break;
case 28: /* headings */
case 29: /* heading */
pr.headings = get_true_false(next_char, TRUE);
break;
case 30: /* user_graph */
pr.user_graph = get_true_false(next_char, TRUE);
break;
case 31: /* echo_input */
pr.echo_input = get_true_false(next_char, TRUE);
if (pr.echo_input == 0)
phrq_io->Set_echo_on(false);
else
phrq_io->Set_echo_on(true);
break;
case 32: /* warning */
case 33: /* warnings */
(void)sscanf(next_char, "%d", &pr.warnings);
break;
case 34: /* initial_isotopes */
pr.initial_isotopes = get_true_false(next_char, TRUE);
break;
case 35: /* isotope_ratios */
pr.isotope_ratios = get_true_false(next_char, TRUE);
break;
case 36: /* isotope_alphas */
pr.isotope_alphas = get_true_false(next_char, TRUE);
break;
case 37: /* censor_species */
if (copy_token(token, &next_char, &l) != EMPTY)
{
(void)sscanf(token, SCANFORMAT, &censor);
}
else
{
censor = 0;
}
break;
case 38: /* alkalinity */
pr.alkalinity = get_true_false(next_char, TRUE);
break;
case 40: /* high_precision */
value = get_true_false(next_char, TRUE);
high_precision = (value != FALSE);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
/*
* Utilitity routines for read
*/
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
int Phreeqc::
check_key(const char *str)
/* ---------------------------------------------------------------------- */
{
/*
* Check if string begins with a keyword, returns TRUE or FALSE
*
* Arguments:
* *str is pointer to character string to be checked for keywords
* Returns:
* TRUE,
* FALSE.
*/
const char* cptr;
std::string stdtoken;
char * token1;
token1 = string_duplicate(str);
cptr = token1;
int j = copy_token(stdtoken, &cptr);
Utilities::str_tolower(stdtoken);
std::string key(stdtoken);
if (j == EMPTY)
{
next_keyword = Keywords::KEY_END;
}
else
{
next_keyword = Keywords::Keyword_search(key);
}
free_check_null(token1);
if (next_keyword > 0)
{
return TRUE;
}
return (FALSE);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
check_units(std::string &tot_units, bool alkalinity, bool check_compatibility,
const char *default_units, bool print)
/* ---------------------------------------------------------------------- */
{
#define NUNITS (sizeof(units) / sizeof(char *))
/*
* Check if legitimate units
* Input:
* tot_units character string to check,
* alkalinity TRUE if alkalinity, FALSE if any other total,
* check_compatibility TRUE check alk and default units, FALSE otherwise
* default_units character string of default units (check /L, /kg, etc)
* print TRUE print warning messages
* Output:
* tot_units standard form for unit
*/
const char *units[] = {
"Mol/l", /* 0 */
"mMol/l", /* 1 */
"uMol/l", /* 2 */
"g/l", /* 3 */
"mg/l", /* 4 */
"ug/l", /* 5 */
"Mol/kgs", /* 6 */
"mMol/kgs", /* 7 */
"uMol/kgs", /* 8 */
"g/kgs", /* 9 = ppt */
"mg/kgs", /* 10 = ppm */
"ug/kgs", /* 11 = ppb */
"Mol/kgw", /* 12 = mol/kg H2O */
"mMol/kgw", /* 13 = mmol/kg H2O */
"uMol/kgw", /* 14 = umol/kg H2O */
"g/kgw", /* 15 = mol/kg H2O */
"mg/kgw", /* 16 = mmol/kg H2O */
"ug/kgw", /* 17 = umol/kg H2O */
"eq/l", /* 18 */
"meq/l", /* 19 */
"ueq/l", /* 20 */
"eq/kgs", /* 21 */
"meq/kgs", /* 22 */
"ueq/kgs", /* 23 */
"eq/kgw", /* 24 */
"meq/kgw", /* 25 */
"ueq/kgw", /* 26 */
};
Utilities::squeeze_white(tot_units);
Utilities::str_tolower(tot_units);
replace("milli", "m", tot_units);
replace("micro", "u", tot_units);
replace("grams", "g", tot_units);
replace("gram", "g", tot_units);
replace("moles", "Mol", tot_units);
replace("mole", "Mol", tot_units);
replace("mol", "Mol", tot_units);
replace("liter", "l", tot_units);
replace("kgh", "kgw", tot_units);
replace("ppt", "g/kgs", tot_units);
replace("ppm", "mg/kgs", tot_units);
replace("ppb", "ug/kgs", tot_units);
replace("equivalents", "eq", tot_units);
replace("equivalent", "eq", tot_units);
replace("equiv", "eq", tot_units);
size_t pos;
if ((pos = tot_units.find("/l")) != std::string::npos)
{
tot_units = tot_units.substr(0, pos + 2);
}
else if ((pos = tot_units.find("/kgs")) != std::string::npos)
{
tot_units = tot_units.substr(0, pos + 4);
}
else if ((pos = tot_units.find("/kgw")) != std::string::npos)
{
tot_units = tot_units.substr(0, pos + 4);
}
/*
* Check if unit in list
*/
bool found = false;
size_t i;
for (i = 0; i < NUNITS; i++)
{
if (strcmp(tot_units.c_str(), units[i]) == 0)
{
found = true;
break;
}
}
if (!found)
{
if (print)
{
error_string = sformatf( "Unknown unit, %s.", tot_units.c_str());
error_msg(error_string, CONTINUE);
}
return (ERROR);
}
/*
* Check if units are compatible with default_units
*/
if (!check_compatibility)
return (OK);
/*
* Special cases for alkalinity
*/
if (alkalinity && strstr(tot_units.c_str(), "Mol") != NULL)
{
if (print == TRUE)
{
error_string = sformatf(
"Alkalinity given in moles, assumed to be equivalents.");
warning_msg(error_string);
}
replace("Mol", "eq", tot_units);
}
if (!alkalinity && strstr(tot_units.c_str(), "eq") != NULL)
{
if (print)
{
error_msg("Only alkalinity can be entered in equivalents.",
CONTINUE);
}
return (ERROR);
}
/*
* See if default_units are compatible with tot_units
*/
if (strstr(default_units, "/l") && strstr(tot_units.c_str(), "/l"))
return (OK);
if (strstr(default_units, "/kgs") && strstr(tot_units.c_str(), "/kgs"))
return (OK);
if (strstr(default_units, "/kgw") && strstr(tot_units.c_str(), "/kgw"))
return (OK);
std::string string = default_units;
Utilities::replace("kgs", "kg solution", string);
Utilities::replace("kgs", "kg solution", tot_units);
Utilities::replace("kgw", "kg water", string);
Utilities::replace("kgw", "kg water", tot_units);
Utilities::replace("/l", "/L", string);
Utilities::replace("Mol", "mol", string);
Utilities::replace("/l", "/L", tot_units);
Utilities::replace("Mol", "mol", tot_units);
if (print == TRUE)
{
error_string = sformatf(
"Units for master species, %s, are not compatible with default units, %s.",
tot_units.c_str(), string.c_str());
error_msg(error_string, CONTINUE);
}
return (ERROR);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
find_option(const char *item, int *n, const char **list, int count_list, int exact)
/* ---------------------------------------------------------------------- */
{
/*
* Compares a string value to match beginning letters of a list of options
*
* Arguments:
* item entry: pointer to string to compare
* n exit: item in list that was matched
* list entry: pointer to list of character values, assumed to
* be lower case
* count_list entry: number of character values in list
*
* Returns:
* OK item matched
* ERROR item not matched
* n -1 item not matched
* i position of match in list
*/
int i;
std::string stdtoken(item);
Utilities::str_tolower(stdtoken);
for (i = 0; i < count_list; i++)
{
if (exact == TRUE)
{
if (strcmp(list[i], stdtoken.c_str()) == 0)
{
*n = i;
return (OK);
}
}
else
{
if (strstr(list[i], stdtoken.c_str()) == list[i])
{
*n = i;
return (OK);
}
}
}
*n = -1;
return (ERROR);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
get_true_false(const char *string, int default_value)
/* ---------------------------------------------------------------------- */
{
/*
* Returns true unless string starts with "F" or "f"
*/
int l;
char token[MAX_LENGTH];
const char* cptr;
cptr = string;
if (copy_token(token, &cptr, &l) == EMPTY)
{
return (default_value);
}
else
{
if (token[0] == 'F' || token[0] == 'f')
{
return (FALSE);
}
}
return (TRUE);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
get_option(const char **opt_list, int count_opt_list, const char **next_char)
/* ---------------------------------------------------------------------- */
{
/*
* Read a line and check for options
*/
int j;
int opt;
const char *opt_ptr;
std::string stdoption;
/*
* Read line
*/
j = check_line("get_option", FALSE, TRUE, TRUE, FALSE);
if (j == EOF)
{
j = OPTION_EOF;
}
else if (j == KEYWORD)
{
j = OPTION_KEYWORD;
}
else if (j == OPTION)
{
opt_ptr = line;
copy_token(stdoption, &opt_ptr);
if (find_option(&(stdoption.c_str()[1]), &opt, opt_list, count_opt_list, FALSE) == OK)
{
j = opt;
replace(stdoption.c_str(), opt_list[j], line_save);
replace(stdoption.c_str(), opt_list[j], line);
opt_ptr = line;
copy_token(stdoption, &opt_ptr);
*next_char = opt_ptr;
if (pr.echo_input == TRUE)
{
if (!reading_database())
output_msg(sformatf( "\t%s\n", line_save));
}
}
else
{
if (!reading_database())
output_msg(sformatf( "\t%s\n", line_save));
error_msg("Unknown option.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
j = OPTION_ERROR;
*next_char = line;
}
}
else
{
opt_ptr = line;
copy_token(stdoption, &opt_ptr);
if (find_option(&(stdoption.c_str()[0]), &opt, opt_list, count_opt_list, TRUE) == OK)
{
j = opt;
*next_char = opt_ptr;
}
else
{
j = OPTION_DEFAULT;
*next_char = line;
}
if (pr.echo_input == TRUE)
{
if (!reading_database())
output_msg(sformatf( "\t%s\n", line_save));
}
}
return (j);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_rates(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads basic code with which to calculate rates
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
const char* cptr;
int l, n;
int return_value, opt, opt_save;
char token[MAX_LENGTH];
class rate *rate_ptr;
const char* next_char;
const char *opt_list[] = {
"start", /* 0 */
"end" /* 1 */
};
int count_opt_list = 2;
n = -1;
opt_save = OPTION_DEFAULT;
/*
* Read lines
*/
return_value = UNKNOWN;
rate_ptr = NULL;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in RATES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* start */
opt_save = OPT_1;
break;
case 1: /* end */
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT: /* read rate name */
cptr = line;
copy_token(token, &cptr, &l);
{
const char *name = string_hsave(token);
rate_ptr = rate_search(name, &n);
}
if (rate_ptr == NULL)
{
size_t count_rates = rates.size();
rates.resize(count_rates + 1);
rate_ptr = &rates[count_rates];
}
else
{
rate_free(rate_ptr);
}
rate_ptr->new_def = TRUE;
rate_ptr->commands.clear();
rate_ptr->name = string_hsave(token);
rate_ptr->linebase = NULL;
rate_ptr->varbase = NULL;
rate_ptr->loopbase = NULL;
opt_save = OPT_1;
break;
case OPT_1: /* read command */
if (rate_ptr == NULL)
{
input_error++;
error_string = sformatf( "No rate name has been defined.");
error_msg(error_string, CONTINUE);
opt_save = OPT_1;
break;
}
rate_ptr->commands.append(";\0");
rate_ptr->commands.append(line);
opt_save = OPT_1;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
/* output_msg(sformatf( "%s", rates[0].commands));
*/
rates_map.clear();
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_user_print(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads basic code with which to calculate rates
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"start", /* 0 */
"end" /* 1 */
};
int count_opt_list = 2;
opt_save = OPTION_DEFAULT;
/*
* Read lines
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in USER_PRINT keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* start */
opt_save = OPTION_DEFAULT;
break;
case 1: /* end */
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT: /* read first command */
rate_free(user_print);
user_print->new_def = TRUE;
user_print->commands.clear();
user_print->linebase = NULL;
user_print->varbase = NULL;
user_print->loopbase = NULL;
user_print->name =
string_hsave("user defined Basic print routine");
case OPT_1: /* read command */
user_print->commands.append(";\0");
user_print->commands.append(line);
opt_save = OPT_1;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
/* output_msg(sformatf( "%s", rates[0].commands));
*/ return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_user_punch(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads basic code with which to calculate rates
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int return_value, opt, opt_save;
std::string stdtoken;
const char* next_char;
const char *opt_list[] = {
"start", /* 0 */
"end", /* 1 */
"heading", /* 2 */
"headings" /* 3 */
};
int count_opt_list = 4;
opt_save = OPTION_DEFAULT;
/*
* Read lines
*/
int n_user;
UserPunch temp_user_punch;
const char* cptr = line;
temp_user_punch.read_number_description(cptr);
n_user = temp_user_punch.Get_n_user();
temp_user_punch.Set_PhreeqcPtr(this);
//std::map < int, UserPunch >::iterator up = UserPunch_map.find(n_user);
//if (up != UserPunch_map.end())
//{
// UserPunch_map.erase(up);
//}
// Malloc rate structure
class rate* r = new class rate;
r->commands.clear();
r->new_def = TRUE;
r->linebase = NULL;
r->varbase = NULL;
r->loopbase = NULL;
r->name = string_hsave("user defined Basic punch routine");
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in USER_PUNCH keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* start */
opt_save = OPTION_DEFAULT;
break;
case 1: /* end */
opt_save = OPTION_DEFAULT;
break;
case 2: /* headings */
case 3: /* heading */
while (copy_token(stdtoken, &next_char) != EMPTY)
{
temp_user_punch.Get_headings().push_back(stdtoken);
}
break;
case OPTION_DEFAULT: /* read first command */
{
r->commands.clear();
}
case OPT_1: /* read command */
r->commands.append(";\0");
r->commands.append(line);
opt_save = OPT_1;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
UserPunch_map.erase(n_user);
UserPunch_map[n_user] = temp_user_punch;
UserPunch_map[n_user].Set_rate(r);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_solid_solutions(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads solid solution data
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int n_user;
std::string token;
int return_value, opt;
const char* next_char;
const char *opt_list[] = {
"component", /* 0 */
"comp", /* 1 */
"parms", /* 2 */
"gugg_nondimensional", /* 3 */
"gugg_kj", /* 4 */
"activity_coefficients", /* 5 */
"distribution_coefficients", /* 6 */
"miscibility_gap", /* 7 */
"spinodal_gap", /* 8 */
"critical_point", /* 9 */
"alyotropic_point", /* 10 */
"temp", /* 11 */
"tempk", /* 12 */
"tempc", /* 13 */
"thompson", /* 14 */
"margules", /* 15 */
"comp1", /* 16 */
"comp2" /* 17 */
};
int count_opt_list = 18;
/*
* Read ss_assemblage number
*/
cxxSSassemblage temp_ss_assemblage;
const char* cptr = line;
temp_ss_assemblage.read_number_description(cptr);
n_user = temp_ss_assemblage.Get_n_user();
temp_ss_assemblage.Set_new_def(true);
std::vector<cxxSScomp> comps;
cxxSScomp * comp0_ptr = NULL;
cxxSScomp * comp1_ptr = NULL;
cxxSS * ss_ptr = NULL;
/*
* Set use data to first read
*/
if (!use.Get_ss_assemblage_in())
{
use.Set_ss_assemblage_in(true);
use.Set_n_ss_assemblage_user(n_user);
}
/*
* Read solid solutions
*/
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SOLID_SOLUTIONS keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
/*
* New component
*/
case 0: /* component */
case 1: /* comp */
{
cxxSScomp comp(this->phrq_io);
/*
* Read phase name of component
*/
cptr = next_char;
copy_token(token, &cptr);
comp.Set_name(token);
/*
* Read moles of component
*/
if (copy_token(token, &cptr) == EMPTY)
{
comp.Set_moles(NAN);
}
else
{
int j = sscanf(token.c_str(), SCANFORMAT, &dummy);
comp.Set_moles(dummy);
if (j != 1)
{
error_msg("Expected moles of solid solution.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
comps.push_back(comp);
}
break;
case 2: /* parms */
case 3: /* gugg_nondimensional */
/*
* Read parameters
*/
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p()[0] = dummy;
}
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p()[1] = dummy;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_A0_A1);
break;
case 4: /* gugg_kj */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p()[0] = dummy;
}
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p()[1] = dummy;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_DIM_GUGG);
break;
case 5: /* activity coefficients */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 4; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 4)
{
error_string = sformatf(
"Expected 4 parameters to calculate a0 and a1 from two activity coefficients, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_GAMMAS);
break;
case 6: /* distribution coefficients */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 4; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 4)
{
error_string = sformatf(
"Expected 4 parameters to calculate a0 and a1 from two distribution coefficients, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_DIST_COEF);
break;
case 7: /* miscibility_gap */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected 2 miscibility gap fractions of component 2 to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_MISCIBILITY);
break;
case 8: /* spinodal_gap */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected 2 spinodal gap fractions of component 2 to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_SPINODAL);
break;
case 9: /* critical point */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected fraction of component 2 and critical temperature to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_CRITICAL);
break;
case 10: /* alyotropic point */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected fraction of component 2 and sigma pi at alyotropic point to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_ALYOTROPIC);
break;
case 12: /* tempk */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
{
cptr = next_char;
int j = 0;
if (copy_token(token, &cptr) != EMPTY)
{
j = sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Set_tk(dummy);
}
if (j != 1)
{
error_string = sformatf(
"Expected temperature (Kelvin) for parameters, assemblage %d, solid solution %s, using 298.15 K",
n_user,
ss_ptr->Get_name().c_str());
warning_msg(error_string);
ss_ptr->Set_tk(298.15);
}
}
break;
case 11: /* temp */
case 13: /* tempc */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
{
cptr = next_char;
int j = 0;
if (copy_token(token, &cptr) != EMPTY)
{
j = sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Set_tk(dummy + 298.15);
}
if (j != 1)
{
error_string = sformatf(
"Expected temperature (Celsius) for parameters, assemblage %d, solid solution %s, using 25 C",
n_user,
ss_ptr->Get_name().c_str());
warning_msg(error_string);
ss_ptr->Set_tk(298.15);
}
}
break;
case 14: /* Thompson and Waldbaum */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected Wg2 and Wg1 Thompson-Waldbaum parameters to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_WALDBAUM);
break;
case 15: /* Margules */
if (!ss_ptr)
{
error_msg("Solid solution name has not been defined", CONTINUE);
break;
}
cptr = next_char;
ss_ptr->Get_p().clear();
for (int i = 0; i < 2; i++)
{
if (copy_token(token, &cptr) != EMPTY)
{
(void)sscanf(token.c_str(), SCANFORMAT, &dummy);
ss_ptr->Get_p().push_back(dummy);
}
}
if (ss_ptr->Get_p().size() != 2)
{
error_string = sformatf(
"Expected alpha2 and alpha3 Margules parameters to calculate a0 and a1, assemblage %d, solid solution %s",
n_user,
ss_ptr->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
ss_ptr->Set_input_case(cxxSS::SS_PARM_MARGULES);
break;
case 16: /* comp1 */
/*
* Read phase name of component
*/
delete comp0_ptr;
comp0_ptr = new cxxSScomp;
cptr = next_char;
copy_token(token, &cptr);
comp0_ptr->Set_name(token);
/*
* Read moles of component
*/
if (copy_token(token, &cptr) == EMPTY)
{
comp0_ptr->Set_moles(NAN);
}
else
{
int j = sscanf(token.c_str(), SCANFORMAT, &dummy);
comp0_ptr->Set_moles(dummy);
if (j != 1)
{
error_msg("Expected moles of solid solution.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
break;
case 17: /* comp2 */
delete comp1_ptr;
comp1_ptr = new cxxSScomp;
/*
* Read phase name of component
*/
cptr = next_char;
copy_token(token, &cptr);
comp1_ptr->Set_name(token);
/*
* Read moles of component
*/
if (copy_token(token, &cptr) == EMPTY)
{
comp1_ptr->Set_moles(NAN);
}
else
{
int j = sscanf(token.c_str(), SCANFORMAT, &dummy);
comp1_ptr->Set_moles(dummy);
if (j != 1)
{
error_msg("Expected moles of solid solution.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
break;
/*
* New solid solution
*/
case OPTION_DEFAULT:
if(ss_ptr)
{
if (comp1_ptr)
{
comps.insert(comps.begin(), *comp1_ptr);
}
if (comp0_ptr)
{
comps.insert(comps.begin(), *comp0_ptr);
}
ss_ptr->Set_ss_comps(comps);
temp_ss_assemblage.Get_SSs()[ss_ptr->Get_name()] = *ss_ptr;
delete ss_ptr;
ss_ptr = NULL;
comps.clear();
delete comp0_ptr;
delete comp1_ptr;
comp0_ptr = comp1_ptr = NULL;
}
ss_ptr = new cxxSS;
/*
* Read solid solution name
*/
cptr = line;
copy_token(token, &cptr);
ss_ptr->Set_name(token);
ss_ptr->Set_total_moles(0.0);
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
// add last ss and clean up
if (comp1_ptr)
comps.insert(comps.begin(), *comp1_ptr);
if (comp0_ptr)
comps.insert(comps.begin(), *comp0_ptr);
if (ss_ptr != NULL && comps.size() > 0)
{
ss_ptr->Set_ss_comps(comps);
}
if (ss_ptr != NULL && ss_ptr->Get_name().size() > 0)
{
temp_ss_assemblage.Get_SSs()[ss_ptr->Get_name()] = *ss_ptr;
}
delete ss_ptr;
ss_ptr = NULL;
comps.clear();
delete comp0_ptr;
delete comp1_ptr;
comp0_ptr = comp1_ptr = NULL;
// check non ideal ss
std::vector<cxxSS *> ss_v;
for (size_t i = 0; i < ss_v.size(); i++)
{
if (ss_v[i]->Get_p()[0] != 0.0 ||
ss_v[i]->Get_p()[1] != 0.0)
{
if (ss_v[i]->Get_ss_comps().size() != 2)
{
error_string = sformatf(
"Solid solution, %s, is nonideal. Must define exactly two components (-comp1 and -comp2).",
ss_v[i]->Get_name().c_str());
error_msg(error_string, CONTINUE);
input_error++;
}
}
}
// Add to map
Rxn_ss_assemblage_map[n_user] = temp_ss_assemblage;
Rxn_new_ss_assemblage.insert(n_user);
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_llnl_aqueous_model_parameters(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads aqueous model parameters
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int return_value, opt;
const char* next_char;
const char* opt_list[] = {
"temperatures", /* 0 */
"temperature", /* 1 */
"temp", /* 2 */
"adh", /* 3 */
"debye_huckel_a", /* 4 */
"dh_a", /* 5 */
"bdh", /* 6 */
"debye_huckel_b", /* 7 */
"dh_b", /* 8 */
"bdot", /* 9 */
"b_dot", /* 10 */
"c_co2", /* 11 */
"co2_coefs" /* 12 */
};
int count_opt_list = 13;
/*
* Initialize
*/
/*
* Read aqueous model parameters
*/
return_value = UNKNOWN;
int opt_save = OPTION_DEFAULT;
opt_save = OPTION_DEFAULT;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_DEFAULT:
case OPTION_ERROR:
input_error++;
error_msg
("Unknown input in LLNL_AQUEOUS_MODEL_PARAMETERS keyword.",
CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* temperatures */
case 1: /* temperature */
case 2: /* temp */
{
std::istringstream iss(next_char);
while (iss >> dummy)
{
llnl_temp.push_back(dummy);
}
opt_save = 2;
}
break;
case 3: /* adh */
case 4: /* debye_huckel_a */
case 5: /* dh_a */
{
std::istringstream iss(next_char);
while (iss >> dummy)
{
llnl_adh.push_back(dummy);
}
opt_save = 5;
}
break;
case 6: /* bdh */
case 7: /* debye_huckel_b */
case 8: /* dh_b */
{
std::istringstream iss(next_char);
while (iss >> dummy)
{
llnl_bdh.push_back(dummy);
}
opt_save = 8;
}
break;
case 9: /* bdot */
case 10: /* b_dot */
{
std::istringstream iss(next_char);
while (iss >> dummy)
{
llnl_bdot.push_back(dummy);
}
opt_save = 10;
}
break;
case 11: /* c_co2 */
case 12: /* co2_coefs */
{
std::istringstream iss(next_char);
while (iss >> dummy)
{
llnl_co2_coefs.push_back(dummy);
}
opt_save = 12;
}
break;
}
return_value = check_line_return;
if (return_value == EOF || return_value == KEYWORD)
break;
}
/* check consistency */
if ((llnl_temp.size() == 0) ||
(llnl_temp.size() != llnl_adh.size()) ||
(llnl_temp.size() != llnl_bdh.size()) ||
(llnl_temp.size() != llnl_bdot.size()))
{
error_msg
("Must define equal number (>0) of temperatures, dh_a, dh_b, and bdot parameters\nin LLNL_AQUEOUS_MODEL",
CONTINUE);
input_error++;
}
if (llnl_co2_coefs.size() != 5)
{
error_msg
("Must define 5 CO2 activity coefficient parameters in LLNL_AQUEOUS_MODEL",
CONTINUE);
input_error++;
}
for (size_t i = 1; i < llnl_temp.size(); i++)
{
if (llnl_temp[i - 1] > llnl_temp[i])
{
error_msg
("Temperatures must be in ascending order in LLNL_AQUEOUS_MODEL",
CONTINUE);
input_error++;
}
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
next_keyword_or_option(const char **opt_list, int count_opt_list)
/* ---------------------------------------------------------------------- */
{
/*
* Reads to next keyword or option or eof
*
* Returns:
* KEYWORD
* OPTION
* EOF
*/
int opt;
const char* next_char;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_EOF)
{ /* end of file */
break;
}
else if (opt == OPTION_KEYWORD)
{ /* keyword */
break;
}
else if (opt >= 0 && opt < count_opt_list)
{
break;
}
else
{
error_msg("Expected a keyword or option.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
}
}
return (opt);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_named_logk(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads K's that can be used to calculate K's for species
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
int l;
int i, empty;
class logk *logk_ptr;
char token[MAX_LENGTH];
int return_value, opt, opt_save;
const char* next_char;
const char *opt_list[] = {
"log_k", /* 0 */
"logk", /* 1 */
"delta_h", /* 2 */
"deltah", /* 3 */
"analytical_expression", /* 4 */
"a_e", /* 5 */
"ae", /* 6 */
"ln_alpha1000", /* 7 */
"add_logk", /* 8 */
"add_log_k", /* 9 */
"vm" /* 10 */
};
int count_opt_list = 11;
logk_ptr = NULL;
/*
* Read name followed by options
*/
opt_save = OPTION_DEFAULT;
return_value = UNKNOWN;
for (;;)
{
opt = get_option(opt_list, count_opt_list, &next_char);
if (opt == OPTION_DEFAULT)
{
opt = opt_save;
}
opt_save = OPTION_DEFAULT;
switch (opt)
{
case OPTION_EOF: /* end of file */
return_value = EOF;
break;
case OPTION_KEYWORD: /* keyword */
return_value = KEYWORD;
break;
case OPTION_ERROR:
input_error++;
error_msg("Unknown input in SPECIES keyword.", CONTINUE);
error_msg(line_save, CONTINUE);
break;
case 0: /* log_k */
case 1: /* logk */
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_log_k_only(next_char, &logk_ptr->log_k[0]);
logk_copy2orig(logk_ptr);
opt_save = OPTION_DEFAULT;
break;
case 2: /* delta_h */
case 3: /* deltah */
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_delta_h_only(next_char, &logk_ptr->log_k[1],
&logk_ptr->original_units);
logk_copy2orig(logk_ptr);
opt_save = OPTION_DEFAULT;
break;
case 4: /* analytical_expression */
case 5: /* a_e */
case 6: /* ae */
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_analytical_expression_only(next_char, &(logk_ptr->log_k[T_A1]));
logk_copy2orig(logk_ptr);
opt_save = OPTION_DEFAULT;
break;
case 7: /* ln_alpha1000 */
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
empty = TRUE;
for (i = T_A1; i <= T_A6; i++)
{
if (logk_ptr->log_k[i] != 0.0)
{
empty = FALSE;
logk_ptr->log_k[i] = 0.0;
}
}
if (empty == FALSE)
{
error_string = sformatf(
"Analytical expression previously defined for %s in NAMED_EXPRESSIONS\nAnalytical expression will be overwritten.",
logk_ptr->name);
warning_msg(error_string);
}
read_analytical_expression_only(next_char, &(logk_ptr->log_k[T_A1]));
for (i = T_A1; i < T_A6; i++)
{
logk_ptr->log_k[i] /= 1000. * LOG_10;
}
logk_copy2orig(logk_ptr);
opt_save = OPTION_DEFAULT;
break;
case 8: /* add_logk */
case 9: /* add_log_k */
{
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
size_t count_add_logk = logk_ptr->add_logk.size();
logk_ptr->add_logk.resize(count_add_logk + 1);
/* read name */
if (copy_token(token, &next_char, &i) == EMPTY)
{
input_error++;
error_string = sformatf(
"Expected the name of a NAMED_EXPRESSION.");
error_msg(error_string, CONTINUE);
break;
}
logk_ptr->add_logk[count_add_logk].name =
string_hsave(token);
/* read coef */
i = sscanf(next_char, SCANFORMAT,
&logk_ptr->add_logk[count_add_logk].coef);
if (i <= 0)
{
logk_ptr->add_logk[count_add_logk].coef = 1;
}
opt_save = OPTION_DEFAULT;
}
break;
case 10: /* vm, molar volume */
if (logk_ptr == NULL)
{
error_string = sformatf(
"No reaction defined before option, %s.",
opt_list[opt]);
error_msg(error_string, CONTINUE);
input_error++;
break;
}
read_vm_only(next_char, &logk_ptr->log_k[vm0],
&logk_ptr->original_deltav_units);
logk_copy2orig(logk_ptr);
opt_save = OPTION_DEFAULT;
break;
case OPTION_DEFAULT:
/*
* Get space for logk information
*/
logk_ptr = NULL;
copy_token(token, &next_char, &l);
logk_ptr = logk_store(token, TRUE);
/*
* Get pointer to each species in the reaction, store new species if necessary
*/
opt_save = OPTION_DEFAULT;
break;
}
if (return_value == EOF || return_value == KEYWORD)
break;
}
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_copy(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads solution,
* equilibrium_phases,
* exchange,
* surface,
* solid_solution,
* gas_phase,
* kinetics,
* mix,
* reaction,
* reaction_temperature
*
*/
int i, l, n, n_user, n_user_start, n_user_end, return_value;
const char* cptr;
char token[MAX_LENGTH], token1[MAX_LENGTH], nonkeyword[MAX_LENGTH];
/*
* Read "copy"
*/
cptr = line;
copy_token(token, &cptr, &l);
/*
* Read keyword
*/
copy_token(token, &cptr, &l);
check_key(token);
switch (next_keyword)
{
case Keywords::KEY_NONE: /* Have not read line with keyword */
Utilities::strcpy_safe(nonkeyword, MAX_LENGTH, token);
break;
case Keywords::KEY_SOLUTION: /* Solution */
case Keywords::KEY_EQUILIBRIUM_PHASES: /* Pure phases */
case Keywords::KEY_REACTION: /* Reaction */
case Keywords::KEY_MIX: /* Mix */
case Keywords::KEY_EXCHANGE: /* Ex */
case Keywords::KEY_SURFACE: /* Surface */
case Keywords::KEY_REACTION_TEMPERATURE: /* Temperature */
case Keywords::KEY_REACTION_PRESSURE: /* Pressure */
case Keywords::KEY_GAS_PHASE: /* Gas */
case Keywords::KEY_KINETICS: /* Kinetics */
case Keywords::KEY_SOLID_SOLUTIONS: /* solid_solutions */
break;
default:
input_error++;
error_msg
("Expecting keyword solution, mix, kinetics, reaction, reaction_pressure, reaction_temperature, equilibrium_phases, exchange, surface, gas_phase, or solid_solutions, or cell.",
CONTINUE);
error_msg(line_save, CONTINUE);
check_line("End of use", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (ERROR);
}
/*
* Read source index
*/
Utilities::strcpy_safe(token1, MAX_LENGTH, token);
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
(void)sscanf(token, "%d", &n_user);
//if (n_user < 0)
//{
// error_msg("Source index number must be a positive integer.",
// CONTINUE);
// error_msg(line_save, CONTINUE);
// input_error++;
// return (ERROR);
//}
//if (strstr(token, "-") != NULL)
//{
// error_msg
// ("COPY does not accept a range of numbers for source index",
// CONTINUE);
// error_msg(line_save, CONTINUE);
// input_error++;
// return (ERROR);
//}
}
else
{
error_msg("Source index number must be an integer.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
/*
* Read target index or range of indices
*/
i = copy_token(token, &cptr, &l);
if (i == DIGIT)
{
replace("-", " ", &token[1]);
n = sscanf(token, "%d%d", &n_user_start, &n_user_end);
if (n == 1)
{
n_user_end = n_user_start;
}
}
else
{
error_msg("Target index number must be an integer.",
CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
switch (next_keyword)
{
case Keywords::KEY_NONE:
str_tolower(nonkeyword);
if (strstr(nonkeyword, "cell") != nonkeyword)
{
error_msg("Unknown input in COPY data block.", CONTINUE);
error_msg(line_save, CONTINUE);
input_error++;
return (ERROR);
}
copier_add(&copy_solution, n_user, n_user_start, n_user_end);
copier_add(&copy_pp_assemblage, n_user, n_user_start, n_user_end);
copier_add(&copy_reaction, n_user, n_user_start, n_user_end);
copier_add(&copy_mix, n_user, n_user_start, n_user_end);
copier_add(&copy_exchange, n_user, n_user_start, n_user_end);
copier_add(&copy_surface, n_user, n_user_start, n_user_end);
copier_add(&copy_temperature, n_user, n_user_start, n_user_end);
copier_add(&copy_pressure, n_user, n_user_start, n_user_end);
copier_add(&copy_gas_phase, n_user, n_user_start, n_user_end);
copier_add(&copy_kinetics, n_user, n_user_start, n_user_end);
copier_add(&copy_ss_assemblage, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_SOLUTION: /* Solution */
copier_add(&copy_solution, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_EQUILIBRIUM_PHASES: /* Pure phases */
copier_add(&copy_pp_assemblage, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_REACTION: /* Reaction */
copier_add(&copy_reaction, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_MIX: /* Mix */
copier_add(&copy_mix, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_EXCHANGE: /* Ex */
copier_add(&copy_exchange, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_SURFACE: /* Surface */
copier_add(&copy_surface, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_REACTION_TEMPERATURE: /* Temperature */
copier_add(&copy_temperature, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_REACTION_PRESSURE: /* Pressure */
copier_add(&copy_pressure, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_GAS_PHASE: /* Gas */
copier_add(&copy_gas_phase, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_KINETICS: /* Kinetics */
copier_add(&copy_kinetics, n_user, n_user_start, n_user_end);
break;
case Keywords::KEY_SOLID_SOLUTIONS: /* solid_solutions */
copier_add(&copy_ss_assemblage, n_user, n_user_start, n_user_end);
break;
default:
error_msg("Error in switch for READ_COPY.", STOP);
break;
}
return_value = check_line("End of COPY", FALSE, TRUE, TRUE, TRUE);
/* empty, eof, keyword, print */
return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_reaction_pressure(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads REACTION_PRESSURE data block
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
assert(!reading_database());
// Make instance, set n_user, n_user_end, description
cxxPressure atm(this->phrq_io);
const char* cptr = line;
atm.read_number_description(cptr);
int n_user = atm.Get_n_user();
/*
* Make parser
*/
CParser parser(this->phrq_io);
if (pr.echo_input == FALSE) parser.set_echo_file(CParser::EO_NONE);
atm.read(parser);
if (atm.Get_base_error_count() == 0)
{
Rxn_pressure_map[n_user] = atm;
}
if (use.Get_pressure_in() == FALSE)
{
use.Set_pressure_in(true);
use.Set_n_pressure_user(atm.Get_n_user());
}
// Make copies if necessary
if (atm.Get_n_user_end() > n_user)
{
int i;
for (i = n_user + 1; i <= atm.Get_n_user_end(); i++)
{
Utilities::Rxn_copy(Rxn_pressure_map, n_user, i);
}
}
return cleanup_after_parser(parser);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_reaction_pressure_raw(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads REACTION_PRESSURE_RAW data block
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
assert(!reading_database());
cxxPressure atm(this->phrq_io);
/*
* Make parser
*/
CParser parser(this->phrq_io);
if (pr.echo_input == FALSE) parser.set_echo_file(CParser::EO_NONE);
atm.read_raw(parser);
// Store
if (atm.Get_base_error_count() == 0)
{
Rxn_pressure_map[atm.Get_n_user()] = atm;
}
// Make copies if necessary
Utilities::Rxn_copies(Rxn_pressure_map, atm.Get_n_user(), atm.Get_n_user_end());
return cleanup_after_parser(parser);
}
int Phreeqc::
cleanup_after_parser(CParser &parser)
{
// check_key sets next_keyword
if (parser.get_m_line_type() == PHRQ_io::LT_EOF)
{
Utilities::strcpy_safe(line, max_line, "");
Utilities::strcpy_safe(line_save, max_line, "");
next_keyword = Keywords::KEY_END;
return(TRUE);
}
int return_value = check_key(parser.line().c_str());
// copy parser line to line and line_save
// make sure there is enough space
size_t l1 = strlen(parser.line().c_str()) + 1;
size_t l2 = strlen(parser.line_save().c_str()) + 1;
size_t l = (l1 > l2) ? l1 : l2;
if (l >= (size_t) max_line)
{
max_line = (int) l * 2;
line_save = (char *) PHRQ_realloc(line_save,
(size_t) max_line * sizeof(char));
if (line_save == NULL)
malloc_error();
line = (char *) PHRQ_realloc(line, (size_t) max_line * sizeof(char));
if (line == NULL)
malloc_error();
}
Utilities::strcpy_safe(line, max_line, parser.line().c_str());
Utilities::strcpy_safe(line_save, max_line, parser.line_save().c_str());
return return_value;
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_temperature(void)
/* ---------------------------------------------------------------------- */
{
/*
* Reads REACTION_TEMPERATURE data block
*
* Arguments:
* none
*
* Returns:
* KEYWORD if keyword encountered, input_error may be incremented if
* a keyword is encountered in an unexpected position
* EOF if eof encountered while reading mass balance concentrations
* ERROR if error occurred reading data
*
*/
assert(!reading_database());
// Make instance, set n_user, n_user_end, description
cxxTemperature t_react(this->phrq_io);
const char* cptr = line;
t_react.read_number_description(cptr);
int n_user = t_react.Get_n_user();
/*
* Make parser
*/
CParser parser(this->phrq_io);
if (pr.echo_input == FALSE) parser.set_echo_file(CParser::EO_NONE);
t_react.read(parser);
if (t_react.Get_base_error_count() == 0)
{
Rxn_temperature_map[n_user] = t_react;
}
if (use.Get_temperature_in() == FALSE)
{
use.Set_temperature_in(true);
use.Set_n_temperature_user(t_react.Get_n_user());
}
// Make copies if necessary
if (t_react.Get_n_user_end() > n_user)
{
int i;
for (i = n_user + 1; i <= t_react.Get_n_user_end(); i++)
{
Utilities::Rxn_copy(Rxn_temperature_map, n_user, i);
}
}
return cleanup_after_parser(parser);
}