mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-15 16:18:22 +01:00
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
10246 lines
251 KiB
C++
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(©_solution, n_user, n_user_start, n_user_end);
|
|
copier_add(©_pp_assemblage, n_user, n_user_start, n_user_end);
|
|
copier_add(©_reaction, n_user, n_user_start, n_user_end);
|
|
copier_add(©_mix, n_user, n_user_start, n_user_end);
|
|
copier_add(©_exchange, n_user, n_user_start, n_user_end);
|
|
copier_add(©_surface, n_user, n_user_start, n_user_end);
|
|
copier_add(©_temperature, n_user, n_user_start, n_user_end);
|
|
copier_add(©_pressure, n_user, n_user_start, n_user_end);
|
|
copier_add(©_gas_phase, n_user, n_user_start, n_user_end);
|
|
copier_add(©_kinetics, n_user, n_user_start, n_user_end);
|
|
copier_add(©_ss_assemblage, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_SOLUTION: /* Solution */
|
|
copier_add(©_solution, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_EQUILIBRIUM_PHASES: /* Pure phases */
|
|
copier_add(©_pp_assemblage, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_REACTION: /* Reaction */
|
|
copier_add(©_reaction, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_MIX: /* Mix */
|
|
copier_add(©_mix, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_EXCHANGE: /* Ex */
|
|
copier_add(©_exchange, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_SURFACE: /* Surface */
|
|
copier_add(©_surface, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_REACTION_TEMPERATURE: /* Temperature */
|
|
copier_add(©_temperature, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_REACTION_PRESSURE: /* Pressure */
|
|
copier_add(©_pressure, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_GAS_PHASE: /* Gas */
|
|
copier_add(©_gas_phase, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_KINETICS: /* Kinetics */
|
|
copier_add(©_kinetics, n_user, n_user_start, n_user_end);
|
|
break;
|
|
case Keywords::KEY_SOLID_SOLUTIONS: /* solid_solutions */
|
|
copier_add(©_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);
|
|
}
|