mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-15 16:18:22 +01:00
b4a1f672 Merge commit '3c8e294fd35563abbf53316d100d9f900e2b5b5a' 3c8e294f Squashed 'phreeqcpp/' changes from c369020..b948e30 git-subtree-dir: src git-subtree-split: b4a1f672db7d7203a306a7c499cf8c67142da2bc
5601 lines
154 KiB
C++
5601 lines
154 KiB
C++
#include "Utils.h"
|
|
#include "Phreeqc.h"
|
|
#include "phqalloc.h"
|
|
#include "Exchange.h"
|
|
#include "GasPhase.h"
|
|
#include "PPassemblage.h"
|
|
#include "SSassemblage.h"
|
|
#include "cxxKinetics.h"
|
|
#include "Solution.h"
|
|
|
|
#define ZERO_TOL 1.0e-30
|
|
|
|
#if defined(PHREEQCI_GUI)
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_model(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int n_user, last;
|
|
int new_named_logk;
|
|
/*
|
|
* Determine if any new elements, species, phases have been read
|
|
*/
|
|
overall_iterations = 0;
|
|
state = INITIALIZE;
|
|
new_model = FALSE;
|
|
new_pp_assemblage = FALSE;
|
|
new_surface = FALSE;
|
|
new_exchange = FALSE;
|
|
new_reaction = FALSE;
|
|
new_temperature = FALSE;
|
|
new_mix = FALSE;
|
|
new_solution = FALSE;
|
|
new_gas_phase = FALSE;
|
|
new_inverse = FALSE;
|
|
new_punch = FALSE;
|
|
new_surface = FALSE;
|
|
new_ss_assemblage = FALSE;
|
|
new_kinetics = FALSE;
|
|
new_pitzer = FALSE;
|
|
new_named_logk = FALSE;
|
|
|
|
if (keycount[Keywords::KEY_SOLUTION_SPECIES] > 0 || /*"species" */
|
|
keycount[Keywords::KEY_SOLUTION_MASTER_SPECIES] > 0 || /*"master" */
|
|
keycount[Keywords::KEY_PHASES] > 0 || /*"phases" */
|
|
keycount[Keywords::KEY_EXCHANGE_SPECIES] > 0 || /*"exchange_species" */
|
|
keycount[Keywords::KEY_EXCHANGE_MASTER_SPECIES] > 0 || /*"master_exchange_species" */
|
|
keycount[Keywords::KEY_SURFACE_SPECIES] > 0 || /*"surface_species" */
|
|
keycount[Keywords::KEY_SURFACE_MASTER_SPECIES] > 0 || /*"master_surface_species" */
|
|
keycount[Keywords::KEY_RATES] > 0 || /*"rates" */
|
|
keycount[Keywords::KEY_LLNL_AQUEOUS_MODEL_PARAMETERS] > 0 || /*"llnl_aqueous_model_parameters" */
|
|
(keycount[Keywords::KEY_DATABASE] > 0 && simulation == 0) || /*"database" */
|
|
keycount[Keywords::KEY_NAMED_EXPRESSIONS] > 0 || /*"named_analytical_expressions" */
|
|
keycount[Keywords::KEY_ISOTOPES] > 0 || /*"isotopes" */
|
|
keycount[Keywords::KEY_CALCULATE_VALUES] > 0 || /*"calculate_values" */
|
|
keycount[Keywords::KEY_ISOTOPE_RATIOS] > 0 || /*"isotopes_ratios", */
|
|
keycount[Keywords::KEY_ISOTOPE_ALPHAS] > 0 || /*"isotopes_alphas" */
|
|
keycount[Keywords::KEY_PITZER] > 0 || /*"pitzer" */
|
|
keycount[Keywords::KEY_SIT] > 0 /*"sit" */
|
|
)
|
|
{
|
|
new_model = TRUE;
|
|
}
|
|
if (keycount[Keywords::KEY_EQUILIBRIUM_PHASES] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_MODIFY])
|
|
{
|
|
new_pp_assemblage = TRUE; /*"pure_phases" */
|
|
}
|
|
if (keycount[Keywords::KEY_SURFACE] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_MODIFY])
|
|
{
|
|
new_surface = TRUE; /*"surface" */
|
|
}
|
|
if (keycount[Keywords::KEY_EXCHANGE] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_MODIFY])
|
|
{
|
|
new_exchange = TRUE; /*"exchange" */
|
|
}
|
|
if (keycount[Keywords::KEY_REACTION] > 0 /*||
|
|
keycount[Keywords::KEY_REACTION_RAW] > 0 ||
|
|
keycount[Keywords::KEY_REACTION_MODIFY]*/)
|
|
{
|
|
new_reaction = TRUE; /*"reaction" */
|
|
}
|
|
if (keycount[Keywords::KEY_REACTION_TEMPERATURE] > 0 /*||
|
|
keycount[Keywords::KEY_REACTION_TEMPERATURE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_REACTION_TEMPERATURE_MODIFY]*/)
|
|
{
|
|
new_temperature = TRUE; /*"reacton_temperature" */
|
|
}
|
|
if (keycount[Keywords::KEY_MIX] > 0 ||
|
|
keycount[Keywords::KEY_MIX_RAW] > 0)
|
|
{
|
|
new_mix = TRUE; /*"mix" */
|
|
}
|
|
if (keycount[Keywords::KEY_SOLUTION] > 0 ||
|
|
keycount[Keywords::KEY_SOLUTION_SPREAD] > 0 ||
|
|
keycount[Keywords::KEY_SOLUTION_RAW] > 0 ||
|
|
keycount[Keywords::KEY_SOLUTION_MODIFY])
|
|
{ /*"solution" */
|
|
new_solution = TRUE;
|
|
}
|
|
if (keycount[Keywords::KEY_GAS_PHASE] > 0 ||
|
|
keycount[Keywords::KEY_GAS_PHASE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_GAS_PHASE_MODIFY])
|
|
{
|
|
new_gas_phase = TRUE; /*"gas_phase" */
|
|
}
|
|
if (keycount[Keywords::KEY_SOLID_SOLUTIONS] > 0 ||
|
|
keycount[Keywords::KEY_SOLID_SOLUTIONS_RAW] > 0 ||
|
|
keycount[Keywords::KEY_SOLID_SOLUTIONS_MODIFY])
|
|
{
|
|
new_ss_assemblage = TRUE; /*"solid_solutions" */
|
|
}
|
|
if (keycount[Keywords::KEY_KINETICS] > 0 /*||
|
|
keycount[Keywords::KEY_KINETICS_RAW] > 0 ||
|
|
keycount[Keywords::KEY_KINETICS_MODIFY]*/)
|
|
{
|
|
new_kinetics = TRUE; /*"kinetics" */
|
|
}
|
|
if (keycount[Keywords::KEY_INVERSE_MODELING] > 0)
|
|
{
|
|
new_inverse = TRUE; /*"inverse_modeling" */
|
|
}
|
|
if (keycount[Keywords::KEY_SELECTED_OUTPUT] > 0 || /*"selected_output" */
|
|
keycount[Keywords::KEY_USER_PUNCH] > 0) /*"user_punch" */
|
|
{
|
|
new_punch = TRUE;
|
|
}
|
|
|
|
if (keycount[Keywords::KEY_COPY] > 0)
|
|
{
|
|
new_copy = TRUE; /*"copy" */
|
|
}
|
|
if (keycount[Keywords::KEY_PITZER] > 0)
|
|
{
|
|
new_pitzer = TRUE; /*"pitzer" */
|
|
}
|
|
if (keycount[Keywords::KEY_NAMED_EXPRESSIONS] > 0)
|
|
{
|
|
new_named_logk = TRUE; /*"named_log_k" */
|
|
}
|
|
|
|
/*
|
|
* Sort arrays
|
|
*/
|
|
|
|
if (new_model == TRUE)
|
|
{
|
|
/* species */
|
|
if (s.size() > 1) //qsort(&s[0], s.size(), sizeof(class species*), s_compare);
|
|
{
|
|
s.clear();
|
|
std::map<std::string, class species*>::iterator it;
|
|
for (it = species_map.begin(); it != species_map.end(); it++)
|
|
{
|
|
s.push_back(it->second);
|
|
}
|
|
}
|
|
/* master species */
|
|
if (master.size() > 1) qsort(&master[0], master.size(), sizeof(class master*), master_compare);
|
|
/* elements */
|
|
if (elements.size() > 1) //qsort(&elements[0], elements.size(), sizeof(class element*), element_compare);
|
|
{
|
|
elements.clear();
|
|
std::map<std::string, class element*>::iterator it;
|
|
for (it = elements_map.begin(); it != elements_map.end(); it++)
|
|
{
|
|
elements.push_back(it->second);
|
|
}
|
|
} /* phases */
|
|
if (phases.size() > 1) //qsort(&phases[0], phases.size(), sizeof(class phase *), phase_compare);
|
|
{
|
|
phases.clear();
|
|
std::map<std::string, class phase*>::iterator it;
|
|
for (it = phases_map.begin(); it != phases_map.end(); it++)
|
|
{
|
|
phases.push_back(it->second);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* named_log_k */
|
|
if (new_named_logk)
|
|
{
|
|
tidy_logk();
|
|
}
|
|
/*
|
|
* Check pointers, write reactions for species
|
|
*/
|
|
if (new_model)
|
|
{
|
|
sum_species_map.clear();
|
|
|
|
tidy_species();
|
|
|
|
tidy_phases();
|
|
|
|
tidy_master_isotope();
|
|
/*
|
|
* calculate gfw of water, kg/mole
|
|
*/
|
|
compute_gfw("H2O", &gfw_water);
|
|
gfw_water *= 0.001;
|
|
}
|
|
/*
|
|
* tidy surface data
|
|
*/
|
|
if (new_model || new_surface)
|
|
{
|
|
tidy_surface();
|
|
}
|
|
/*
|
|
* tidy inverse data
|
|
*/
|
|
if (new_inverse)
|
|
{
|
|
tidy_inverse();
|
|
}
|
|
/*
|
|
* tidy gas phase data
|
|
*/
|
|
if (new_gas_phase)
|
|
{
|
|
tidy_gas_phase();
|
|
}
|
|
/*
|
|
* tidy pp_assemblage data
|
|
*/
|
|
if (new_model || new_pp_assemblage)
|
|
{
|
|
tidy_pp_assemblage();
|
|
}
|
|
/*
|
|
* tidy ss_assemblage data
|
|
*/
|
|
if (new_model || new_ss_assemblage)
|
|
{
|
|
tidy_ss_assemblage();
|
|
}
|
|
/*
|
|
* tidy exchange data, after pp_assemblages
|
|
*/
|
|
if (new_exchange)
|
|
{
|
|
tidy_exchange();
|
|
tidy_min_exchange();
|
|
tidy_kin_exchange();
|
|
}
|
|
/*
|
|
* tidy surface data
|
|
*/
|
|
if (new_surface)
|
|
{
|
|
tidy_min_surface();
|
|
tidy_kin_surface();
|
|
}
|
|
/*
|
|
* tidy solution isotope data
|
|
*/
|
|
if (new_solution)
|
|
{
|
|
tidy_isotopes();
|
|
}
|
|
if (new_model)
|
|
{
|
|
tidy_isotope_ratios();
|
|
tidy_isotope_alphas();
|
|
}
|
|
/*
|
|
* Duplicate kinetics
|
|
*/
|
|
if (new_kinetics)
|
|
{
|
|
std::map<int, cxxKinetics>::iterator it;
|
|
for (it = Rxn_kinetics_map.begin(); it != Rxn_kinetics_map.end(); it++)
|
|
{
|
|
n_user = it->second.Get_n_user();
|
|
last = it->second.Get_n_user_end();
|
|
it->second.Set_n_user_end(n_user);
|
|
Utilities::Rxn_copies(Rxn_kinetics_map, n_user, last);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tidy pitzer information
|
|
*/
|
|
if (pitzer_model && new_model)
|
|
{
|
|
pitzer_tidy();
|
|
}
|
|
/*
|
|
* Tidy SIT information
|
|
*/
|
|
if (sit_model && new_model)
|
|
{
|
|
sit_tidy();
|
|
}
|
|
/*
|
|
* Tidy punch information
|
|
*/
|
|
if (get_input_errors() == 0 && (new_punch || new_model))
|
|
{
|
|
tidy_punch();
|
|
}
|
|
/*
|
|
* Tidy solution information
|
|
*/
|
|
if (new_solution)
|
|
{
|
|
tidy_solutions();
|
|
}
|
|
/*
|
|
* need to update exchange and surface related in case anything has changed
|
|
*/
|
|
if (keycount[Keywords::KEY_KINETICS] > 0 ||
|
|
keycount[Keywords::KEY_KINETICS_RAW] > 0 ||
|
|
keycount[Keywords::KEY_KINETICS_MODIFY] ||
|
|
keycount[Keywords::KEY_EXCHANGE] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_MODIFY])
|
|
{
|
|
update_kin_exchange();
|
|
}
|
|
if (keycount[Keywords::KEY_EQUILIBRIUM_PHASES] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_MODIFY] ||
|
|
keycount[Keywords::KEY_EXCHANGE] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EXCHANGE_MODIFY])
|
|
{
|
|
update_min_exchange();
|
|
}
|
|
if (keycount[Keywords::KEY_EQUILIBRIUM_PHASES] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_RAW] > 0 ||
|
|
keycount[Keywords::KEY_EQUILIBRIUM_PHASES_MODIFY] ||
|
|
keycount[Keywords::KEY_SURFACE] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_MODIFY] > 0)
|
|
{
|
|
update_min_surface();
|
|
}
|
|
if (keycount[Keywords::KEY_KINETICS] > 0 ||
|
|
keycount[Keywords::KEY_KINETICS_RAW] > 0 ||
|
|
keycount[Keywords::KEY_KINETICS_MODIFY] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_RAW] > 0 ||
|
|
keycount[Keywords::KEY_SURFACE_MODIFY] > 0)
|
|
{
|
|
update_kin_surface();
|
|
}
|
|
/* if (new_model || new_exchange || new_pp_assemblage || new_surface || new_gas_phase || new_kinetics) reset_last_model(); */
|
|
if (new_model)
|
|
{
|
|
reset_last_model();
|
|
}
|
|
/*
|
|
* make sure essential species are defined
|
|
*/
|
|
//if (new_model)
|
|
{
|
|
if (s_h2o == NULL)
|
|
{
|
|
input_error++;
|
|
//error_msg("H2O not defined.", STOP);
|
|
error_msg("H2O not defined.", CONTINUE);
|
|
}
|
|
else
|
|
{
|
|
if (s_h2o->primary == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H2O, primary master species for O, not defined.",
|
|
CONTINUE);
|
|
}
|
|
if (s_h2o->secondary == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H2O, secondary master species for O(-2), not defined.",
|
|
CONTINUE);
|
|
}
|
|
if (s_h2o->type != H2O)
|
|
{
|
|
input_error++;
|
|
error_msg("H2O can only be defined in SOLUTION_SPECIES.",
|
|
CONTINUE);
|
|
}
|
|
}
|
|
if (s_hplus == NULL && s_h3oplus == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("Neither H+ nor H3O+ are defined in solution_species.",
|
|
STOP);
|
|
}
|
|
else if (s_hplus == NULL && s_h3oplus != NULL)
|
|
{
|
|
s_hplus = s_h3oplus;
|
|
s_h3oplus = NULL;
|
|
}
|
|
else if (s_hplus != NULL && s_h3oplus == NULL)
|
|
{
|
|
}
|
|
else if (s_hplus != NULL && s_h3oplus != NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("Cannot define both H+ and H3O+ in solution_species.",
|
|
STOP);
|
|
}
|
|
if (s_hplus->primary == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H3O+, primary master species for H, not defined.",
|
|
CONTINUE);
|
|
}
|
|
if (s_hplus->secondary == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H3O+, secondary master species for H(1), not defined.",
|
|
CONTINUE);
|
|
}
|
|
if (s_eminus == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("e- not defined in solution_species.", CONTINUE);
|
|
}
|
|
if (s_eminus->primary == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("e-, primary master species for E-, not defined.",
|
|
CONTINUE);
|
|
}
|
|
if (pitzer_model == FALSE || pitzer_pe == TRUE)
|
|
{
|
|
if (s_h2 == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H2(aq) not defined in solution_species.", CONTINUE);
|
|
}
|
|
if (s_o2 == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("O2(aq) not defined in solution_species.", CONTINUE);
|
|
}
|
|
}
|
|
element_h_one = element_store("H(1)");
|
|
if (element_h_one == NULL)
|
|
{
|
|
input_error++;
|
|
error_msg("H(1) not defined in solution_master_species.", CONTINUE);
|
|
}
|
|
}
|
|
/*
|
|
* Error check, program termination
|
|
*/
|
|
if (get_input_errors() > 0 || parse_error > 0)
|
|
{
|
|
error_msg("Calculations terminating due to input errors.", STOP);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
check_species_input(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Check species data for completeness
|
|
*/
|
|
int i;
|
|
int return_value;
|
|
|
|
return_value = OK;
|
|
for (i = 0; i < (int)s.size(); i++)
|
|
{
|
|
if (s[i]->next_elt.size() == 0)
|
|
{
|
|
input_error++;
|
|
return_value = ERROR;
|
|
error_string = sformatf(
|
|
"Elements in species have not been tabulated, %s.",
|
|
s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
if (s[i]->rxn.token.size() == 0)
|
|
{
|
|
input_error++;
|
|
return_value = ERROR;
|
|
error_string = sformatf(
|
|
"Reaction for species has not been defined, %s.",
|
|
s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
else
|
|
{
|
|
select_log_k_expression(s[i]->logk, s[i]->rxn.logk);
|
|
add_other_logk(s[i]->rxn.logk, s[i]->add_logk);
|
|
}
|
|
}
|
|
return (return_value);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
select_log_k_expression(LDBLE * source_k, LDBLE * target_k)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int j;
|
|
bool analytic;
|
|
|
|
analytic = false;
|
|
for (j = T_A1; j <= T_A6; j++)
|
|
{
|
|
if (source_k[j] != 0.0)
|
|
{
|
|
analytic = true;
|
|
break;
|
|
}
|
|
}
|
|
if (analytic)
|
|
{
|
|
target_k[logK_T0] = 0.0;
|
|
target_k[delta_h] = 0.0;
|
|
for (j = T_A1; j <= T_A6; j++)
|
|
{
|
|
target_k[j] = source_k[j];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
target_k[logK_T0] = source_k[logK_T0];
|
|
target_k[delta_h] = source_k[delta_h];
|
|
for (j = T_A1; j <= T_A6; j++)
|
|
{
|
|
target_k[j] = 0.0;
|
|
}
|
|
}
|
|
for (j = delta_v; j < MAX_LOG_K_INDICES; j++)
|
|
{
|
|
target_k[j] = source_k[j];
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_logk(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Picks log k expression
|
|
*/
|
|
{
|
|
int i;
|
|
for (i = 0; i < (int)logk.size(); i++)
|
|
{
|
|
select_log_k_expression(logk[i]->log_k_original, logk[i]->log_k);
|
|
logk[i]->done = FALSE;
|
|
}
|
|
for (i = 0; i < (int)logk.size(); i++)
|
|
{
|
|
if (logk[i]->done == FALSE)
|
|
{
|
|
add_logks(logk[i], 0);
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
add_other_logk(LDBLE * source_k, std::vector<class name_coef> &add_logk)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int j;
|
|
bool analytic;
|
|
class logk *logk_ptr;
|
|
LDBLE coef;
|
|
|
|
for (size_t i = 0; i < add_logk.size(); i++)
|
|
{
|
|
coef = add_logk[i].coef;
|
|
std::string token = add_logk[i].name;
|
|
str_tolower(token);
|
|
std::map<std::string, class logk *>::iterator l_it = logk_map.find(token);
|
|
if (l_it == logk_map.end())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Could not find named temperature expression, %s\n",
|
|
token.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
logk_ptr = l_it->second;
|
|
analytic = false;
|
|
for (j = T_A1; j <= T_A6; j++)
|
|
{
|
|
if (logk_ptr->log_k[j] != 0.0)
|
|
{
|
|
analytic = true;
|
|
break;
|
|
}
|
|
}
|
|
if (analytic)
|
|
{
|
|
for (j = T_A1; j <= T_A6; j++)
|
|
{
|
|
source_k[j] += logk_ptr->log_k[j] * coef;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
source_k[logK_T0] += logk_ptr->log_k[logK_T0] * coef;
|
|
source_k[delta_h] += logk_ptr->log_k[delta_h] * coef;
|
|
}
|
|
for (j = delta_v; j < MAX_LOG_K_INDICES; j++)
|
|
{
|
|
source_k[j] += logk_ptr->log_k[j] * coef;
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
add_logks(class logk *logk_ptr, int repeats)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j;
|
|
class logk *next_logk_ptr;
|
|
LDBLE coef;
|
|
/*
|
|
* Adds in other named_expressions to get complete log K
|
|
* Evaluates others recursively if necessary
|
|
*/
|
|
if (repeats > 15)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Circular definition of named_logk? %s\n",
|
|
logk_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
for (i = 0; i < (int)logk_ptr->add_logk.size(); i++)
|
|
{
|
|
coef = logk_ptr->add_logk[i].coef;
|
|
std::string token = logk_ptr->add_logk[i].name;
|
|
str_tolower(token);
|
|
std::map<std::string, class logk*>::iterator l_it = logk_map.find(token);
|
|
if (l_it == logk_map.end())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Could not find named temperature expression, %s\n",
|
|
token.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
next_logk_ptr = l_it->second;
|
|
if (next_logk_ptr->done == FALSE)
|
|
{
|
|
/*output_msg(sformatf( "Done == FALSE\n", token)); */
|
|
if (add_logks(next_logk_ptr, repeats + 1) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
}
|
|
for (j = 0; j < MAX_LOG_K_INDICES; j++)
|
|
{
|
|
logk_ptr->log_k[j] += next_logk_ptr->log_k[j] * coef;
|
|
}
|
|
}
|
|
logk_ptr->done = TRUE;
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
coef_in_master(class master * master_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int l;
|
|
LDBLE coef;
|
|
const char* cptr;
|
|
std::string elt_name;
|
|
const class elt_list *next_elt;
|
|
|
|
coef = 0.0;
|
|
cptr = master_ptr->elt->name;
|
|
get_elt(&cptr, elt_name, &l);
|
|
for (next_elt = &master_ptr->s->next_elt[0]; next_elt->elt != NULL;
|
|
next_elt++)
|
|
{
|
|
if (strcmp(elt_name.c_str(), next_elt->elt->name) == 0)
|
|
{
|
|
coef = next_elt->coef;
|
|
break;
|
|
}
|
|
}
|
|
return (coef);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
rewrite_eqn_to_secondary(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Write equation for species in terms of secondary species
|
|
* Result is in trxn.
|
|
*/
|
|
LDBLE coef;
|
|
int repeat, i, add_count;
|
|
class rxn_token_temp *token_ptr;
|
|
/*
|
|
*
|
|
*/
|
|
add_count = 0;
|
|
repeat = TRUE;
|
|
/*
|
|
* Reduce reaction equation to primary and secondary species
|
|
*/
|
|
while (repeat == TRUE)
|
|
{
|
|
repeat = FALSE;
|
|
/* Check for too many iterations */
|
|
if (++add_count > MAX_ADD_EQUATIONS)
|
|
{
|
|
parse_error++;
|
|
error_string = sformatf(
|
|
"Could not reduce equation to secondary master species, %s.",
|
|
trxn.token[0].name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
|
|
for (i = 1; i < count_trxn; i++)
|
|
{
|
|
token_ptr = &(trxn.token[i]);
|
|
if (token_ptr->s == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"NULL species pointer for species, %s.",
|
|
token_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
break;
|
|
}
|
|
if (token_ptr->s->secondary == NULL
|
|
&& token_ptr->s->primary == NULL)
|
|
{
|
|
coef = token_ptr->coef;
|
|
trxn_add(token_ptr->s->rxn, coef, true);
|
|
repeat = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
trxn_combine();
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
replace_solids_gases(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Write equation for species in terms of secondary species
|
|
* Result is in trxn.
|
|
*/
|
|
LDBLE coef;
|
|
int n;
|
|
int repeat, i, add_count;
|
|
class rxn_token_temp *token_ptr;
|
|
class phase *phase_ptr;
|
|
int replaced;
|
|
char token[MAX_LENGTH];
|
|
/*
|
|
*
|
|
*/
|
|
add_count = 0;
|
|
repeat = TRUE;
|
|
replaced = FALSE;
|
|
/*
|
|
* Reduce reaction equation to primary and secondary species
|
|
*/
|
|
while (repeat == TRUE)
|
|
{
|
|
repeat = FALSE;
|
|
/* Check for too many iterations */
|
|
if (++add_count > MAX_ADD_EQUATIONS)
|
|
{
|
|
parse_error++;
|
|
error_string = sformatf(
|
|
"Could not remove all solids and gases from equation, %s.",
|
|
trxn.token[0].name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
|
|
for (i = 1; i < count_trxn; i++)
|
|
{
|
|
token_ptr = &(trxn.token[i]);
|
|
if (token_ptr->s == NULL)
|
|
{
|
|
phase_ptr = phase_bsearch(token_ptr->name, &n, FALSE);
|
|
/* try phase name without (g) or (s) */
|
|
if (phase_ptr == NULL)
|
|
{
|
|
Utilities::strcpy_safe(token, MAX_LENGTH, token_ptr->name);
|
|
replace("(g)", "", token);
|
|
replace("(s)", "", token);
|
|
replace("(G)", "", token);
|
|
replace("(S)", "", token);
|
|
phase_ptr = phase_bsearch(token, &n, FALSE);
|
|
}
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Phase not found, %s.",
|
|
token_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
coef = token_ptr->coef;
|
|
/* add reaction for solid/gas */
|
|
/* debug
|
|
output_msg(sformatf( "Reaction to add.\n"));
|
|
rxn_print(phase_ptr->rxn);
|
|
*/
|
|
trxn_add_phase(phase_ptr->rxn, coef, false);
|
|
|
|
/* remove solid/gas from trxn list */
|
|
trxn.token[i].name = phase_ptr->rxn.token[0].name;
|
|
trxn.token[i].s = phase_ptr->rxn.token[0].s;
|
|
trxn.token[i].coef = -coef * phase_ptr->rxn.token[0].coef;
|
|
repeat = TRUE;
|
|
replaced = TRUE;
|
|
/* debug
|
|
output_msg(sformatf( "Before combined.\n"));
|
|
trxn_print();
|
|
*/
|
|
/* combine */
|
|
trxn_combine();
|
|
/* debug
|
|
output_msg(sformatf( "Combined.\n"));
|
|
trxn_print();
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
trxn_combine();
|
|
return (replaced);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
rewrite_eqn_to_primary(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Write equation for secondary master species in terms of primary master species
|
|
* Store result in reaction structure for master species
|
|
* rewrite if necessary.
|
|
*
|
|
*/
|
|
int repeat, j, add_count;
|
|
|
|
/*
|
|
* Check secondary master species
|
|
*/
|
|
repeat = TRUE;
|
|
add_count = 0;
|
|
/*
|
|
* Check if reaction contains only primary master species
|
|
*/
|
|
while (repeat == TRUE)
|
|
{
|
|
repeat = FALSE;
|
|
/*
|
|
* Check for too many iterations
|
|
*/
|
|
if (++add_count > MAX_ADD_EQUATIONS)
|
|
{
|
|
parse_error++;
|
|
error_string = sformatf(
|
|
"Could not reduce equation to primary master species, %s.",
|
|
trxn.token[0].s->name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
/*
|
|
* Go through species in reaction for secondary master species, look for non-primary
|
|
* species as reactants, rewrite
|
|
*/
|
|
for (j = 1; j < count_trxn; j++)
|
|
{
|
|
if (trxn.token[j].s->primary == NULL)
|
|
{
|
|
trxn_add(trxn.token[j].s->rxn, trxn.token[j].coef, true);
|
|
repeat = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
trxn_combine();
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_gas_phase(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int n_user, last;
|
|
LDBLE P, V_m;
|
|
bool PR;
|
|
/*
|
|
* Find all gases for each gas_phase in phase list
|
|
*/
|
|
for (std::set<int>::const_iterator nit = Rxn_new_gas_phase.begin(); nit != Rxn_new_gas_phase.end(); nit++)
|
|
{
|
|
std::map<int, cxxGasPhase>::iterator it = Rxn_gas_phase_map.find(*nit);
|
|
if (it == Rxn_gas_phase_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
cxxGasPhase *gas_phase_ptr = &(it->second);
|
|
PR = false;
|
|
P = 0.0;
|
|
for (size_t j = 0; j < gas_phase_ptr->Get_gas_comps().size(); j++)
|
|
{
|
|
int k;
|
|
class phase *phase_ptr = phase_bsearch(gas_phase_ptr->Get_gas_comps()[j].Get_phase_name().c_str(), &k, FALSE);
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Gas not found in PHASES database, %s.",
|
|
gas_phase_ptr->Get_gas_comps()[j].Get_phase_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (phase_ptr->t_c > 0 && phase_ptr->p_c > 0)
|
|
PR = true;
|
|
}
|
|
}
|
|
gas_phase_ptr->Set_pr_in(PR);
|
|
|
|
if (gas_phase_ptr->Get_new_def())
|
|
{
|
|
for (size_t j = 0; j < gas_phase_ptr->Get_gas_comps().size(); j++)
|
|
{
|
|
/*
|
|
* Fixed pressure
|
|
*/
|
|
if (gas_phase_ptr->Get_type() == cxxGasPhase::GP_PRESSURE)
|
|
{
|
|
if (gas_phase_ptr->Get_solution_equilibria())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Gas phase %d: cannot use '-equilibrium' option with fixed pressure gas phase.",
|
|
gas_phase_ptr->Get_n_user());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
/* calculate moles */
|
|
if (!std::isnan(gas_phase_ptr->Get_gas_comps()[j].Get_p_read()))
|
|
{
|
|
P += gas_phase_ptr->Get_gas_comps()[j].Get_p_read();
|
|
if (!PR)
|
|
{
|
|
double moles = gas_phase_ptr->Get_gas_comps()[j].Get_p_read() * gas_phase_ptr->Get_volume() /
|
|
R_LITER_ATM / gas_phase_ptr->Get_temperature();
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_moles(moles);
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_p(gas_phase_ptr->Get_gas_comps()[j].Get_p_read());
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_phi(1.0);
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_f(gas_phase_ptr->Get_gas_comps()[j].Get_p_read());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Gas phase %d: partial pressure of gas component %s not defined.",
|
|
gas_phase_ptr->Get_n_user(), gas_phase_ptr->Get_gas_comps()[j].Get_phase_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Fixed volume
|
|
*/
|
|
if (!gas_phase_ptr->Get_solution_equilibria())
|
|
{
|
|
if (!std::isnan(gas_phase_ptr->Get_gas_comps()[j].Get_p_read()))
|
|
{
|
|
P += gas_phase_ptr->Get_gas_comps()[j].Get_p_read();
|
|
if (!PR)
|
|
{
|
|
double moles = gas_phase_ptr->Get_gas_comps()[j].Get_p_read() *
|
|
gas_phase_ptr->Get_volume() / R_LITER_ATM /
|
|
gas_phase_ptr->Get_temperature();
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_moles(moles);
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_p(gas_phase_ptr->Get_gas_comps()[j].Get_p_read());
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_phi(1.0);
|
|
gas_phase_ptr->Get_gas_comps()[j].Set_f(gas_phase_ptr->Get_gas_comps()[j].Get_p_read());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Gas phase %d: moles of gas component %s not defined.",
|
|
gas_phase_ptr->Get_n_user(),
|
|
gas_phase_ptr->Get_gas_comps()[j].Get_phase_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PR && P > 0)
|
|
{
|
|
std::vector<class phase *> phase_ptrs;
|
|
size_t j_PR;
|
|
std::vector<cxxGasComp> &gc = gas_phase_ptr->Get_gas_comps();
|
|
for (j_PR = 0; j_PR < gas_phase_ptr->Get_gas_comps().size(); j_PR++)
|
|
{
|
|
int k;
|
|
class phase *phase_ptr = phase_bsearch(gas_phase_ptr->Get_gas_comps()[j_PR].Get_phase_name().c_str(), &k, FALSE);
|
|
if (gc[j_PR].Get_p_read() == 0)
|
|
{
|
|
gc[j_PR].Set_moles(0.0);
|
|
gc[j_PR].Set_p(0.0);
|
|
gc[j_PR].Set_phi(1.0);
|
|
gc[j_PR].Set_f(0.0);
|
|
continue;
|
|
}
|
|
if (phase_ptr)
|
|
{
|
|
phase_ptr->moles_x = gc[j_PR].Get_p_read() / P;
|
|
phase_ptrs.push_back(phase_ptr);
|
|
}
|
|
}
|
|
V_m = calc_PR(phase_ptrs, P, gas_phase_ptr->Get_temperature(), 0);
|
|
gas_phase_ptr->Set_v_m(V_m);
|
|
if (gas_phase_ptr->Get_type() == cxxGasPhase::GP_VOLUME)
|
|
{
|
|
gas_phase_ptr->Set_total_p(P);
|
|
}
|
|
for (j_PR = 0; j_PR < gas_phase_ptr->Get_gas_comps().size(); j_PR++)
|
|
{
|
|
int k;
|
|
class phase *phase_ptr = phase_bsearch(gc[j_PR].Get_phase_name().c_str(), &k, FALSE);
|
|
if (gc[j_PR].Get_p_read() == 0)
|
|
{
|
|
gc[j_PR].Set_moles(0.0);
|
|
gc[j_PR].Set_p(0.0);
|
|
gc[j_PR].Set_phi(1.0);
|
|
gc[j_PR].Set_f(0.0);
|
|
} else
|
|
{
|
|
if (phase_ptr)
|
|
{
|
|
gc[j_PR].Set_moles(phase_ptr->moles_x * gas_phase_ptr->Get_volume() / V_m);
|
|
gc[j_PR].Set_p(gc[j_PR].Get_p_read());
|
|
gc[j_PR].Set_phi(phase_ptr->pr_phi);
|
|
gc[j_PR].Set_f(gc[j_PR].Get_p_read()* phase_ptr->pr_phi);
|
|
gas_phase_ptr->Set_total_moles(gas_phase_ptr->Get_total_moles() + gc[j_PR].Get_moles());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Duplicate gas phase, only if not solution equilibria
|
|
*/
|
|
if (!gas_phase_ptr->Get_solution_equilibria())
|
|
{
|
|
gas_phase_ptr->Set_new_def(false);
|
|
n_user = gas_phase_ptr->Get_n_user();
|
|
last = gas_phase_ptr->Get_n_user_end();
|
|
gas_phase_ptr->Set_n_user_end(n_user);
|
|
for (int j1 = n_user + 1; j1 <= last; j1++)
|
|
{
|
|
Utilities::Rxn_copy(Rxn_gas_phase_map, n_user, j1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gas_phase_ptr->Set_new_def(true);
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_inverse(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* After all of data are read, fill in data for an inverse structure,
|
|
* including master species pointers, phase pointers, and uncertainties
|
|
* and a list of all elements from phases or -balance input.
|
|
*/
|
|
int i, j, k, l;
|
|
int count_in;
|
|
LDBLE value;
|
|
class master *master_ptr;
|
|
class master *master_alk_ptr;
|
|
const class elt_list *elt_list_ptr;
|
|
master_alk_ptr = master_bsearch("Alkalinity");
|
|
for (i = 0; i < count_inverse; i++)
|
|
{
|
|
if (inverse[i].new_def != TRUE)
|
|
continue;
|
|
/*
|
|
* Set default uncertainties for all solutions, if necessary
|
|
*/
|
|
if (inverse[i].uncertainties.size() < inverse[i].count_solns)
|
|
{
|
|
size_t count = inverse[i].uncertainties.size();
|
|
double value = (count > 0) ? inverse[i].uncertainties.back() : 0.05;
|
|
inverse[i].uncertainties.resize(inverse[i].count_solns);
|
|
for (size_t j = count; j < inverse[i].count_solns; j++)
|
|
{
|
|
inverse[i].uncertainties[j] = value;
|
|
}
|
|
}
|
|
/*
|
|
* Set default ph uncertainties for all solutions, if necessary
|
|
*/
|
|
if (inverse[i].ph_uncertainties.size() < inverse[i].count_solns)
|
|
{
|
|
size_t count = inverse[i].ph_uncertainties.size();
|
|
double value = (count > 0) ? inverse[i].ph_uncertainties.back() : 0.05;
|
|
inverse[i].ph_uncertainties.resize(inverse[i].count_solns);
|
|
for (size_t j = count; j < inverse[i].count_solns; j++)
|
|
{
|
|
inverse[i].ph_uncertainties[j] = value;
|
|
}
|
|
}
|
|
/*
|
|
* Set default force for all solutions
|
|
*/
|
|
if (inverse[i].force_solns.size() < inverse[i].count_solns)
|
|
{
|
|
size_t count = inverse[i].force_solns.size();
|
|
inverse[i].force_solns.resize(inverse[i].count_solns);
|
|
for (size_t j = count; j < inverse[i].count_solns; j++)
|
|
{
|
|
inverse[i].force_solns[j] = false;
|
|
}
|
|
}
|
|
/*
|
|
* Find master species for element, set uncertainties
|
|
*/
|
|
for (j = 0; j < inverse[i].elts.size(); j++)
|
|
{
|
|
inverse[i].elts[j].master =
|
|
master_bsearch_primary(inverse[i].elts[j].name);
|
|
if (inverse[i].elts[j].master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "No master species for element, %s.",
|
|
inverse[i].elts[j].name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
size_t count_uncertainties = inverse[i].elts[j].uncertainties.size();
|
|
inverse[i].elts[j].uncertainties.resize((size_t)inverse[i].count_solns);
|
|
if (count_uncertainties == 0)
|
|
{
|
|
/* use default uncertainties for element */
|
|
for (k = 0; k < inverse[i].count_solns; k++)
|
|
{
|
|
inverse[i].elts[j].uncertainties[k] =
|
|
inverse[i].uncertainties[k];
|
|
}
|
|
}
|
|
else if (count_uncertainties < inverse[i].count_solns)
|
|
{
|
|
/* use input uncertainties, fill in any missing at end */
|
|
value = inverse[i].elts[j].uncertainties[count_uncertainties - 1];
|
|
for (size_t k = count_uncertainties; k < inverse[i].count_solns; k++)
|
|
{
|
|
inverse[i].elts[j].uncertainties[k] = value;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Find phase
|
|
*/
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
for (j = 0; j < inverse[i].phases.size(); j++)
|
|
{
|
|
inverse[i].phases[j].phase =
|
|
phase_bsearch(inverse[i].phases[j].name, &k, FALSE);
|
|
if (inverse[i].phases[j].phase == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Could not find phase, %s.",
|
|
inverse[i].phases[j].name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
/*
|
|
* Find isotope elements
|
|
*/
|
|
if (inverse[i].phases[j].isotopes.size() > 0)
|
|
{
|
|
for (k = 0; k < inverse[i].phases[j].isotopes.size(); k++)
|
|
{
|
|
inverse[i].phases[j].isotopes[k].primary = NULL;
|
|
inverse[i].phases[j].isotopes[k].master = NULL;
|
|
master_ptr =
|
|
master_bsearch(inverse[i].phases[j].isotopes[k].
|
|
elt_name);
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Element not found for isotope calculation: %s.",
|
|
inverse[i].phases[j].isotopes[k].elt_name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->primary != TRUE)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Isotope ratio may only be used"
|
|
" for total element in phase.\n"
|
|
"Secondary species not allowed: %s.",
|
|
master_ptr->elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
inverse[i].phases[j].isotopes[k].primary = master_ptr;
|
|
inverse[i].phases[j].isotopes[k].master = master_ptr;
|
|
/* find coefficient for element */
|
|
for (elt_list_ptr = &inverse[i].phases[j].phase->next_elt[0];
|
|
elt_list_ptr->elt != NULL; elt_list_ptr++)
|
|
{
|
|
if (elt_list_ptr->elt == master_ptr->elt)
|
|
{
|
|
inverse[i].phases[j].isotopes[k].coef =
|
|
elt_list_ptr->coef;
|
|
break;
|
|
}
|
|
}
|
|
if (elt_list_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Element, %s,for which isotope ratio was defined is not found in phase, %s",
|
|
master_ptr->elt->name,
|
|
inverse[i].phases[j].phase->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
}
|
|
qsort(&inverse[i].phases[j].isotopes[0],
|
|
inverse[i].phases[j].isotopes.size(),
|
|
sizeof(class isotope), isotope_compare);
|
|
}
|
|
add_elt_list(inverse[i].phases[j].phase->next_elt, 1.0);
|
|
|
|
}
|
|
if (get_input_errors() > 0)
|
|
return (ERROR);
|
|
/*
|
|
* Sort elements in reaction and combine
|
|
*/
|
|
elt_list_combine();
|
|
/*
|
|
* Mark master species list
|
|
*/
|
|
for (j = 0; j < (int)master.size(); j++)
|
|
master[j]->in = FALSE;
|
|
for (j = 0; j < count_elts; j++)
|
|
{
|
|
elt_list[j].elt->master->in = TRUE;
|
|
}
|
|
/* Include all input elements */
|
|
for (j = 0; j < inverse[i].elts.size(); j++)
|
|
{
|
|
inverse[i].elts[j].master->in = TRUE;
|
|
}
|
|
s_eminus->primary->in = TRUE; /* Include electrons */
|
|
if (master_alk_ptr)
|
|
{
|
|
master_alk_ptr->in = TRUE; /* Include alkalinity */
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Alkalinity must be defined in SOLUTION_MASTER_SPECIES to be able to use INVERSE_MODELING.");
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
/*
|
|
* Unmark primary and mark secondary master species for redox elements
|
|
*/
|
|
count_in = 0;
|
|
inverse[i].count_redox_rxns = 0;
|
|
for (j = 0; j < (int)master.size(); j++)
|
|
{
|
|
/* skip all secondary master species in this loop */
|
|
if (master[j]->primary == FALSE || master[j]->in == FALSE)
|
|
continue;
|
|
count_in++;
|
|
if (j + 1 == (int)master.size())
|
|
continue;
|
|
/* if next master species is secondary, mark all
|
|
secondary master species until a primary is found */
|
|
if (master[(size_t)j + 1]->primary == FALSE)
|
|
{
|
|
master[j]->in = FALSE;
|
|
count_in--;
|
|
for (k = j + 1; k < (int)master.size(); k++)
|
|
{
|
|
if (master[k]->primary == FALSE)
|
|
{
|
|
count_in++;
|
|
master[k]->in = TRUE;
|
|
if (master[k]->s->primary == NULL)
|
|
{
|
|
inverse[i].count_redox_rxns++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Save list of master species in inv_elts structure
|
|
*/
|
|
std::vector<class inv_elts> inv_elts;
|
|
inv_elts.resize(count_in);
|
|
count_in = 0;
|
|
for (j = 0; j < (int)master.size(); j++)
|
|
{
|
|
/* skip H(1) and O(-2) */
|
|
if (master[j]->s == s_hplus || master[j]->s == s_h2o)
|
|
continue;
|
|
if (master[j]->in == TRUE)
|
|
{
|
|
/* set master */
|
|
inv_elts[count_in].master = master[j];
|
|
/* alloc uncertainties and set default */
|
|
inv_elts[count_in].uncertainties.resize((size_t)inverse[i].count_solns);
|
|
for (k = 0; k < inverse[i].count_solns; k++)
|
|
{
|
|
inv_elts[count_in].uncertainties[k] =
|
|
inverse[i].uncertainties[k];
|
|
}
|
|
count_in++;
|
|
}
|
|
}
|
|
if (s_co3->secondary->in == TRUE)
|
|
{
|
|
inverse[i].carbon = TRUE;
|
|
}
|
|
else
|
|
{
|
|
inverse[i].carbon = FALSE;
|
|
}
|
|
/*
|
|
* copy in input uncertainties
|
|
*/
|
|
/* copy primary redox to all secondary redox */
|
|
for (j = 0; j < inverse[i].elts.size(); j++)
|
|
{
|
|
master_ptr = master_bsearch(inverse[i].elts[j].name);
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Element not found, %s.",
|
|
inverse[i].elts[j].name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->primary == FALSE
|
|
|| master_ptr->s->secondary == NULL)
|
|
continue;
|
|
for (k = 0; k < count_in; k++)
|
|
{
|
|
if (master_ptr == inv_elts[k].master->elt->primary)
|
|
{
|
|
for (l = 0; l < inverse[i].count_solns; l++)
|
|
{
|
|
inv_elts[k].uncertainties[l] =
|
|
inverse[i].elts[j].uncertainties[l];
|
|
}
|
|
}
|
|
}
|
|
inverse[i].elts[j].uncertainties.clear();
|
|
}
|
|
/* copy masters that are not primary redox */
|
|
for (j = 0; j < inverse[i].elts.size(); j++)
|
|
{
|
|
master_ptr = master_bsearch(inverse[i].elts[j].name);
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Element not found, %s.",
|
|
inverse[i].elts[j].name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->primary == TRUE
|
|
&& master_ptr->s->secondary != NULL)
|
|
continue;
|
|
for (k = 0; k < count_in; k++)
|
|
{
|
|
if (master_ptr == inv_elts[k].master)
|
|
{
|
|
for (l = 0; l < inverse[i].count_solns; l++)
|
|
{
|
|
inv_elts[k].uncertainties[l] =
|
|
inverse[i].elts[j].uncertainties[l];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
inverse[i].elts[j].uncertainties.clear();
|
|
}
|
|
/*
|
|
* replace elts in inverse struct
|
|
*/
|
|
inverse[i].elts.clear();
|
|
inverse[i].elts = inv_elts;
|
|
inverse[i].elts.resize(count_in);
|
|
for (j = 0; j < inverse[i].elts.size(); j++)
|
|
{
|
|
/* debug
|
|
output_msg(sformatf( "\t%d\t%s", j, inverse[i].elts[j].master->elt->name));
|
|
for (k = 0; k < inverse[i].count_solns; k++) {
|
|
output_msg(sformatf( "\t%f", inverse[i].elts[j].uncertainties[k]));
|
|
}
|
|
output_msg(sformatf("\n"));
|
|
*/
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_phases(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
int replaced;
|
|
/*
|
|
* Fix log Ks first, so they can possibly be added to other phase equations
|
|
*/
|
|
for (i = 0; i < (int)phases.size(); i++)
|
|
{
|
|
select_log_k_expression(phases[i]->logk, phases[i]->rxn.logk);
|
|
add_other_logk(phases[i]->rxn.logk, phases[i]->add_logk);
|
|
phases[i]->rxn.token[0].name = phases[i]->name;
|
|
phases[i]->rxn.token[0].s = NULL;
|
|
}
|
|
/*
|
|
* Rewrite all phases to secondary species
|
|
*/
|
|
for (i = 0; i < (int)phases.size(); i++)
|
|
{
|
|
/*
|
|
* Rewrite equation
|
|
*/
|
|
count_trxn = 0;
|
|
trxn_add_phase(phases[i]->rxn, 1.0, false);
|
|
trxn.token[0].name = phases[i]->name;
|
|
/* debug
|
|
output_msg(sformatf( "%s PHASE.\n", phases[i]->name));
|
|
trxn_print();
|
|
*/
|
|
replaced = replace_solids_gases();
|
|
phases[i]->replaced = replaced;
|
|
/* save rxn_s */
|
|
trxn_reverse_k();
|
|
rewrite_eqn_to_secondary();
|
|
trxn_reverse_k();
|
|
trxn_copy(phases[i]->rxn_s);
|
|
/*
|
|
* Check equation
|
|
*/
|
|
if (phases[i]->check_equation == TRUE)
|
|
{
|
|
if (replaced == FALSE)
|
|
{
|
|
phase_rxn_to_trxn(phases[i], phases[i]->rxn);
|
|
}
|
|
else
|
|
{
|
|
phase_rxn_to_trxn(phases[i], phases[i]->rxn_s);
|
|
}
|
|
if (check_eqn(FALSE) == ERROR)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equation for phase %s does not balance.",
|
|
phases[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_pp_assemblage(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
LDBLE coef;
|
|
const char* cptr;
|
|
/*
|
|
* Find pointers for pure phases
|
|
*/
|
|
//std::map<int, cxxPPassemblage>::iterator it;
|
|
//it = Rxn_pp_assemblage_map.begin();
|
|
//for ( ; it != Rxn_pp_assemblage_map.end(); it++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_pp_assemblage.size(); nn++)
|
|
//{
|
|
//std::map<int, cxxPPassemblage>::iterator kit = Rxn_pp_assemblage_map.find(Rxn_new_pp_assemblage[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_pp_assemblage.begin(); nit != Rxn_new_pp_assemblage.end(); nit++)
|
|
{
|
|
std::map<int, cxxPPassemblage>::iterator kit = Rxn_pp_assemblage_map.find(*nit);
|
|
if (kit == Rxn_pp_assemblage_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
//if (!kit->second.Get_new_def()) continue;
|
|
cxxPPassemblage *pp_assemblage_ptr = &(kit->second);
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
coef = 1.0;
|
|
pp_assemblage_ptr->Set_new_def(false);
|
|
|
|
std::map<std::string, cxxPPassemblageComp>::iterator it;
|
|
it = pp_assemblage_ptr->Get_pp_assemblage_comps().begin();
|
|
for ( ; it != pp_assemblage_ptr->Get_pp_assemblage_comps().end(); it++)
|
|
{
|
|
int k;
|
|
class phase *phase_ptr = phase_bsearch(it->first.c_str(), &k, FALSE);
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Phase not found in database, %s.",
|
|
it->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
add_elt_list(phase_ptr->next_elt, coef);
|
|
}
|
|
if (it->second.Get_add_formula().size() > 0)
|
|
{
|
|
size_t first = count_elts;
|
|
phase_ptr = phase_bsearch(it->second.Get_add_formula().c_str(), &k, FALSE);
|
|
if (phase_ptr != NULL)
|
|
{
|
|
it->second.Set_add_formula(phase_ptr->formula);
|
|
}
|
|
{
|
|
cptr = it->second.Get_add_formula().c_str();
|
|
get_elts_in_species(&cptr, coef);
|
|
}
|
|
/* check that all elements are in the database */
|
|
for (size_t l = first; l < count_elts; l++)
|
|
{
|
|
if (elt_list[l].elt->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Element \"%s\" in alternative phase for \"%s\" in EQUILIBRIUM_PHASES not found in database.",
|
|
elt_list[l].elt->name,
|
|
it->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Store list with all elements in phases and add formulae
|
|
*/
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
pp_assemblage_ptr->Set_eltList(nd);
|
|
/*
|
|
* Duplicate pure phases if necessary
|
|
*/
|
|
|
|
int n_user = pp_assemblage_ptr->Get_n_user();
|
|
int n_user_end = pp_assemblage_ptr->Get_n_user_end();
|
|
pp_assemblage_ptr->Set_n_user_end(n_user);
|
|
Utilities::Rxn_copies(Rxn_pp_assemblage_map, n_user, n_user_end);
|
|
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_ss_assemblage(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
class phase *phase_ptr;
|
|
LDBLE nb, nc, n_tot, xb, xc, dnb, dnc, l_a0, l_a1;
|
|
LDBLE xb2, xb3, xb4, xc2, xc3;
|
|
LDBLE moles;
|
|
/*
|
|
* Find pointers for pure phases
|
|
*/
|
|
//std::map<int, cxxSSassemblage>::iterator it;
|
|
//for (it = Rxn_ss_assemblage_map.begin(); it != Rxn_ss_assemblage_map.end(); it++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_ss_assemblage.size(); nn++)
|
|
//{
|
|
//std::map<int, cxxSSassemblage>::iterator it = Rxn_ss_assemblage_map.find(Rxn_new_ss_assemblage[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_ss_assemblage.begin(); nit != Rxn_new_ss_assemblage.end(); nit++)
|
|
{
|
|
std::map<int, cxxSSassemblage>::iterator it = Rxn_ss_assemblage_map.find(*nit);
|
|
if (it == Rxn_ss_assemblage_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
//if (!it->second.Get_new_def()) continue;
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
cxxSSassemblage *ss_assemblage_ptr = &(it->second);
|
|
std::vector<cxxSS *> ss_ptrs = ss_assemblage_ptr->Vectorize();
|
|
for (size_t j = 0; j < ss_ptrs.size(); j++)
|
|
{
|
|
cxxSS *ss_ptr = ss_ptrs[j];
|
|
for (size_t k = 0; k < ss_ptr->Get_ss_comps().size(); k++)
|
|
{
|
|
cxxSScomp * comp_ptr = &(ss_ptr->Get_ss_comps()[k]);
|
|
int k1;
|
|
phase_ptr = phase_bsearch(comp_ptr->Get_name().c_str(), &k1, FALSE);
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Phase not found in database, %s, assemblage %d.",
|
|
comp_ptr->Get_name().c_str(),
|
|
ss_assemblage_ptr->Get_n_user());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
phase_ptr->moles_x = 0;
|
|
phase_ptr->fraction_x = 0;
|
|
}
|
|
if (std::isnan(comp_ptr->Get_moles()))
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Moles of solid solution component not defined, %s, assemblage %d.",
|
|
comp_ptr->Get_name().c_str(),
|
|
ss_assemblage_ptr->Get_n_user());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (ss_assemblage_ptr->Get_new_def())
|
|
{
|
|
/*
|
|
* Calculate a0 and a1 first
|
|
*/
|
|
ss_calc_a0_a1(ss_ptr);
|
|
|
|
n_tot = 0;
|
|
for (size_t k = 0; k < ss_ptr->Get_ss_comps().size(); k++)
|
|
{
|
|
cxxSScomp * comp_ptr = &(ss_ptr->Get_ss_comps()[k]);
|
|
moles = comp_ptr->Get_moles();
|
|
if (moles <= 0.0)
|
|
{
|
|
moles = MIN_TOTAL_SS;
|
|
comp_ptr->Set_initial_moles(moles);
|
|
}
|
|
n_tot += moles;
|
|
}
|
|
|
|
for (size_t k = 0; k < ss_ptr->Get_ss_comps().size(); k++)
|
|
{
|
|
cxxSScomp * comp_ptr = &(ss_ptr->Get_ss_comps()[k]);
|
|
moles = comp_ptr->Get_moles();
|
|
if (moles <= 0.0)
|
|
{
|
|
moles = MIN_TOTAL_SS;
|
|
}
|
|
comp_ptr->Set_fraction_x(moles / n_tot);
|
|
comp_ptr->Set_log10_fraction_x(log10(moles / n_tot));
|
|
}
|
|
l_a0 = ss_ptr->Get_a0();
|
|
l_a1 = ss_ptr->Get_a1();
|
|
|
|
/*
|
|
* Binary solid solution
|
|
*/
|
|
if (l_a0 != 0.0 || l_a1 != 0)
|
|
{
|
|
ss_ptr->Set_dn(1.0 / n_tot);
|
|
nc = ss_ptr->Get_ss_comps()[0].Get_moles();
|
|
if (nc == 0)
|
|
nc = MIN_TOTAL_SS;
|
|
nb = ss_ptr->Get_ss_comps()[1].Get_moles();
|
|
if (nb == 0)
|
|
nb = MIN_TOTAL_SS;
|
|
xc = nc / n_tot;
|
|
xb = nb / n_tot;
|
|
|
|
/* lambdas */
|
|
ss_ptr->Get_ss_comps()[0].Set_log10_lambda(xb * xb * (l_a0 - l_a1 * (3 - 4 * xb)) / LOG_10);
|
|
ss_ptr->Get_ss_comps()[1].Set_log10_lambda(xc * xc * (l_a0 + l_a1 * (4 * xb - 1)) / LOG_10);
|
|
|
|
/* derivatives wrt nc and nb */
|
|
xc2 = xc * xc;
|
|
xc3 = xc2 * xc;
|
|
xb2 = xb * xb;
|
|
xb3 = xb2 * xb;
|
|
xb4 = xb3 * xb;
|
|
|
|
/* component 1 */
|
|
dnb =
|
|
-2 * l_a0 * xb * xc2 - 8 * l_a1 * xb2 * xc2 +
|
|
6 * l_a1 * xb * xc2 - 4 * l_a1 * xc * xb4 -
|
|
8 * l_a1 * xb3 * xc2 - 4 * l_a1 * xb2 * xc3 -
|
|
2 * l_a0 * xc * xb2 - 8 * l_a1 * xc * xb3 +
|
|
6 * l_a1 * xc * xb2 + 1;
|
|
ss_ptr->Get_ss_comps()[0].Set_dnb(dnb / n_tot);
|
|
dnc =
|
|
2 * l_a0 * xb3 + 2 * l_a0 * xc * xb2 + 8 * l_a1 * xb4 +
|
|
8 * l_a1 * xc * xb3 - 2 * l_a1 * xb3 - 6 * l_a1 * xc * xb2;
|
|
ss_ptr->Get_ss_comps()[0].Set_dnc(-xb / nc + dnc / n_tot);
|
|
ss_ptr->Get_ss_comps()[0].Set_dn(1.0 / n_tot);
|
|
|
|
/* component 2 */
|
|
dnb =
|
|
2 * l_a0 * xb * xc2 + 2 * l_a0 * xc3 +
|
|
8 * l_a1 * xb2 * xc2 + 8 * l_a1 * xb * xc3 -
|
|
2 * l_a1 * xb * xc2 - 6 * l_a1 * xc3;
|
|
ss_ptr->Get_ss_comps()[1].Set_dnb(-xc / nb + dnb / n_tot);
|
|
dnc =
|
|
-2 * l_a0 * xc * xb2 - 8 * l_a1 * xc * xb3 +
|
|
2 * l_a1 * xc * xb2 - 2 * l_a0 * xb * xc2 -
|
|
8 * l_a1 * xb2 * xc2 + 6 * l_a1 * xb * xc2 + 1;
|
|
ss_ptr->Get_ss_comps()[1].Set_dnc(dnc / n_tot);
|
|
ss_prep(ss_ptr->Get_tk(), ss_ptr, TRUE);
|
|
ss_ptr->Get_ss_comps()[1].Set_dn(1.0 / n_tot);
|
|
/*
|
|
* Ideal solid solution
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
ss_ptr->Set_dn(1.0 / n_tot);
|
|
for (size_t k = 0; k < ss_ptr->Get_ss_comps().size(); k++)
|
|
{
|
|
cxxSScomp * comp_ptr = &(ss_ptr->Get_ss_comps()[k]);
|
|
comp_ptr->Set_log10_lambda(0);
|
|
moles = comp_ptr->Get_moles();
|
|
if (moles <= 0.0)
|
|
moles = MIN_TOTAL_SS;
|
|
comp_ptr->Set_dnb((n_tot - moles) / (moles * n_tot));
|
|
comp_ptr->Set_dn(1.0 / n_tot);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ss_assemblage_ptr->Set_new_def(false);
|
|
/*
|
|
* Duplicate ss_assemblage if necessary
|
|
*/
|
|
int n_user = ss_assemblage_ptr->Get_n_user();
|
|
int n_user_end = ss_assemblage_ptr->Get_n_user_end();
|
|
Utilities::Rxn_copies(Rxn_ss_assemblage_map, n_user, n_user_end);
|
|
ss_assemblage_ptr->Set_n_user_end(n_user);
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_punch(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
//int i, j, l;
|
|
int punch_save;
|
|
//char token[MAX_LENGTH];
|
|
/*
|
|
* tidy punch information
|
|
*/
|
|
std::map < int, SelectedOutput >::iterator so_it = SelectedOutput_map.begin();
|
|
for ( ; so_it != SelectedOutput_map.end(); so_it++)
|
|
{
|
|
current_selected_output = &(so_it->second);
|
|
if (current_selected_output == NULL)
|
|
continue;
|
|
|
|
|
|
/* totals */
|
|
|
|
for (size_t i = 0; i < current_selected_output->Get_totals().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_totals()[i];
|
|
std::string noplus = pair_ptr.first;
|
|
replace(noplus, "(+", "(");
|
|
pair_ptr.second = master_bsearch(noplus.c_str());
|
|
}
|
|
|
|
/* molalities */
|
|
for (size_t i = 0; i < current_selected_output->Get_molalities().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_molalities()[i];
|
|
pair_ptr.second = s_search(pair_ptr.first.c_str());
|
|
}
|
|
|
|
/* log activities */
|
|
|
|
//for (i = 0; i < punch.count_activities; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_activities().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_activities()[i];
|
|
pair_ptr.second = s_search(pair_ptr.first.c_str());
|
|
}
|
|
|
|
/* equilibrium phases */
|
|
|
|
//for (i = 0; i < punch.count_pure_phases; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_pure_phases().size(); i++)
|
|
{
|
|
int j;
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_pure_phases()[i];
|
|
pair_ptr.second = phase_bsearch(pair_ptr.first.c_str(), &j, FALSE);
|
|
}
|
|
|
|
/* saturation indices */
|
|
|
|
//for (i = 0; i < punch.count_si; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_si().size(); i++)
|
|
{
|
|
int j;
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_si()[i];
|
|
pair_ptr.second = phase_bsearch(pair_ptr.first.c_str(), &j, FALSE);
|
|
}
|
|
|
|
/* gases */
|
|
|
|
//for (i = 0; i < punch.count_gases; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_gases().size(); i++)
|
|
{
|
|
int j;
|
|
std::pair< std::string, void *> &pair_ptr = current_selected_output->Get_gases()[i];
|
|
pair_ptr.second = phase_bsearch(pair_ptr.first.c_str(), &j, FALSE);
|
|
}
|
|
}
|
|
/*
|
|
* Always write new headings when SELECTED_OUTPUT is read
|
|
*/
|
|
so_it = SelectedOutput_map.begin();
|
|
for ( ; so_it != SelectedOutput_map.end(); so_it++)
|
|
{
|
|
current_selected_output = &(so_it->second);
|
|
if (current_selected_output == NULL ||
|
|
!current_selected_output->Get_new_def())
|
|
continue;
|
|
phrq_io->Set_punch_ostream(current_selected_output->Get_punch_ostream());
|
|
|
|
|
|
int l;
|
|
if (current_selected_output->Get_high_precision() == false)
|
|
{
|
|
l = 12;
|
|
}
|
|
else
|
|
{
|
|
l = 20;
|
|
}
|
|
// UserPunch
|
|
std::map < int, UserPunch >::iterator up_it = UserPunch_map.find(current_selected_output->Get_n_user());
|
|
current_user_punch = up_it == UserPunch_map.end() ? NULL : &(up_it->second);
|
|
|
|
punch_save = pr.punch;
|
|
pr.punch = TRUE;
|
|
phrq_io->Set_punch_on(true);
|
|
|
|
/* constant stuff, sim, pH, etc. */
|
|
|
|
if (current_selected_output->Get_sim() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "sim"));
|
|
}
|
|
if (current_selected_output->Get_state() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "state"));
|
|
}
|
|
if (current_selected_output->Get_soln() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "soln"));
|
|
}
|
|
if (current_selected_output->Get_dist() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "dist_x"));
|
|
}
|
|
if (current_selected_output->Get_time() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "time"));
|
|
}
|
|
if (current_selected_output->Get_step() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "step"));
|
|
}
|
|
if (current_selected_output->Get_ph() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "pH"));
|
|
}
|
|
if (current_selected_output->Get_pe() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "pe"));
|
|
}
|
|
if (current_selected_output->Get_rxn() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "reaction"));
|
|
}
|
|
if (current_selected_output->Get_temp() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "temp"));
|
|
}
|
|
if (current_selected_output->Get_alk() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "Alk"));
|
|
}
|
|
if (current_selected_output->Get_mu() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "mu"));
|
|
}
|
|
if (current_selected_output->Get_water() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "mass_H2O"));
|
|
}
|
|
if (current_selected_output->Get_charge_balance() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "charge"));
|
|
}
|
|
if (current_selected_output->Get_percent_error() == TRUE)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "pct_err"));
|
|
}
|
|
/* totals */
|
|
|
|
//for (i = 0; i < punch.count_totals; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_totals().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_totals()[i];
|
|
fpunchf_heading(sformatf("%*s\t", l, pair_ref.first.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find master species,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
//fpunchf_heading(sformatf("%*s\t", l, punch.totals[i].name));
|
|
//if (punch.totals[i].master == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find master species,"
|
|
// " %s.", punch.totals[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* molalities */
|
|
|
|
//for (i = 0; i < punch.count_molalities; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_molalities().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_molalities()[i];
|
|
std::string name = "m_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find species,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "m_");
|
|
//Utilities::strcat_safe(token, punch.molalities[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//if (punch.molalities[i].s == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find species,"
|
|
// " %s.", punch.molalities[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* log activities */
|
|
|
|
//for (i = 0; i < punch.count_activities; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_activities().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_activities()[i];
|
|
std::string name = "la_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find species,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "la_");
|
|
//Utilities::strcat_safe(token, punch.activities[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//if (punch.activities[i].s == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find species, "
|
|
// "%s.", punch.activities[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* equilibrium phases */
|
|
|
|
//for (i = 0; i < punch.count_pure_phases; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_pure_phases().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_pure_phases()[i];
|
|
fpunchf_heading(sformatf("%*s\t", l, pair_ref.first.c_str()));
|
|
std::string name = "d_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find phase,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "d_");
|
|
//Utilities::strcat_safe(token, punch.pure_phases[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, punch.pure_phases[i].name));
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//if (punch.pure_phases[i].phase == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find phase, "
|
|
// "%s.", punch.pure_phases[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* saturation indices */
|
|
|
|
//for (i = 0; i < punch.count_si; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_si().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_si()[i];
|
|
std::string name = "si_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find phase,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "si_");
|
|
//Utilities::strcat_safe(token, punch.si[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//if (punch.si[i].phase == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find phase, "
|
|
// "%s.", punch.si[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* gases */
|
|
|
|
//if (punch.count_gases > 0)
|
|
if (current_selected_output->Get_gases().size() > 0)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, "pressure"));
|
|
fpunchf_heading(sformatf("%*s\t", l, "total mol"));
|
|
fpunchf_heading(sformatf("%*s\t", l, "volume"));
|
|
}
|
|
//for (i = 0; i < punch.count_gases; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_gases().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_gases()[i];
|
|
std::string name = "g_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
if (pair_ref.second == NULL)
|
|
{
|
|
error_string = sformatf( "Did not find phase,"
|
|
" %s.", pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "g_");
|
|
//Utilities::strcat_safe(token, punch.gases[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//if (punch.gases[i].phase == NULL)
|
|
//{
|
|
// error_string = sformatf( "Did not find phase, "
|
|
// "%s.", punch.gases[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
}
|
|
|
|
/* kinetics */
|
|
|
|
//for (i = 0; i < punch.count_kinetics; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_kinetics().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_kinetics()[i];
|
|
std::string name = "k_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
name = "dk_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "k_");
|
|
//Utilities::strcat_safe(token, punch.kinetics[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "dk_");
|
|
//Utilities::strcat_safe(token, punch.kinetics[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
}
|
|
|
|
/* solid solutions */
|
|
|
|
//for (i = 0; i < punch.count_s_s; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_s_s().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_s_s()[i];
|
|
std::string name = "s_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "s_");
|
|
//Utilities::strcat_safe(token, punch.s_s[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
}
|
|
|
|
/* isotopes */
|
|
|
|
//for (i = 0; i < punch.count_isotopes; i++)
|
|
for (size_t i = 0; i < current_selected_output->Get_isotopes().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_isotopes()[i];
|
|
if (isotope_ratio_search(pair_ref.first.c_str()) == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"Did not find isotope_ratio definition for "
|
|
"%s in -isotopes of SELECTED_OUTPUT.\n%s must be defined in ISOTOPE_RATIO data block.",
|
|
pair_ref.first.c_str(), pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
std::string name = "I_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
//if (isotope_ratio_search(punch.isotopes[i].name) == NULL)
|
|
//{
|
|
// error_string = sformatf(
|
|
// "Did not find isotope_ratio definition for "
|
|
// "%s in -isotopes of SELECTED_OUTPUT.\n%s must be defined in ISOTOPE_RATIO data block.",
|
|
// punch.isotopes[i].name, punch.isotopes[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "I_");
|
|
//Utilities::strcat_safe(token, punch.isotopes[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
}
|
|
|
|
/* calculate_values */
|
|
|
|
for (size_t i = 0; i < current_selected_output->Get_calculate_values().size(); i++)
|
|
{
|
|
std::pair< std::string, void *> &pair_ref = current_selected_output->Get_calculate_values()[i];
|
|
if (calculate_value_search(pair_ref.first.c_str()) == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"Did not find calculate_values definition for "
|
|
"%s in -calculate_values of SELECTED_OUTPUT.\n%s must be defined in CALCULATE_VALUES data block.",
|
|
pair_ref.first.c_str(),
|
|
pair_ref.first.c_str());
|
|
warning_msg(error_string);
|
|
}
|
|
std::string name = "V_";
|
|
name.append(pair_ref.first);
|
|
fpunchf_heading(sformatf("%*s\t", l, name.c_str()));
|
|
//if (calculate_value_search(punch.calculate_values[i].name) == NULL)
|
|
//{
|
|
// error_string = sformatf(
|
|
// "Did not find calculate_values definition for "
|
|
// "%s in -calculate_values of SELECTED_OUTPUT.\n%s must be defined in CALCULATE_VALUES data block.",
|
|
// punch.calculate_values[i].name,
|
|
// punch.calculate_values[i].name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
// Utilities::strcpy_safe(token, MAX_LENGTH, "V_");
|
|
//Utilities::strcat_safe(token, punch.calculate_values[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
}
|
|
|
|
/* user_punch */
|
|
if (current_user_punch != NULL && current_selected_output->Get_user_punch())
|
|
{
|
|
for (size_t i = 0; i < current_user_punch->Get_headings().size(); i++)
|
|
{
|
|
fpunchf_heading(sformatf("%*s\t", l, current_user_punch->Get_headings()[i].c_str()));
|
|
}
|
|
}
|
|
fpunchf_heading("\n");
|
|
|
|
current_selected_output->Set_new_def(false);
|
|
pr.punch = punch_save;
|
|
phrq_io->Set_punch_on(pr.punch == TRUE);
|
|
|
|
punch_flush();
|
|
}
|
|
|
|
current_selected_output = NULL;
|
|
current_user_punch = NULL;
|
|
phrq_io->Set_punch_ostream(NULL);
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_species(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j;
|
|
class master *master_ptr;
|
|
char c;
|
|
const char* cptr;
|
|
/*
|
|
* Make sure species pointers are ok
|
|
*/
|
|
if (check_species_input() == ERROR)
|
|
{
|
|
error_msg("Calculations terminating due to input errors.", STOP);
|
|
}
|
|
/*
|
|
* Set secondary and primary pointers in species structures
|
|
*/
|
|
for (i = 0; i < (int)s.size(); i++)
|
|
{
|
|
s[i]->number = i;
|
|
s[i]->primary = NULL;
|
|
s[i]->secondary = NULL;
|
|
if (s[i]->check_equation == TRUE)
|
|
{
|
|
species_rxn_to_trxn(s[i]);
|
|
if (check_eqn(TRUE) == ERROR)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equation for species %s does not balance.",
|
|
s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < (int)master.size(); i++)
|
|
{
|
|
cptr = master[i]->elt->name;
|
|
if (cptr[0] != '[')
|
|
{
|
|
while ((c = (int) *(++cptr)) != '\0')
|
|
{
|
|
if (isupper((int) c))
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Element or valence name in SOLUTION_MASTER_SPECIES should include only one element, %s.",
|
|
master[i]->elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* store sequence number in master structure */
|
|
master[i]->number = i;
|
|
if (master[i]->s == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Species pointer is null for, %s. Check your _MASTER_ and _SPECIES definitions.",
|
|
master[i]->elt->name);
|
|
error_msg(error_string, STOP);
|
|
}
|
|
|
|
if (strcmp(master[i]->elt->name, "Alkalinity") != 0)
|
|
{
|
|
if (master[i]->primary == TRUE)
|
|
{
|
|
master[i]->s->primary = master[i];
|
|
}
|
|
else
|
|
{
|
|
master[i]->s->secondary = master[i];
|
|
}
|
|
}
|
|
if (strcmp(master[i]->elt->name, "C") == 0)
|
|
{
|
|
s_co3 = master[i]->s;
|
|
}
|
|
if (master[i]->gfw_formula != NULL)
|
|
{
|
|
if (compute_gfw(master[i]->gfw_formula, &master[i]->gfw) == ERROR)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Calculating gfw for master species, %s, formula %s.",
|
|
master[i]->elt->name, master[i]->gfw_formula);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Write equations for all master species in terms of primary
|
|
* master species, set coefficient of element in master species
|
|
*/
|
|
for (i = 0; i < (int)master.size(); i++)
|
|
{
|
|
count_trxn = 0;
|
|
if (master[i]->s->primary != NULL)
|
|
{
|
|
trxn_add(master[i]->s->rxn, 1.0, false);
|
|
trxn_add(master[i]->s->rxn, -1.0, true);
|
|
}
|
|
else
|
|
{
|
|
trxn_add(master[i]->s->rxn, 1.0, false);
|
|
rewrite_eqn_to_primary();
|
|
}
|
|
trxn_copy(master[i]->rxn_primary);
|
|
master[i]->coef = coef_in_master(master[i]);
|
|
}
|
|
/*
|
|
* Rewrite all species to secondary species
|
|
*/
|
|
for (i = 0; i < (int)s.size(); i++)
|
|
{
|
|
count_trxn = 0;
|
|
if (s[i]->primary != NULL || s[i]->secondary != NULL)
|
|
{
|
|
trxn_add(s[i]->rxn, 1.0, false);
|
|
trxn_add(s[i]->rxn, -1.0, true);
|
|
}
|
|
else
|
|
{
|
|
trxn_add(s[i]->rxn, 1.0, false);
|
|
rewrite_eqn_to_secondary();
|
|
}
|
|
//rxn_free(s[i].rxn_s);
|
|
//s[i].rxn_s = rxn_alloc(count_trxn + 1);
|
|
trxn_copy(s[i]->rxn_s);
|
|
/* calculate alkalinity */
|
|
s[i]->alk = calc_alk(s[i]->rxn_s);
|
|
/* set co2 coefficient */
|
|
s[i]->co2 = 0.0;
|
|
for (j = 1; j < count_trxn; j++)
|
|
{
|
|
if (trxn.token[j].s == s_co3)
|
|
{
|
|
s[i]->co2 = trxn.token[j].coef;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Set pointer in element to master species
|
|
*/
|
|
for (i = 0; i < (int)elements.size(); i++)
|
|
{
|
|
elements[i]->master = master_bsearch(elements[i]->name);
|
|
if (elements[i]->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "No master species for element %s.",
|
|
elements[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
elements[i]->primary = master_bsearch_primary(elements[i]->name);
|
|
if (elements[i]->primary == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "No master species for element %s.",
|
|
elements[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
/*
|
|
* Make sure all primary master species for redox elements
|
|
* are also secondary master species
|
|
*/
|
|
for (i = 0; i < (int)master.size(); i++)
|
|
{
|
|
if (master[i]->primary == FALSE)
|
|
{
|
|
master_ptr = master[i]->s->secondary->elt->primary;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Every primary master species for a redox element\n"
|
|
"\tmust also be a secondary master species.\n"
|
|
"\tError in definitions related to %s .\n",
|
|
master[i]->s->name);
|
|
error_msg(error_string, CONTINUE);
|
|
|
|
}
|
|
else if (master_ptr->s->secondary == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Every primary master species for a redox element\n"
|
|
"\tmust also be a secondary master species.\n"
|
|
"\t%s is the primary master species for element %s.\n"
|
|
"\tAnother entry in SOLUTION_MASTER_SPECIES is needed.\n"
|
|
"\tDefine species %s as a secondary master species for a valence state.\n"
|
|
"\tFor example: \n" "\t%s(0)\t%s alk gfw",
|
|
master_ptr->s->name, master_ptr->elt->name,
|
|
master_ptr->s->name, master_ptr->elt->name,
|
|
master_ptr->s->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Calculate H and O if alternate mass balance is given
|
|
*/
|
|
for (i = 0; i < (int)s.size(); i++)
|
|
{
|
|
if (s[i]->next_secondary.size() != 0)
|
|
{
|
|
s[i]->h = 0.0;
|
|
s[i]->o = 0.0;
|
|
for (j = 0; s[i]->next_secondary[j].elt != NULL; j++)
|
|
{
|
|
if (s[i]->next_secondary[j].elt->primary == NULL)
|
|
continue;
|
|
if (s[i]->next_secondary[j].elt->primary->s == s_hplus || s[i]->next_secondary[j].elt->primary->s == s_h3oplus)
|
|
{
|
|
s[i]->h += s[i]->next_secondary[j].coef;
|
|
}
|
|
else if (s[i]->next_secondary[j].elt->primary->s == s_h2o)
|
|
{
|
|
s[i]->o += s[i]->next_secondary[j].coef;
|
|
}
|
|
else if (s[i]->mole_balance != NULL)
|
|
{
|
|
master_ptr = s[i]->next_secondary[j].elt->master;
|
|
if (master_ptr != NULL)
|
|
{
|
|
if (master_ptr->primary == TRUE)
|
|
{
|
|
if (master_ptr->s->secondary != NULL)
|
|
{
|
|
master_ptr = master_ptr->s->secondary;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Element in -mole_balance %s not defined for species %s.\n", s[i]->mole_balance, s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->coef != 1)
|
|
{
|
|
s[i]->next_secondary[j].coef /= master_ptr->coef;
|
|
}
|
|
}
|
|
}
|
|
if (s[i]->type == EX)
|
|
{
|
|
for (j = 0; s[i]->next_secondary[j].elt != NULL; j++)
|
|
{
|
|
if (s[i]->next_secondary[j].elt->primary->s->type == EX)
|
|
{
|
|
s[i]->equiv = s[i]->next_secondary[j].coef;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (s[i]->type == EX)
|
|
{
|
|
/*
|
|
* Find valence of cation from coefficients of reaction components
|
|
* Changed to be coefficient of exchanger
|
|
*/
|
|
LDBLE exchange_coef = 0.0;
|
|
for (j = 1; s[i]->rxn_s.token[j].s != NULL; j++)
|
|
{
|
|
if (s[i]->rxn_s.token[j].s->type == EX)
|
|
{
|
|
exchange_coef = s[i]->rxn_s.token[j].coef;
|
|
break;
|
|
}
|
|
}
|
|
if (exchange_coef == 0.0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No exchange species found in equation for %s.\n", s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
s[i]->equiv = exchange_coef;
|
|
}
|
|
if (s[i]->type == SURF)
|
|
{
|
|
LDBLE surface_coef = 0.0;
|
|
/*
|
|
* Find coefficient of surface in rxn, store in equiv
|
|
*/
|
|
for (j = 1; s[i]->rxn_s.token[j].s != NULL; j++)
|
|
{
|
|
if (s[i]->rxn_s.token[j].s->type == SURF)
|
|
{
|
|
surface_coef = s[i]->rxn_s.token[j].coef;
|
|
break;
|
|
}
|
|
}
|
|
if (surface_coef == 0.0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No surface species found in equation for %s.\n", s[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
s[i]->equiv = surface_coef;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < (int)master.size(); i++)
|
|
{
|
|
if (master[i]->gfw <= 0.0)
|
|
{
|
|
if (master[i]->type >= EMINUS) continue;
|
|
if ((strcmp(master[i]->elt->name, "E") != 0) &&
|
|
(strcmp(master[i]->elt->name, "e") != 0) &&
|
|
(strcmp(master[i]->elt->name, "H(1)") != 0) &&
|
|
(strcmp(master[i]->elt->name, "O(-2)") != 0)
|
|
)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Gram formula wt in SOLUTION_MASTER_SPECIES should not be <= 0.0, %s.\n", master[i]->elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_surface(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* After all of data are read, fill in master species for surface comps
|
|
* Sort surface
|
|
*/
|
|
const char* cptr1;
|
|
cxxSurface *surface_ptr;
|
|
//std::map<int, cxxSurface>::iterator kit;
|
|
//for (kit = Rxn_surface_map.begin(); kit != Rxn_surface_map.end(); kit++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_surface.size(); nn++)
|
|
//{
|
|
//std::map<int, cxxSurface>::iterator kit = Rxn_surface_map.find(Rxn_new_surface[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_surface.begin(); nit != Rxn_new_surface.end(); nit++)
|
|
{
|
|
std::map<int, cxxSurface>::iterator kit = Rxn_surface_map.find(*nit);
|
|
if (kit == Rxn_surface_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
//if (!kit->second.Get_new_def()) continue;
|
|
surface_ptr = &(kit->second);
|
|
if (surface_ptr->Get_tidied()) continue;
|
|
surface_ptr->Set_tidied(true);
|
|
// ccm incompatible with Donnan or diffuse_layer
|
|
if (surface_ptr->Get_type() == cxxSurface::CCM)
|
|
{
|
|
if (surface_ptr->Get_dl_type() == cxxSurface::BORKOVEK_DL || surface_ptr->Get_dl_type() == cxxSurface::DONNAN_DL)
|
|
{
|
|
input_error++;
|
|
error_string = "Cannot use -diffuse_layer or -donnan calculation with Constant Capacity Model.";
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
}
|
|
for (size_t i = 0; i < surface_ptr->Get_surface_comps().size(); i++)
|
|
{
|
|
cxxSurfaceComp *comp_ptr = &(surface_ptr->Get_surface_comps()[i]);
|
|
/*
|
|
* Find master species for each surface
|
|
*/
|
|
cxxNameDouble::iterator jit = comp_ptr->Get_totals().begin();
|
|
for ( ; jit != comp_ptr->Get_totals().end(); jit++ )
|
|
{
|
|
class element *elt_ptr = element_store(jit->first.c_str());
|
|
class master *master_ptr = elt_ptr->master;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Master species not in database for %s, "
|
|
"skipping element.",
|
|
elt_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->type != SURF)
|
|
continue;
|
|
comp_ptr->Set_master_element(elt_ptr->name);
|
|
/*
|
|
* Set flags
|
|
*/
|
|
cxxSurfaceCharge *charge_ptr = surface_ptr->Find_charge(comp_ptr->Get_charge_name());
|
|
/*
|
|
* Calculate moles of sites
|
|
*/
|
|
if (surface_ptr->Get_new_def()
|
|
&& surface_ptr->Get_sites_units() == cxxSurface::SITES_DENSITY
|
|
&& comp_ptr->Get_phase_name().size() == 0)
|
|
{
|
|
if (charge_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Surface type is incompatible with site units for %s.",
|
|
comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
comp_ptr->Set_moles(
|
|
comp_ptr->Get_moles() * 1.0e18 *
|
|
charge_ptr->Get_specific_area() *
|
|
charge_ptr->Get_grams() / AVOGADRO);
|
|
/*
|
|
* Calculate totals
|
|
*/
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr1 = comp_ptr->Get_formula().c_str();
|
|
get_elts_in_species(&cptr1, comp_ptr->Get_moles());
|
|
}
|
|
{
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
comp_ptr->Set_totals(nd);
|
|
}
|
|
}
|
|
if (surface_ptr->Get_type() == cxxSurface::CD_MUSIC)
|
|
{
|
|
charge_ptr->Set_charge_balance(charge_ptr->Get_charge_balance() +
|
|
comp_ptr->Get_moles() *
|
|
comp_ptr->Get_formula_z());
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Check that all surface comps have a corresponding master
|
|
*/
|
|
for (size_t i = 0; i < surface_ptr->Get_surface_comps().size(); i++)
|
|
{
|
|
if (surface_ptr->Get_surface_comps()[i].Get_master_element().size() == 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No surface master species for surface component %s, ",
|
|
surface_ptr->Get_surface_comps()[i].Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
/*
|
|
* Sort components
|
|
*/
|
|
std::map<std::string, cxxSurfaceComp> comp_map;
|
|
for (size_t i = 0; i < surface_ptr->Get_surface_comps().size(); i++)
|
|
{
|
|
cxxSurfaceComp *comp_ptr = &(surface_ptr->Get_surface_comps()[i]);
|
|
comp_map[comp_ptr->Get_formula()] = *comp_ptr;
|
|
}
|
|
std::map<std::string, cxxSurfaceComp>::iterator it = comp_map.begin();
|
|
surface_ptr->Get_surface_comps().clear();
|
|
for ( ; it != comp_map.end(); it++)
|
|
{
|
|
surface_ptr->Get_surface_comps().push_back(it->second);
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_solutions(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Define n_user for any solutions read by solution_spread that
|
|
* don`t have n_user defined
|
|
*/
|
|
class master *master_ptr;
|
|
|
|
/*
|
|
* Calculate solution numbers
|
|
*/
|
|
if (unnumbered_solutions.size() > 0)
|
|
{
|
|
int last = 0;
|
|
std::map<int, cxxSolution>::iterator jit;
|
|
for (jit = Rxn_solution_map.begin(); jit != Rxn_solution_map.end(); jit++)
|
|
{
|
|
if (jit->second.Get_n_user() > last)
|
|
last = jit->second.Get_n_user();
|
|
if (jit->second.Get_n_user_end() > last)
|
|
last = jit->second.Get_n_user_end();
|
|
}
|
|
if (save.solution == TRUE)
|
|
{
|
|
if (save.n_solution_user > last)
|
|
last = save.n_solution_user;
|
|
if (save.n_solution_user_end > last)
|
|
last = save.n_solution_user_end;
|
|
}
|
|
// put unnumbered solutions in map
|
|
for (size_t i = 0; i < unnumbered_solutions.size(); i++)
|
|
{
|
|
if (use.Get_n_solution_user() < 0)
|
|
{
|
|
use.Set_n_solution_user(last + 1);
|
|
}
|
|
unnumbered_solutions[i].Set_n_user_both(++last);
|
|
Rxn_solution_map[last] = unnumbered_solutions[i];
|
|
Rxn_new_solution.insert(last);
|
|
}
|
|
unnumbered_solutions.clear();
|
|
}
|
|
/*
|
|
* Check that elements are in database
|
|
*/
|
|
//std::map<int, cxxSolution>::iterator it;
|
|
//for (it = Rxn_solution_map.begin(); it != Rxn_solution_map.end(); it++)
|
|
//for(size_t n = 0; n < Rxn_new_solution.size(); n++)
|
|
//{
|
|
//std::map<int, cxxSolution>::iterator it = Rxn_solution_map.find(Rxn_new_solution[n]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_solution.begin(); nit != Rxn_new_solution.end(); nit++)
|
|
{
|
|
std::map<int, cxxSolution>::iterator it = Rxn_solution_map.find(*nit);
|
|
if (it == Rxn_solution_map.end())
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
cxxSolution &solution_ref = it->second;
|
|
//if (solution_ref.Get_new_def())
|
|
{
|
|
cxxISolution *initial_data_ptr = solution_ref.Get_initial_data();
|
|
if (initial_data_ptr != NULL)
|
|
{
|
|
std::map<std::string, cxxISolutionComp>::iterator iit = initial_data_ptr->Get_comps().begin();
|
|
for ( ; iit != initial_data_ptr->Get_comps().end(); iit++)
|
|
{
|
|
cxxISolutionComp &comp_ref = iit->second;
|
|
if (strcmp(comp_ref.Get_description().c_str(), "H(1)") == 0 ||
|
|
strcmp(comp_ref.Get_description().c_str(), "E") == 0)
|
|
{
|
|
comp_ref.Set_moles(0.0);
|
|
continue;
|
|
}
|
|
std::string token;
|
|
std::string description = comp_ref.Get_description();
|
|
std::string::iterator b = description.begin();
|
|
std::string::iterator e = description.end();
|
|
CParser::copy_token(token, b, e);
|
|
|
|
master_ptr = master_bsearch(token.c_str());
|
|
if (master_ptr == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"Could not find element in database, %s.\n\tConcentration is set to zero.",
|
|
comp_ref.Get_description().c_str());
|
|
warning_msg(error_string);
|
|
comp_ref.Set_input_conc(0.0);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
species_rxn_to_trxn(class species *s_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Copy reaction from reaction structure to
|
|
* temp reaction structure.
|
|
*/
|
|
if (trxn.token.size() <= s_ptr->rxn.token.size())
|
|
{
|
|
trxn.token.resize(s_ptr->rxn.token.size());
|
|
}
|
|
count_trxn = 0;
|
|
for (size_t i = 0; s_ptr->rxn.token[i].s != NULL; i++)
|
|
{
|
|
trxn.token[i].name = s_ptr->rxn.token[i].s->name;
|
|
trxn.token[i].z = s_ptr->rxn.token[i].s->z;
|
|
trxn.token[i].s = s_ptr->rxn.token[i].s;
|
|
trxn.token[i].unknown = NULL;
|
|
trxn.token[i].coef = s_ptr->rxn.token[i].coef;
|
|
count_trxn = i + 1;
|
|
if (count_trxn + 1 > trxn.token.size())
|
|
trxn.token.resize(count_trxn + 1);
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_isotopes(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Isotope ratios for each element or element valence state
|
|
*/
|
|
LDBLE isotope_number;
|
|
class master *master_ptr, *primary_ptr;
|
|
|
|
size_t primary_number = 0;
|
|
primary_ptr = NULL;
|
|
std::map<int, cxxSolution>::iterator it;
|
|
for (it = Rxn_solution_map.begin(); it != Rxn_solution_map.end(); it++)
|
|
{
|
|
std::map<std::string, cxxSolutionIsotope> new_isotopes;
|
|
cxxSolution &solution_ref = it->second;
|
|
if (!solution_ref.Get_new_def())
|
|
continue;
|
|
if (solution_ref.Get_isotopes().size() == 0)
|
|
continue;
|
|
|
|
std::map<std::string, cxxSolutionIsotope> primary_isotopes;
|
|
/*
|
|
* Make list of primary master species for isotopes
|
|
*/
|
|
std::map < std::string, cxxSolutionIsotope >::iterator kit = solution_ref.Get_isotopes().begin();
|
|
for ( ; kit != solution_ref.Get_isotopes().end(); kit++)
|
|
{
|
|
cxxSolutionIsotope &isotope_ref = kit->second;
|
|
master_ptr = master_bsearch_primary(isotope_ref.Get_elt_name().c_str());
|
|
isotope_number = isotope_ref.Get_isotope_number();
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"In isotope calculation: element not defined: %s.",
|
|
isotope_ref.Get_elt_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
std::ostringstream iso_name_str;
|
|
iso_name_str << (int) isotope_number << master_ptr->elt->name;
|
|
|
|
std::map < std::string, cxxSolutionIsotope >::iterator jit;
|
|
jit = primary_isotopes.find(iso_name_str.str().c_str());
|
|
if (jit == primary_isotopes.end())
|
|
{
|
|
cxxSolutionIsotope temp_isotope;
|
|
temp_isotope.Set_isotope_name(iso_name_str.str().c_str());
|
|
temp_isotope.Set_elt_name(master_ptr->elt->name);
|
|
temp_isotope.Set_isotope_number(isotope_number);
|
|
primary_isotopes[iso_name_str.str().c_str()] = temp_isotope;
|
|
}
|
|
}
|
|
if (get_input_errors() > 0)
|
|
return (ERROR);
|
|
/*
|
|
* Go through all redox states of the list of primary species and isotope number
|
|
*/
|
|
for (kit = primary_isotopes.begin(); kit != primary_isotopes.end(); kit++)
|
|
{
|
|
/* find index number of master species, set flag to FALSE */
|
|
master_ptr = master_bsearch(kit->second.Get_elt_name().c_str());
|
|
isotope_number = kit->second.Get_isotope_number();
|
|
for (int k = 0; k < (int)master.size(); k++)
|
|
{
|
|
master[k]->isotope = FALSE;
|
|
}
|
|
primary_number = master_ptr->number;
|
|
primary_ptr = master_ptr;
|
|
|
|
/* go through isotopes of solution and fill in master species */
|
|
std::map < std::string, cxxSolutionIsotope >::iterator lit = solution_ref.Get_isotopes().begin();
|
|
for ( ; lit != solution_ref.Get_isotopes().end(); lit++)
|
|
{
|
|
master_ptr = master_bsearch(lit->second.Get_elt_name().c_str());
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"In isotope calculation: element not defined: %s.",
|
|
lit->second.Get_elt_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* only fill for pertinent isotope */
|
|
if (master_ptr->elt->primary != primary_ptr)
|
|
continue;
|
|
if (lit->second.Get_isotope_number() != isotope_number)
|
|
continue;
|
|
|
|
/* for primary, fill in ratio for all secondary species */
|
|
if (master_ptr->primary == TRUE && master_ptr->s->secondary != NULL)
|
|
{
|
|
for (size_t k = primary_number + 1; k < (int)master.size(); k++)
|
|
{
|
|
if (master[k]->elt->primary != primary_ptr)
|
|
break;
|
|
master[k]->isotope_ratio = lit->second.Get_ratio();
|
|
master[k]->isotope_ratio_uncertainty = lit->second.Get_ratio_uncertainty();
|
|
if (master[k]->isotope == TRUE)
|
|
{
|
|
error_string = sformatf(
|
|
"In isotope calculation: redefinition of isotope ratio for %s.",
|
|
lit->second.Get_elt_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
master[k]->isotope = TRUE;
|
|
}
|
|
}
|
|
/* for secondary and non redox, set ratio */
|
|
else
|
|
{
|
|
master_ptr->isotope_ratio = lit->second.Get_ratio();
|
|
master_ptr->isotope_ratio_uncertainty = lit->second.Get_ratio_uncertainty();
|
|
if (master_ptr->isotope == TRUE)
|
|
{
|
|
error_string = sformatf(
|
|
"In isotope calculation: redefinition of isotope ratio for %s.",
|
|
lit->second.Get_elt_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
master_ptr->isotope = TRUE;
|
|
}
|
|
}
|
|
/*
|
|
* Write new isotope structure
|
|
*/
|
|
for (int k = 0; k < (int)master.size(); k++)
|
|
{
|
|
/* skip primary master species of redox elements */
|
|
if (master[k]->primary == TRUE && master[k]->s->secondary != NULL)
|
|
continue;
|
|
if (master[k]->elt->primary == primary_ptr && master[k]->isotope == FALSE)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Isotopic ratio not defined for element or valence state %g%s, using 0.",
|
|
(double) isotope_number, master[k]->elt->name);
|
|
warning_msg(error_string);
|
|
master[k]->isotope = TRUE;
|
|
master[k]->isotope_ratio = 0.0;
|
|
master[k]->isotope_ratio_uncertainty = 0.001;
|
|
}
|
|
if (master[k]->isotope == FALSE)
|
|
continue;
|
|
cxxSolutionIsotope temp_iso;
|
|
temp_iso.Set_isotope_number(isotope_number);
|
|
temp_iso.Set_elt_name(master[k]->elt->name);
|
|
temp_iso.Set_total(0);
|
|
temp_iso.Set_ratio(master[k]->isotope_ratio);
|
|
temp_iso.Set_ratio_uncertainty(master[k]->isotope_ratio_uncertainty);
|
|
if (!std::isnan(master[k]->isotope_ratio_uncertainty))
|
|
{
|
|
temp_iso.Set_ratio_uncertainty_defined(true);
|
|
}
|
|
std::string token = sformatf("%d%s", (int) isotope_number,
|
|
master[k]->elt->name);
|
|
temp_iso.Set_isotope_name(token.c_str());
|
|
new_isotopes[token] = temp_iso;
|
|
}
|
|
}
|
|
solution_ref.Set_isotopes(new_isotopes);
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_kin_exchange(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If exchanger is related to mineral, exchanger amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
cxxKinetics *kinetics_ptr;
|
|
const char* cptr;
|
|
LDBLE conc;
|
|
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
//for ( ; it != Rxn_exchange_map.end(); it++)
|
|
//for (size_t nn = 0; nn < Rxn_new_exchange.size(); nn++)
|
|
//{
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(Rxn_new_exchange[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_exchange.begin(); nit != Rxn_new_exchange.end(); nit++)
|
|
{
|
|
std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(*nit);
|
|
if (it == Rxn_exchange_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
cxxExchange * exchange_ptr = &(it->second);
|
|
if (!exchange_ptr->Get_new_def())
|
|
continue;
|
|
if (exchange_ptr->Get_n_user() < 0)
|
|
continue;
|
|
// check elements
|
|
for (size_t j = 0; j < exchange_ptr->Get_exchange_comps().size(); j++)
|
|
{
|
|
cxxExchComp & comp_ref = exchange_ptr->Get_exchange_comps()[j];
|
|
if (comp_ref.Get_rate_name().size() == 0)
|
|
continue;
|
|
/* First find exchange master species */
|
|
cxxNameDouble nd = comp_ref.Get_totals();
|
|
cxxNameDouble::iterator kit = nd.begin();
|
|
bool found_exchange = false;
|
|
for (; kit != nd.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element *elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr == NULL || elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Master species not in database "
|
|
"for %s, skipping element.",
|
|
kit->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_ptr->master->type == EX)
|
|
found_exchange = true;;
|
|
}
|
|
if (!found_exchange)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Exchange formula does not contain an exchange master species, %s",
|
|
comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* Now find associated kinetic reaction ... */
|
|
if ((kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, exchange_ptr->Get_n_user())) == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetics %d must be defined to use exchange related to kinetic reaction, %s",
|
|
exchange_ptr->Get_n_user(), comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
size_t k;
|
|
for (k = 0; k < kinetics_ptr->Get_kinetics_comps().size(); k++)
|
|
{
|
|
if (strcmp_nocase
|
|
(comp_ref.Get_rate_name().c_str(),
|
|
kinetics_ptr->Get_kinetics_comps()[k].Get_rate_name().c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (k == kinetics_ptr->Get_kinetics_comps().size())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetic reaction, %s, related to exchanger, %s, not found in KINETICS %d",
|
|
comp_ref.Get_rate_name().c_str(), comp_ref.Get_formula().c_str(), exchange_ptr->Get_n_user());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* use database name for phase */
|
|
comp_ref.Set_rate_name(kinetics_ptr->Get_kinetics_comps()[k].Get_rate_name().c_str());
|
|
|
|
/* make exchanger concentration proportional to mineral ... */
|
|
conc = kinetics_ptr->Get_kinetics_comps()[k].Get_m() * comp_ref.Get_phase_proportion();
|
|
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, conc);
|
|
}
|
|
comp_ref.Set_totals(elt_list_NameDouble());
|
|
/*
|
|
* No check on availability of exchange elements
|
|
*/
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
update_kin_exchange(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If exchanger is related to mineral, exchanger amount is
|
|
* set in proportion. Exchange needs to be updated if the
|
|
* amount of kinetic reaction has changed. Corner case of
|
|
* zero moles.
|
|
*/
|
|
{
|
|
cxxKinetics* kinetics_ptr;
|
|
const char* cptr;
|
|
LDBLE conc;
|
|
|
|
std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
for ( ; it != Rxn_exchange_map.end(); it++)
|
|
{
|
|
cxxExchange* exchange_ptr = &(it->second);
|
|
if (exchange_ptr->Get_n_user() < 0) continue;
|
|
// check elements
|
|
for (size_t j = 0; j < exchange_ptr->Get_exchange_comps().size(); j++)
|
|
{
|
|
cxxExchComp& comp_ref = exchange_ptr->Get_exchange_comps()[j];
|
|
if (comp_ref.Get_rate_name().size() == 0) continue;
|
|
double comp_moles = 0.0;
|
|
/* First find exchange master species */
|
|
cxxNameDouble nd = comp_ref.Get_totals();
|
|
cxxNameDouble::iterator kit = nd.begin();
|
|
bool found_exchange = false;
|
|
for (; kit != nd.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr == NULL || elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Master species not in database "
|
|
"for %s, skipping element.",
|
|
kit->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_ptr->master->type == EX)
|
|
{
|
|
comp_moles = kit->second;
|
|
found_exchange = true;
|
|
}
|
|
}
|
|
//if (!found_exchange)
|
|
//{
|
|
// input_error++;
|
|
// error_string = sformatf(
|
|
// "Exchange formula does not contain an exchange master species, %s",
|
|
// comp_ref.Get_formula().c_str());
|
|
// error_msg(error_string, CONTINUE);
|
|
// continue;
|
|
//}
|
|
|
|
/* Now find associated kinetic reaction ... */
|
|
if ((kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, exchange_ptr->Get_n_user())) == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetics %d must be defined to use exchange related to kinetic reaction, %s",
|
|
exchange_ptr->Get_n_user(), comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
size_t k;
|
|
for (k = 0; k < kinetics_ptr->Get_kinetics_comps().size(); k++)
|
|
{
|
|
if (strcmp_nocase
|
|
(comp_ref.Get_rate_name().c_str(),
|
|
kinetics_ptr->Get_kinetics_comps()[k].Get_rate_name().c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (k == kinetics_ptr->Get_kinetics_comps().size())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetic reaction, %s, related to exchanger, %s, not found in KINETICS %d",
|
|
comp_ref.Get_rate_name().c_str(), comp_ref.Get_formula().c_str(), exchange_ptr->Get_n_user());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* use database name for phase */
|
|
comp_ref.Set_rate_name(kinetics_ptr->Get_kinetics_comps()[k].Get_rate_name().c_str());
|
|
|
|
/* make exchanger concentration proportional to mineral ... */
|
|
conc = kinetics_ptr->Get_kinetics_comps()[k].Get_m() * comp_ref.Get_phase_proportion();
|
|
if (found_exchange && comp_moles > 0.0)
|
|
{
|
|
/* parse formula */
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, 1.0);
|
|
}
|
|
cxxNameDouble nd_formula = elt_list_NameDouble();
|
|
double comp_coef = 0;
|
|
for (kit = nd_formula.begin(); kit != nd_formula.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr->master->type == EX)
|
|
{
|
|
comp_coef = kit->second;
|
|
}
|
|
}
|
|
comp_ref.multiply(comp_coef * conc / comp_moles);
|
|
}
|
|
else /* need to generate totals from scratch */
|
|
{
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, conc);
|
|
}
|
|
comp_ref.Set_totals(elt_list_NameDouble());
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_min_exchange(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If exchanger is related to mineral, exchanger amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
int n, jj;
|
|
const char* cptr;
|
|
LDBLE conc;
|
|
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
//for ( ; it != Rxn_exchange_map.end(); it++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_exchange.size(); nn++)
|
|
//{
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(Rxn_new_exchange[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_exchange.begin(); nit != Rxn_new_exchange.end(); nit++)
|
|
{
|
|
std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(*nit);
|
|
if (it == Rxn_exchange_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
cxxExchange * exchange_ptr = &(it->second);
|
|
if (!exchange_ptr->Get_new_def())
|
|
continue;
|
|
if (exchange_ptr->Get_n_user() < 0)
|
|
continue;
|
|
n = exchange_ptr->Get_n_user();
|
|
// check elements
|
|
for (size_t j = 0; j < exchange_ptr->Get_exchange_comps().size(); j++)
|
|
{
|
|
cxxExchComp & comp_ref = exchange_ptr->Get_exchange_comps()[j];
|
|
if (comp_ref.Get_phase_name().size() == 0)
|
|
continue;
|
|
/* First find exchange master species */
|
|
cxxNameDouble nd = comp_ref.Get_totals();
|
|
cxxNameDouble::iterator kit = nd.begin();
|
|
bool found_exchange = false;
|
|
for (; kit != nd.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element *elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr == NULL || elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Master species not in database "
|
|
"for %s, skipping element.",
|
|
kit->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_ptr->master->type == EX)
|
|
{
|
|
found_exchange = true;;
|
|
}
|
|
}
|
|
if (!found_exchange)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Exchange formula does not contain an exchange master species, %s",
|
|
comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
cxxPPassemblage *pp_assemblage_ptr = Utilities::Rxn_find(Rxn_pp_assemblage_map, n);
|
|
/* Now find the mineral on which exchanger depends... */
|
|
if (pp_assemblage_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equilibrium_phases %d must be defined to use exchange related to mineral phase, %s",
|
|
n, comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
std::map<std::string, cxxPPassemblageComp>::iterator jit;
|
|
jit = pp_assemblage_ptr->Get_pp_assemblage_comps().begin();
|
|
for ( ; jit != pp_assemblage_ptr->Get_pp_assemblage_comps().end(); jit++)
|
|
{
|
|
if (strcmp_nocase(comp_ref.Get_phase_name().c_str(), jit->first.c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (jit == pp_assemblage_ptr->Get_pp_assemblage_comps().end() )
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to exchanger, %s, not found in Equilibrium_Phases %d",
|
|
comp_ref.Get_phase_name().c_str(), comp_ref.Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
/* use database name for phase */
|
|
comp_ref.Set_phase_name(jit->first.c_str());
|
|
/* make exchanger concentration proportional to mineral ... */
|
|
conc = jit->second.Get_moles() * comp_ref.Get_phase_proportion();
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, conc);
|
|
}
|
|
comp_ref.Set_totals(elt_list_NameDouble());
|
|
/*
|
|
* make sure exchange elements are in phase
|
|
*/
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, -comp_ref.Get_phase_proportion());
|
|
}
|
|
int l;
|
|
class phase *phase_ptr = phase_bsearch(jit->first.c_str(), &l, FALSE);
|
|
if (phase_ptr != NULL)
|
|
{
|
|
cptr = phase_ptr->formula;
|
|
get_elts_in_species(&cptr, 1.0);
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to exchanger, %s, not found in Equilibrium_Phases %d",
|
|
comp_ref.Get_phase_name().c_str(), comp_ref.Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
elt_list_combine();
|
|
for (jj = 0; jj < count_elts; jj++)
|
|
{
|
|
if (elt_list[jj].elt->primary->s->type != EX
|
|
&& elt_list[jj].coef < 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Stoichiometry of exchanger, %s * %g mol sites/mol phase,\n\tmust be a subset of the related phase %s, %s.",
|
|
comp_ref.Get_formula().c_str(),
|
|
(double) comp_ref.Get_phase_proportion(),
|
|
phase_ptr->name,
|
|
phase_ptr->formula);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
update_min_exchange(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If exchanger is related to mineral, exchanger amount is
|
|
* set in proportion. Need to check in case exchange or min
|
|
* are modified.
|
|
*/
|
|
{
|
|
int n, jj;
|
|
const char* cptr;
|
|
LDBLE conc;
|
|
|
|
std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
for ( ; it != Rxn_exchange_map.end(); it++)
|
|
{
|
|
cxxExchange* exchange_ptr = &(it->second);
|
|
if (exchange_ptr->Get_n_user() < 0) continue;
|
|
n = exchange_ptr->Get_n_user();
|
|
// check elements
|
|
for (size_t j = 0; j < exchange_ptr->Get_exchange_comps().size(); j++)
|
|
{
|
|
double comp_moles = 0.0;
|
|
cxxExchComp& comp_ref = exchange_ptr->Get_exchange_comps()[j];
|
|
if (comp_ref.Get_phase_name().size() == 0) continue;
|
|
/* First find exchange master species */
|
|
cxxNameDouble nd = comp_ref.Get_totals();
|
|
cxxNameDouble::iterator kit = nd.begin();
|
|
bool found_exchange = false;
|
|
for (; kit != nd.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr == NULL || elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Master species not in database "
|
|
"for %s, skipping element.",
|
|
kit->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_ptr->master->type == EX)
|
|
{
|
|
comp_moles = kit->second;
|
|
found_exchange = true;
|
|
}
|
|
}
|
|
//if (!found_exchange)
|
|
//{
|
|
// input_error++;
|
|
// error_string = sformatf(
|
|
// "Exchange formula does not contain an exchange master species, %s",
|
|
// comp_ref.Get_formula().c_str());
|
|
// error_msg(error_string, CONTINUE);
|
|
// continue;
|
|
//}
|
|
|
|
cxxPPassemblage* pp_assemblage_ptr = Utilities::Rxn_find(Rxn_pp_assemblage_map, n);
|
|
/* Now find the mineral on which exchanger depends... */
|
|
if (pp_assemblage_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equilibrium_phases %d must be defined to use exchange related to mineral phase, %s",
|
|
n, comp_ref.Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
std::map<std::string, cxxPPassemblageComp>::iterator jit;
|
|
jit = pp_assemblage_ptr->Get_pp_assemblage_comps().begin();
|
|
for (; jit != pp_assemblage_ptr->Get_pp_assemblage_comps().end(); jit++)
|
|
{
|
|
if (strcmp_nocase(comp_ref.Get_phase_name().c_str(), jit->first.c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (jit == pp_assemblage_ptr->Get_pp_assemblage_comps().end())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to exchanger, %s, not found in Equilibrium_Phases %d",
|
|
comp_ref.Get_phase_name().c_str(), comp_ref.Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
/* use database name for phase */
|
|
comp_ref.Set_phase_name(jit->first.c_str());
|
|
|
|
/* make exchanger concentration proportional to mineral ... */
|
|
conc = jit->second.Get_moles() * comp_ref.Get_phase_proportion();
|
|
if (found_exchange && comp_moles > 0.0)
|
|
{
|
|
/* parse formula */
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, 1.0);
|
|
}
|
|
cxxNameDouble nd_formula = elt_list_NameDouble();
|
|
double comp_coef = 0;
|
|
for (kit = nd_formula.begin(); kit != nd_formula.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr->master->type == EX)
|
|
{
|
|
comp_coef = kit->second;
|
|
}
|
|
}
|
|
comp_ref.multiply(comp_coef * conc / comp_moles);
|
|
}
|
|
else /* comp_moles is zero, need to redefine totals from scratch */
|
|
{
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, conc);
|
|
}
|
|
comp_ref.Set_totals(elt_list_NameDouble());
|
|
/*
|
|
* make sure exchange elements are in phase
|
|
*/
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
cptr = comp_ref.Get_formula().c_str();
|
|
get_elts_in_species(&cptr, -comp_ref.Get_phase_proportion());
|
|
}
|
|
int l;
|
|
class phase* phase_ptr = phase_bsearch(jit->first.c_str(), &l, FALSE);
|
|
if (phase_ptr != NULL)
|
|
{
|
|
cptr = phase_ptr->formula;
|
|
get_elts_in_species(&cptr, 1.0);
|
|
}
|
|
else
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to exchanger, %s, not found in Equilibrium_Phases %d",
|
|
comp_ref.Get_phase_name().c_str(), comp_ref.Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
elt_list_combine();
|
|
for (jj = 0; jj < count_elts; jj++)
|
|
{
|
|
if (elt_list[jj].elt->primary->s->type != EX
|
|
&& elt_list[jj].coef < 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Stoichiometry of exchanger, %s * %g mol sites/mol phase,\n\tmust be a subset of the related phase %s, %s.",
|
|
comp_ref.Get_formula().c_str(),
|
|
(double)comp_ref.Get_phase_proportion(),
|
|
phase_ptr->name,
|
|
phase_ptr->formula);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_min_surface(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If surface is related to mineral, surface amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
//std::map<int, cxxSurface>::iterator kit;
|
|
//for (kit = Rxn_surface_map.begin(); kit != Rxn_surface_map.end(); kit++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_surface.size(); nn++)
|
|
//{
|
|
// std::map<int, cxxSurface>::iterator kit = Rxn_surface_map.find(Rxn_new_surface[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_surface.begin(); nit != Rxn_new_surface.end(); nit++)
|
|
{
|
|
std::map<int, cxxSurface>::iterator kit = Rxn_surface_map.find(*nit);
|
|
if (kit == Rxn_surface_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
cxxSurface *surface_ptr = &(kit->second);
|
|
if (!surface_ptr->Get_new_def())
|
|
continue;
|
|
if (surface_ptr->Get_n_user() < 0)
|
|
continue;
|
|
for (size_t j = 0; j < surface_ptr->Get_surface_comps().size(); j++)
|
|
{
|
|
cxxSurfaceComp *surface_comp_ptr = &(surface_ptr->Get_surface_comps()[j]);
|
|
cxxSurfaceCharge *surface_charge_ptr = surface_ptr->Find_charge(surface_comp_ptr->Get_charge_name());
|
|
if (surface_comp_ptr->Get_phase_name().size() == 0)
|
|
continue;
|
|
int n = surface_ptr->Get_n_user();
|
|
|
|
/* First find surface master species */
|
|
|
|
cxxNameDouble::iterator it;
|
|
for (it = surface_comp_ptr->Get_totals().begin(); it != surface_comp_ptr->Get_totals().end(); it++)
|
|
{
|
|
/* Find master species */
|
|
class element *elt_ptr = element_store(it->first.c_str());
|
|
class master *master_ptr = elt_ptr->master;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Master species not in database "
|
|
"for %s, skipping element.",
|
|
elt_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->type != SURF)
|
|
continue;
|
|
surface_comp_ptr->Set_master_element(elt_ptr->name);
|
|
break;
|
|
}
|
|
if (surface_comp_ptr->Get_master_element().size() == 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Surface formula does not contain a surface master species, %s",
|
|
surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* Now find the mineral on which surface depends... */
|
|
cxxPPassemblage * pp_assemblage_ptr = Utilities::Rxn_find(Rxn_pp_assemblage_map, n);
|
|
if (pp_assemblage_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equilibrium_phases %d must be defined to use surface related to mineral phase, %s",
|
|
n, surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
std::map<std::string, cxxPPassemblageComp>::iterator jit;
|
|
jit = pp_assemblage_ptr->Get_pp_assemblage_comps().begin();
|
|
for ( ; jit != pp_assemblage_ptr->Get_pp_assemblage_comps().end(); jit++)
|
|
{
|
|
if (strcmp_nocase(surface_comp_ptr->Get_phase_name().c_str(),
|
|
jit->first.c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (jit == pp_assemblage_ptr->Get_pp_assemblage_comps().end())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to surface, %s, not found in Equilibrium_Phases %d",
|
|
surface_comp_ptr->Get_phase_name().c_str(), surface_comp_ptr->Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
int l;
|
|
class phase *phase_ptr = phase_bsearch(jit->first.c_str(), &l, FALSE);
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to surface, %s, not found in database.",
|
|
jit->first.c_str(), surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
/* use database name for phase */
|
|
surface_comp_ptr->Set_phase_name(phase_ptr->name);
|
|
/* make surface concentration proportional to mineral ... */
|
|
LDBLE conc = jit->second.Get_moles() * surface_comp_ptr->Get_phase_proportion();
|
|
/* if (conc < MIN_RELATED_SURFACE) conc = 0.0; */
|
|
{
|
|
char * temp_formula = string_duplicate(surface_comp_ptr->Get_formula().c_str());
|
|
const char* cptr = temp_formula;
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
get_elts_in_species(&cptr, conc);
|
|
free_check_null(temp_formula);
|
|
}
|
|
{
|
|
if (surface_ptr->Get_new_def())
|
|
{
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
surface_comp_ptr->Set_totals(nd);
|
|
}
|
|
else
|
|
{
|
|
surface_comp_ptr->Get_totals()[surface_comp_ptr->Get_master_element()] = conc;
|
|
}
|
|
}
|
|
|
|
/* area */
|
|
if (surface_charge_ptr)
|
|
{
|
|
surface_charge_ptr->Set_grams(jit->second.Get_moles());
|
|
}
|
|
/*
|
|
* make sure surface elements are in phase
|
|
* logically necessary for mass balance and to avoid negative concentrations when dissolving phase
|
|
*/
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
{
|
|
const char* cptr = phase_ptr->formula;
|
|
get_elts_in_species(&cptr, 1.0);
|
|
}
|
|
// Revise logic for surface related to mineral
|
|
for (size_t jj = 0; jj < surface_ptr->Get_surface_comps().size(); jj++)
|
|
{
|
|
cxxSurfaceComp *comp_jj_ptr = &(surface_ptr->Get_surface_comps()[jj]);
|
|
// Use formula for all types of surfaces
|
|
{
|
|
const char* cptr = comp_jj_ptr->Get_formula().c_str();
|
|
get_elts_in_species(&cptr, -comp_jj_ptr->Get_phase_proportion());
|
|
|
|
if (surface_ptr->Get_type() != cxxSurface::CD_MUSIC)
|
|
{
|
|
|
|
// Warn if not master species and charge balanced
|
|
class element *elt_ptr = element_store(comp_jj_ptr->Get_master_element().c_str());
|
|
if (elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Unknown element definition in SURFACE \n\t for surface related to equilibrium_phase: SURFACE %d.",
|
|
surface_ptr->Get_n_user());
|
|
error_msg(error_string);
|
|
continue;
|
|
}
|
|
if (elt_ptr->master->s == NULL || elt_ptr->master->s->name == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Unknown master species definition in SURFACE \n\t for surface related to equilibrium_phase: SURFACE %d.",
|
|
surface_ptr->Get_n_user());
|
|
error_msg(error_string);
|
|
continue;
|
|
}
|
|
//if (strcmp(elt_ptr->master->s->name, temp_formula) != 0)
|
|
//{
|
|
// error_string = sformatf("Suggest using master species formula in SURFACE \n\t for surface related to equilibrium_phase: %s.",
|
|
// elt_ptr->master->s->name);
|
|
// warning_msg(error_string);
|
|
//}
|
|
if (elt_ptr->master->s->z != 0.0 && surface_ptr->Get_dl_type() != cxxSurface::DONNAN_DL)
|
|
{
|
|
error_string = sformatf(
|
|
"Use the -donnan option when coupling surface %s to an equilibrium_phase, \n\t and note to give the equilibrium_phase the surface charge.",
|
|
elt_ptr->master->s->name);
|
|
warning_msg(error_string);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elt_list_combine();
|
|
/* Makes no sense: sorbed species need not be in mineral structure... */
|
|
/* But elements that can desorb into solution must be in mineral */
|
|
/* If you precipitate Ca-Mont, and make SurfMg (assuming this is the
|
|
formula in SURFACE), where does the Mg come from?
|
|
Further, if you precipitate Ca-Mont, make SurfCa, desorb
|
|
all the Ca, then dissolve the "Ca-Mont", you must remove SurfCa, or you
|
|
will end up with Ca in solution. H and O are excluded */
|
|
/* Example that makes montmorillonite a cation exchanger:
|
|
PHASES
|
|
Summ_Montmorillonite; Al2.33Si3.67O10(OH)2-0.33 + 12 H2O = 2.33 Al(OH)4- + 3.67 H4SiO4 + 2 H+; -log_k -44.4
|
|
SURFACE_MASTER_SPECIES; Summ Summ-; SURFACE_SPECIES; Summ- = Summ-
|
|
SOLUTION 1; Na 1e1; Cl 1e1; pH 7 charge; C(4) 1 CO2(g) -2
|
|
EQUILIBRIUM_PHASES 1; Ca-Montmorillonite 0 1e-3
|
|
Summ_Montmorillonite 0 0
|
|
SURFACE 1; Summ Summ_Montmorillonite 0.33 3.11e5; -donnan; -equil 1
|
|
END
|
|
*/
|
|
for (int jj = 0; jj < count_elts; jj++)
|
|
{
|
|
if (elt_list[jj].elt->primary == NULL)
|
|
{
|
|
error_string = sformatf("Primary master species missing for %s",
|
|
elt_list[jj].elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
if (elt_list[jj].elt->primary->s == NULL)
|
|
{
|
|
error_string = sformatf(
|
|
"Species missing for %s", elt_list[jj].elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
|
|
if (elt_list[jj].elt->primary->s->type != SURF
|
|
&& elt_list[jj].coef < 0
|
|
//&& elt_list[jj].elt->primary->s != s_hplus
|
|
//&& elt_list[jj].elt->primary->s != s_h2o
|
|
)
|
|
{
|
|
class element *elt_ptr = element_store(surface_comp_ptr->Get_master_element().c_str());
|
|
error_string = sformatf(
|
|
"Element %s in sum of surface sites,\n"
|
|
"\t including %s * %g mol sites/mol phase,\n"
|
|
"\t exceeds stoichiometry in the related phase %s, %s.",
|
|
elt_list[jj].elt->name,
|
|
elt_ptr->master->s->name,
|
|
(double) surface_comp_ptr->Get_phase_proportion(),
|
|
phase_ptr->name,
|
|
phase_ptr->formula);
|
|
warning_msg(error_string);
|
|
warning_msg("The mismatch in stoichiometry may cause mass-balance errors or unwanted redox reactions.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
update_min_surface(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If surface is related to mineral, surface amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
std::map<int, cxxSurface>::iterator kit;
|
|
for (kit = Rxn_surface_map.begin(); kit != Rxn_surface_map.end(); kit++)
|
|
{
|
|
cxxSurface* surface_ptr = &(kit->second);
|
|
if (surface_ptr->Get_n_user() < 0) continue;
|
|
for (size_t j = 0; j < surface_ptr->Get_surface_comps().size(); j++)
|
|
{
|
|
double comp_moles = 0.0;
|
|
cxxSurfaceComp* surface_comp_ptr = &(surface_ptr->Get_surface_comps()[j]);
|
|
if (surface_comp_ptr->Get_phase_name().size() == 0) continue;
|
|
cxxSurfaceCharge* surface_charge_ptr = NULL;
|
|
if (surface_ptr->Get_type() != cxxSurface::NO_EDL)
|
|
{
|
|
surface_charge_ptr = surface_ptr->Find_charge(surface_comp_ptr->Get_charge_name());
|
|
if (surface_charge_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Data structure for surface charge not found "
|
|
"for %s ",
|
|
surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
}
|
|
int n = surface_ptr->Get_n_user();
|
|
|
|
/* First find surface master species */
|
|
cxxNameDouble::iterator it;
|
|
for (it = surface_comp_ptr->Get_totals().begin(); it != surface_comp_ptr->Get_totals().end(); it++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(it->first.c_str());
|
|
class master* master_ptr = elt_ptr->master;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Master species not in database "
|
|
"for %s, skipping element.",
|
|
elt_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->type != SURF) continue;
|
|
comp_moles = it->second;
|
|
surface_comp_ptr->Set_master_element(elt_ptr->name);
|
|
break;
|
|
}
|
|
//if (surface_comp_ptr->Get_master_element().size() == 0)
|
|
//{
|
|
// input_error++;
|
|
// error_string = sformatf(
|
|
// "Surface formula does not contain a surface master species, %s",
|
|
// surface_comp_ptr->Get_formula().c_str());
|
|
// error_msg(error_string, CONTINUE);
|
|
// continue;
|
|
//}
|
|
|
|
/* Now find the mineral on which surface depends... */
|
|
cxxPPassemblage* pp_assemblage_ptr = Utilities::Rxn_find(Rxn_pp_assemblage_map, n);
|
|
if (pp_assemblage_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Equilibrium_phases %d must be defined to use surface related to mineral phase, %s",
|
|
n, surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
std::map<std::string, cxxPPassemblageComp>::iterator jit;
|
|
jit = pp_assemblage_ptr->Get_pp_assemblage_comps().begin();
|
|
for (; jit != pp_assemblage_ptr->Get_pp_assemblage_comps().end(); jit++)
|
|
{
|
|
if (strcmp_nocase(surface_comp_ptr->Get_phase_name().c_str(),
|
|
jit->first.c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (jit == pp_assemblage_ptr->Get_pp_assemblage_comps().end())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to surface, %s, not found in Equilibrium_Phases %d",
|
|
surface_comp_ptr->Get_phase_name().c_str(), surface_comp_ptr->Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
int l;
|
|
class phase* phase_ptr = phase_bsearch(jit->first.c_str(), &l, FALSE);
|
|
if (phase_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Mineral, %s, related to surface, %s, not found in database.",
|
|
jit->first.c_str(), surface_comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
/* use database name for phase */
|
|
surface_comp_ptr->Set_phase_name(phase_ptr->name);
|
|
/* make surface concentration proportional to mineral ... */
|
|
LDBLE conc = jit->second.Get_moles() * surface_comp_ptr->Get_phase_proportion();
|
|
double grams = 0.0;
|
|
if (surface_charge_ptr != NULL)
|
|
{
|
|
grams = surface_charge_ptr->Get_grams();
|
|
}
|
|
if (comp_moles > 0.0)
|
|
{
|
|
surface_comp_ptr->multiply(conc / comp_moles);
|
|
}
|
|
else /* need to generate from scratch */
|
|
{
|
|
char* temp_formula = string_duplicate(surface_comp_ptr->Get_formula().c_str());
|
|
const char* cptr = temp_formula;
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
get_elts_in_species(&cptr, conc);
|
|
free_check_null(temp_formula);
|
|
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
surface_comp_ptr->Set_totals(nd);
|
|
}
|
|
if (grams > 0.0)
|
|
{
|
|
surface_charge_ptr->multiply(jit->second.Get_moles() / grams);
|
|
}
|
|
else if (surface_charge_ptr != NULL) /* need to generate from scratch */
|
|
{
|
|
surface_charge_ptr->Set_grams(jit->second.Get_moles());
|
|
surface_charge_ptr->Set_charge_balance(0.0);
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_kin_surface(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If surface is related to mineral, surface amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
cxxKinetics *kinetics_ptr;
|
|
class phase *phase_ptr;
|
|
std::vector<class elt_list> elt_list_kinetics;
|
|
size_t count_elts_kinetics;
|
|
|
|
//std::map<int, cxxSurface>::iterator it;
|
|
//for (it = Rxn_surface_map.begin(); it != Rxn_surface_map.end(); it++)
|
|
//{
|
|
//for (size_t nn = 0; nn < Rxn_new_surface.size(); nn++)
|
|
//{
|
|
// std::map<int, cxxSurface>::iterator it = Rxn_surface_map.find(Rxn_new_surface[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_surface.begin(); nit != Rxn_new_surface.end(); nit++)
|
|
{
|
|
std::map<int, cxxSurface>::iterator it = Rxn_surface_map.find(*nit);
|
|
if (it == Rxn_surface_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
cxxSurface *surface_ptr = &(it->second);
|
|
if (!surface_ptr->Get_new_def())
|
|
continue;
|
|
if (surface_ptr->Get_n_user() < 0)
|
|
continue;
|
|
int n = surface_ptr->Get_n_user();
|
|
for (size_t j = 0; j < surface_ptr->Get_surface_comps().size(); j++)
|
|
{
|
|
cxxSurfaceComp *comp_ptr = &(surface_ptr->Get_surface_comps()[j]);
|
|
if (comp_ptr->Get_rate_name().size() == 0)
|
|
continue;
|
|
comp_ptr->Set_master_element("");
|
|
|
|
/* First find surface master species */
|
|
int k;
|
|
cxxNameDouble::iterator kit;
|
|
for (kit = comp_ptr->Get_totals().begin(); kit != comp_ptr->Get_totals().end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element *elt_ptr = element_store(kit->first.c_str());
|
|
class master *master_ptr = elt_ptr->master;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Master species not in database "
|
|
"for %s, skipping element.",
|
|
elt_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->type != SURF)
|
|
continue;
|
|
comp_ptr->Set_master_element(elt_ptr->name);
|
|
break;
|
|
}
|
|
if (comp_ptr->Get_master_element().size() == 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Surface formula does not contain a surface master species, %s",
|
|
comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* Now find the kinetic reaction on which surface depends... */
|
|
if ((kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, n)) == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetics %d must be defined to use surface related to kinetic reaction, %s",
|
|
n, comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
for (k = 0; k < (int) kinetics_ptr->Get_kinetics_comps().size(); k++)
|
|
{
|
|
cxxKineticsComp *kin_comp_ptr = &(kinetics_ptr->Get_kinetics_comps()[k]);
|
|
if (strcmp_nocase
|
|
(comp_ptr->Get_rate_name().c_str(),
|
|
kin_comp_ptr->Get_rate_name().c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (k == (int) kinetics_ptr->Get_kinetics_comps().size())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetic reaction, %s, related to surface, %s, not found in Kinetics %d",
|
|
comp_ptr->Get_rate_name().c_str(), comp_ptr->Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
cxxKineticsComp *kin_comp_ptr = &(kinetics_ptr->Get_kinetics_comps()[k]);
|
|
/* use database name for phase */
|
|
comp_ptr->Set_rate_name(kin_comp_ptr->Get_rate_name().c_str());
|
|
|
|
/* make surface concentration proportional to mineral ... */
|
|
LDBLE conc = kin_comp_ptr->Get_m() * comp_ptr->Get_phase_proportion();
|
|
|
|
/* if (conc < MIN_RELATED_SURFACE) conc = 0.0; */
|
|
{
|
|
const char* cptr = comp_ptr->Get_formula().c_str();
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
get_elts_in_species(&cptr, conc);
|
|
}
|
|
{
|
|
if (surface_ptr->Get_new_def())
|
|
{
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
comp_ptr->Set_totals(nd);
|
|
}
|
|
else
|
|
{
|
|
comp_ptr->Get_totals()[comp_ptr->Get_master_element()] = conc;
|
|
}
|
|
}
|
|
|
|
/* area */
|
|
|
|
cxxSurfaceCharge *charge_ptr = surface_ptr->Find_charge(comp_ptr->Get_charge_name());
|
|
charge_ptr->Set_grams(kin_comp_ptr->Get_m());
|
|
}
|
|
/*
|
|
* check on elements
|
|
*/
|
|
/* Go through each kinetic reaction, add all related surface compositions
|
|
* check for negative values
|
|
*/
|
|
if (!surface_ptr->Get_related_rate())
|
|
continue;
|
|
kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, n);
|
|
if (kinetics_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Error in SURFACE related to KINETICS. ");
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
for (size_t k = 0; k < kinetics_ptr->Get_kinetics_comps().size(); k++)
|
|
{
|
|
cxxKineticsComp *kin_comp_ptr = &(kinetics_ptr->Get_kinetics_comps()[k]);
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
|
|
/* added in kinetics formula */
|
|
cxxNameDouble::iterator jit = kin_comp_ptr->Get_namecoef().begin();
|
|
for (; jit != kin_comp_ptr->Get_namecoef().end(); jit++)
|
|
{
|
|
std::string name = jit->first;
|
|
LDBLE coef = jit->second;
|
|
phase_ptr = NULL;
|
|
int jj;
|
|
phase_ptr = phase_bsearch(name.c_str(), &jj, FALSE);
|
|
if (phase_ptr != NULL)
|
|
{
|
|
add_elt_list(phase_ptr->next_elt, 1.0);
|
|
}
|
|
else
|
|
{
|
|
const char* cptr = name.c_str();
|
|
get_elts_in_species(&cptr, coef);
|
|
}
|
|
}
|
|
/* save kinetics formula */
|
|
if (count_elts > 0)
|
|
{
|
|
elt_list_combine();
|
|
}
|
|
elt_list_kinetics = elt_list_vsave();
|
|
count_elts_kinetics = count_elts;
|
|
|
|
/* get surface formulas */
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
cxxSurfaceComp *comp_ptr_save = NULL;
|
|
for (size_t j = 0; j < surface_ptr->Get_surface_comps().size(); j++)
|
|
{
|
|
cxxSurfaceComp *comp_ptr = &(surface_ptr->Get_surface_comps()[j]);
|
|
if (comp_ptr->Get_rate_name().size() == 0)
|
|
continue;
|
|
comp_ptr_save = comp_ptr;
|
|
if (strcmp_nocase
|
|
(comp_ptr->Get_rate_name().c_str(),
|
|
kin_comp_ptr->Get_rate_name().c_str()) == 0)
|
|
{
|
|
const char* cptr = comp_ptr->Get_formula().c_str();
|
|
get_elts_in_species(&cptr, -1 * comp_ptr->Get_phase_proportion());
|
|
}
|
|
}
|
|
elt_list_combine();
|
|
for (int j = 0; j < count_elts; j++)
|
|
{
|
|
if (elt_list[j].elt == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Cannot identify elements in kinetics component %s.",
|
|
comp_ptr_save->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_list[j].elt->primary == NULL )
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Cannot identify primary element in kinetics component %s.",
|
|
comp_ptr_save->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (elt_list[j].elt->primary->s == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Cannot identify primary species for an element in kinetics component %s.",
|
|
comp_ptr_save->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
if (elt_list[j].elt->primary->s->type <= H2O)
|
|
{
|
|
int l;
|
|
for (l = 0; l < count_elts_kinetics; l++)
|
|
{
|
|
if (elt_list[j].elt == elt_list_kinetics[l].elt)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (l == count_elts_kinetics)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Stoichiometry of surface, %s * %g mol sites/mol reactant,\n\tmust be a subset of the formula defined for the related reactant %s.\n\tElement %s is not present in reactant formula.",
|
|
comp_ptr_save->Get_formula().c_str(),
|
|
(double) comp_ptr_save->Get_phase_proportion(),
|
|
comp_ptr_save->Get_rate_name().c_str(), elt_list[j].elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
else if (fabs(elt_list[j].coef) >
|
|
fabs(elt_list_kinetics[l].coef))
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Stoichiometry of surface, %s * %g mol sites/mol reactant,\n\tmust be a subset of the formula defined for the related reactant %s.\n\tCoefficient of element %s in surface exceeds amount present in reactant formula.",
|
|
comp_ptr_save->Get_formula().c_str(),
|
|
(double) comp_ptr_save->Get_phase_proportion(),
|
|
comp_ptr_save->Get_rate_name().c_str(), elt_list[j].elt->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
elt_list_kinetics.clear();
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
update_kin_surface(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If surface is related to mineral, surface amount is
|
|
* set in proportion. Need to update surface if
|
|
* moles of kinetic reaction changes
|
|
*/
|
|
{
|
|
cxxKinetics* kinetics_ptr;
|
|
|
|
std::map<int, cxxSurface>::iterator it;
|
|
for (it = Rxn_surface_map.begin(); it != Rxn_surface_map.end(); it++)
|
|
{
|
|
cxxSurface* surface_ptr = &(it->second);
|
|
if (surface_ptr->Get_n_user() < 0) continue;
|
|
int n = surface_ptr->Get_n_user();
|
|
for (size_t j = 0; j < surface_ptr->Get_surface_comps().size(); j++)
|
|
{
|
|
double comp_moles = 0.0;
|
|
cxxSurfaceComp* comp_ptr = &(surface_ptr->Get_surface_comps()[j]);
|
|
if (comp_ptr->Get_rate_name().size() == 0) continue;
|
|
comp_ptr->Set_master_element("");
|
|
|
|
/* First find surface master species */
|
|
int k;
|
|
cxxNameDouble::iterator kit;
|
|
for (kit = comp_ptr->Get_totals().begin(); kit != comp_ptr->Get_totals().end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element* elt_ptr = element_store(kit->first.c_str());
|
|
class master* master_ptr = elt_ptr->master;
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Master species not in database "
|
|
"for %s, skipping element.",
|
|
elt_ptr->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
if (master_ptr->type != SURF) continue;
|
|
comp_ptr->Set_master_element(elt_ptr->name);
|
|
comp_moles = kit->second;
|
|
break;
|
|
}
|
|
if (comp_ptr->Get_master_element().size() == 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Surface formula does not contain a surface master species, %s",
|
|
comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
/* Now find the kinetic reaction on which surface depends... */
|
|
if ((kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, n)) == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetics %d must be defined to use surface related to kinetic reaction, %s",
|
|
n, comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
for (k = 0; k < (int)kinetics_ptr->Get_kinetics_comps().size(); k++)
|
|
{
|
|
cxxKineticsComp* kin_comp_ptr = &(kinetics_ptr->Get_kinetics_comps()[k]);
|
|
if (strcmp_nocase
|
|
(comp_ptr->Get_rate_name().c_str(),
|
|
kin_comp_ptr->Get_rate_name().c_str()) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (k == (int)kinetics_ptr->Get_kinetics_comps().size())
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Kinetic reaction, %s, related to surface, %s, not found in Kinetics %d",
|
|
comp_ptr->Get_rate_name().c_str(), comp_ptr->Get_formula().c_str(), n);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
|
|
cxxKineticsComp* kin_comp_ptr = &(kinetics_ptr->Get_kinetics_comps()[k]);
|
|
/* use database name for rate */
|
|
comp_ptr->Set_rate_name(kin_comp_ptr->Get_rate_name().c_str());
|
|
cxxSurfaceCharge* charge_ptr = surface_ptr->Find_charge(comp_ptr->Get_charge_name());
|
|
if (surface_ptr->Get_type() != cxxSurface::NO_EDL)
|
|
{
|
|
charge_ptr = surface_ptr->Find_charge(comp_ptr->Get_charge_name());
|
|
if (charge_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf("Data structure for surface charge not found "
|
|
"for %s ",
|
|
comp_ptr->Get_formula().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
}
|
|
/* make surface concentration proportional to mineral ... */
|
|
LDBLE conc = kin_comp_ptr->Get_m() * comp_ptr->Get_phase_proportion();
|
|
double grams = 0.0;
|
|
if (charge_ptr != NULL) charge_ptr->Get_grams();
|
|
if (comp_moles > 0.0)
|
|
{
|
|
comp_ptr->multiply(conc / comp_moles);
|
|
}
|
|
else /* need to generate from scratch */
|
|
{
|
|
const char* cptr = comp_ptr->Get_formula().c_str();
|
|
count_elts = 0;
|
|
paren_count = 0;
|
|
get_elts_in_species(&cptr, conc);
|
|
|
|
cxxNameDouble nd = elt_list_NameDouble();
|
|
comp_ptr->Set_totals(nd);
|
|
}
|
|
|
|
if (grams > 0.0)
|
|
{
|
|
charge_ptr->multiply(kin_comp_ptr->Get_m() / grams);
|
|
}
|
|
else if (charge_ptr != NULL) /* need to generate from scratch */
|
|
{
|
|
charge_ptr->Set_grams(kin_comp_ptr->Get_m());
|
|
charge_ptr->Set_charge_balance(0.0);
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
ss_prep(LDBLE t, cxxSS *ss_ptr, int print)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j, k, converged, divisions;
|
|
LDBLE r, rt, ag0, ag1, crit_pt;
|
|
LDBLE xc, tc;
|
|
LDBLE l_x, x0, x1, xsm1, xsm2, xb1, xb2;
|
|
LDBLE xc1, xc2;
|
|
LDBLE facb1, faca1, spim1, xblm1, acrae, acrael, xliapt, xliapm;
|
|
LDBLE xaly, xaly1, xaly2;
|
|
LDBLE faca, facb, spialy, facal, facbl;
|
|
LDBLE tol;
|
|
|
|
if (pr.ss_assemblage == FALSE)
|
|
print = FALSE;
|
|
tol = 1e-6;
|
|
r = R_KJ_DEG_MOL;
|
|
rt = r * t;
|
|
a0 = ss_ptr->Get_ag0() / rt;
|
|
a1 = ss_ptr->Get_ag1() / rt;
|
|
ss_ptr->Set_a0(a0);
|
|
ss_ptr->Set_a1(a1);
|
|
ag0 = a0 * rt;
|
|
ag1 = a1 * rt;
|
|
cxxSScomp *comp0_ptr = &(ss_ptr->Get_ss_comps()[0]);
|
|
cxxSScomp *comp1_ptr = &(ss_ptr->Get_ss_comps()[1]);
|
|
class phase *phase0_ptr = phase_bsearch(comp0_ptr->Get_name().c_str(), &k, FALSE);
|
|
class phase *phase1_ptr = phase_bsearch(comp1_ptr->Get_name().c_str(), &k, FALSE);
|
|
kc = exp(k_calc(phase0_ptr->rxn.logk, t, REF_PRES_PASCAL) * LOG_10);
|
|
kb = exp(k_calc(phase1_ptr->rxn.logk, t, REF_PRES_PASCAL) * LOG_10);
|
|
crit_pt = fabs(a0) + fabs(a1);
|
|
/*
|
|
* Default, no miscibility or spinodal gaps
|
|
*/
|
|
ss_ptr->Set_miscibility(false);
|
|
ss_ptr->Set_spinodal(false);
|
|
xsm1 = 0.5;
|
|
xsm2 = 0.5;
|
|
xb1 = 0.5;
|
|
xb2 = 0.5;
|
|
xc1 = 0;
|
|
xc2 = 0;
|
|
|
|
if (crit_pt >= tol)
|
|
{
|
|
/*
|
|
* Miscibility gap information
|
|
*/
|
|
if (fabs(a1) < tol)
|
|
{
|
|
xc = 0.5;
|
|
tc = ag0 / (2 * r);
|
|
}
|
|
else
|
|
{
|
|
xc = 0.5 + (pow((ag0 * ag0 + 27 * ag1 * ag1), (LDBLE) 0.5) -
|
|
ag0) / (18 * ag1);
|
|
tc = (12 * ag1 * xc - 6 * ag1 + 2 * ag0) * (xc - xc * xc) / r;
|
|
}
|
|
if (print == TRUE)
|
|
{
|
|
error_string = sformatf( "Description of Solid Solution %s",
|
|
ss_ptr->Get_name().c_str());
|
|
dup_print(error_string, TRUE);
|
|
}
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf(
|
|
"\t Temperature: %g kelvin\n",
|
|
(double) t));
|
|
output_msg(sformatf(
|
|
"\t A0 (dimensionless): %g\n",
|
|
(double) a0));
|
|
output_msg(sformatf(
|
|
"\t A1 (dimensionless): %g\n",
|
|
(double) a1));
|
|
output_msg(sformatf(
|
|
"\t A0 (kJ/mol): %g\n",
|
|
(double) ag0));
|
|
output_msg(sformatf(
|
|
"\t A1 (kJ/mol): %g\n\n",
|
|
(double) ag1));
|
|
}
|
|
if (xc < 0 || xc > 1)
|
|
{
|
|
if (print == TRUE)
|
|
output_msg(sformatf(
|
|
"No miscibility gap above 0 degrees kelvin.\n"));
|
|
}
|
|
else
|
|
{
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf(
|
|
"\t Critical mole-fraction of component 2: %g\n",
|
|
(double) xc));
|
|
output_msg(sformatf(
|
|
"\t Critical temperature: %g kelvin\n",
|
|
(double) tc));
|
|
output_msg(sformatf(
|
|
"\n(The critical temperature calculation assumes that the Guggenheim model\ndefined at %g kelvin is valid at the critical temperature.)\n\n\n",
|
|
(double) t));
|
|
}
|
|
}
|
|
/*
|
|
* Calculate miscibility and spinodal gaps
|
|
*/
|
|
if (tc >= t)
|
|
{
|
|
|
|
/* search for sign changes */
|
|
x0 = 0;
|
|
x1 = 1;
|
|
if (scan(f_spinodal, &x0, &x1) == TRUE)
|
|
{
|
|
|
|
/* find first spinodal pt */
|
|
xsm1 = halve(f_spinodal, x0, x1, tol);
|
|
xsm1 = halve(f_spinodal, x0, x1, tol);
|
|
ss_ptr->Set_spinodal(true);
|
|
|
|
/* find second spinodal pt */
|
|
x0 = x1;
|
|
x1 = 1;
|
|
if (scan(f_spinodal, &x0, &x1) == TRUE)
|
|
{
|
|
xsm2 = halve(f_spinodal, x0, x1, tol);
|
|
}
|
|
else
|
|
{
|
|
error_msg("Failed to find second spinodal point.", STOP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Now find Miscibility gap
|
|
*/
|
|
if (ss_ptr->Get_spinodal())
|
|
{
|
|
if (print == TRUE)
|
|
output_msg(sformatf(
|
|
"\t Spinodal-gap mole fractions, component 2: %g\t%g\n",
|
|
(double) xsm1, (double) xsm2));
|
|
converged = FALSE;
|
|
if (converged == FALSE)
|
|
{
|
|
for (i = 1; i < 3; i++)
|
|
{
|
|
divisions = (int) pow(10., i);
|
|
for (j = 0; j < divisions; j++)
|
|
{
|
|
for (k = divisions; k > 0; k--)
|
|
{
|
|
xc1 = (LDBLE) j / divisions + 0.001;
|
|
xc2 = (LDBLE) k / divisions;
|
|
converged = solve_misc(&xc1, &xc2, tol);
|
|
if (converged == TRUE)
|
|
break;
|
|
}
|
|
if (converged == TRUE)
|
|
break;
|
|
}
|
|
if (converged == TRUE)
|
|
break;
|
|
}
|
|
}
|
|
if (converged == FALSE)
|
|
{
|
|
error_msg("Failed to find miscibility gap.", STOP);
|
|
}
|
|
ss_ptr->Set_miscibility(true);
|
|
if (xc1 < xc2)
|
|
{
|
|
xb1 = 1 - xc2;
|
|
xb2 = 1 - xc1;
|
|
xc1 = 1 - xb1;
|
|
xc2 = 1 - xb2;
|
|
}
|
|
else
|
|
{
|
|
xb1 = 1 - xc1;
|
|
xb2 = 1 - xc2;
|
|
}
|
|
facb1 = kb * xb1 * exp(xc1 * xc1 * (a0 + a1 * (4 * xb1 - 1)));
|
|
faca1 = kc * xc1 * exp(xb1 * xb1 * (a0 - a1 * (3 - 4 * xb1)));
|
|
spim1 = log10(faca1 + facb1);
|
|
xblm1 = 1. / (1. + faca1 / facb1);
|
|
acrae = facb1 / faca1;
|
|
acrael = log10(acrae);
|
|
xliapt = log10(facb1);
|
|
xliapm = log10(faca1);
|
|
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf(
|
|
"\t Miscibility-gap fractions, component 2: %g\t%g\n",
|
|
(double) xb1, (double) xb2));
|
|
output_msg(sformatf(
|
|
"\n\t\t\tEutectic Point Calculations\n\n"));
|
|
output_msg(sformatf(
|
|
"\t Aqueous activity ratio (comp2/comp1): %g\n",
|
|
(double) acrae));
|
|
output_msg(sformatf(
|
|
"\t Log aqueous activity ratio (comp2/comp1): %g\n",
|
|
(double) acrael));
|
|
output_msg(sformatf(
|
|
"\t Aqueous activity fraction of component 2: %g\n",
|
|
(double) xblm1));
|
|
output_msg(sformatf(
|
|
"\t Log IAP (component 2): %g\n",
|
|
(double) xliapt));
|
|
output_msg(sformatf(
|
|
"\t Log IAP (component 1): %g\n",
|
|
(double) xliapm));
|
|
output_msg(sformatf(
|
|
"\t Log Sum Pi: %g\n",
|
|
(double) spim1));
|
|
}
|
|
ss_ptr->Set_tk(t);
|
|
ss_ptr->Set_xb1(xb1);
|
|
ss_ptr->Set_xb2(xb2);
|
|
}
|
|
/*
|
|
* Alyotropic point calculation
|
|
*/
|
|
xaly = -1.0;
|
|
l_x = a0 * a0 + 3 * a1 * a1 + 6 * a1 * log(kb / kc);
|
|
if (l_x > 0)
|
|
{
|
|
if (fabs(l_x - a0 * a0) >= tol)
|
|
{
|
|
xaly1 = (-(a0 - 3 * a1) + pow(l_x, (LDBLE) 0.5)) / (6 * a1);
|
|
xaly2 = (-(a0 - 3 * a1) - pow(l_x, (LDBLE) 0.5)) / (6 * a1);
|
|
if (xaly1 >= 0 && xaly1 <= 1)
|
|
{
|
|
xaly = xaly1;
|
|
}
|
|
if (xaly2 >= 0 && xaly2 <= 1)
|
|
{
|
|
xaly = xaly2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xaly = 0.5 + log(kb / kc) / (2 * a0);
|
|
}
|
|
if (xaly > 0 && xaly < 1)
|
|
{
|
|
faca =
|
|
kc * (1 -
|
|
xaly) * exp(xaly * xaly * (a0 - a1 * (3 - 4 * xaly)));
|
|
facb =
|
|
kb * xaly * exp((1 - xaly) * (1 - xaly) *
|
|
(a0 + a1 * (4 * xaly - 1.0)));
|
|
spialy = log10(faca + facb);
|
|
facal = log10(faca);
|
|
facbl = log10(facb);
|
|
if (xaly > xb1 && xaly < xb2)
|
|
{
|
|
if (print == TRUE)
|
|
output_msg(sformatf(
|
|
"\nLocal minimum in the solidus curve corresponding to a maximum\nin the minimum stoichiometric saturation curve.\n\n"));
|
|
}
|
|
else
|
|
{
|
|
if (print == TRUE)
|
|
output_msg(sformatf(
|
|
"\n\t\t\tAlyotropic Point\n\n"));
|
|
}
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf(
|
|
"\t Solid mole fraction of component 2: %g\n",
|
|
(double) xaly));
|
|
output_msg(sformatf(
|
|
"\t Log IAP (component 2): %g\n",
|
|
(double) facbl));
|
|
output_msg(sformatf(
|
|
"\t Log IAP (component 1): %g\n",
|
|
(double) facal));
|
|
output_msg(sformatf(
|
|
"\t Log Sum Pi: %g\n",
|
|
(double) spialy));
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
halve(LDBLE f(LDBLE x, void *), LDBLE x0, LDBLE x1, LDBLE tol)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
LDBLE l_x, y, y0, dx;
|
|
|
|
y0 = f(x0, this);
|
|
dx = (x1 - x0);
|
|
/*
|
|
* Loop for interval halving
|
|
*/
|
|
for (i = 0; i < 100; i++)
|
|
{
|
|
dx *= 0.5;
|
|
l_x = x0 + dx;
|
|
y = f(l_x, this);
|
|
if (dx < tol || y == 0)
|
|
{
|
|
break;
|
|
}
|
|
if (y0 * y >= 0)
|
|
{
|
|
x0 = l_x;
|
|
y0 = y;
|
|
}
|
|
}
|
|
return (x0 + dx);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
scan(LDBLE f(LDBLE x, void *), LDBLE * xx0, LDBLE * xx1)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j;
|
|
LDBLE fx0, fx1, divisions;
|
|
LDBLE x0, x1, diff;
|
|
|
|
x0 = *xx0;
|
|
x1 = *xx1;
|
|
diff = x1 - x0;
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
fx0 = f(x0, this);
|
|
divisions = (int) pow((LDBLE) 10, (LDBLE) j);
|
|
for (i = 1; i < divisions; i++)
|
|
{
|
|
x1 = *xx0 + diff * (LDBLE) i / divisions;
|
|
fx1 = f(x1, this);
|
|
if (fx0 * fx1 <= 0)
|
|
{
|
|
*xx0 = x0;
|
|
*xx1 = x1;
|
|
return (TRUE);
|
|
}
|
|
x0 = x1;
|
|
fx0 = fx1;
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
LDBLE Phreeqc::
|
|
f_spinodal(LDBLE x, void * cookie)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
LDBLE fx;
|
|
Phreeqc * pThis;
|
|
pThis = (Phreeqc *) cookie;
|
|
fx = -12 * pThis->a1 * x * x * x + (18 * pThis->a1 -
|
|
2 * pThis->a0) * x * x + (2 * pThis->a0 -
|
|
6 * pThis->a1) * x - 1.0;
|
|
return (fx);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
slnq(int n, LDBLE * a, LDBLE * l_delta, int ncols, int print)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, j, k, m;
|
|
/* debug
|
|
*/
|
|
int row;
|
|
|
|
LDBLE b;
|
|
/* Debug
|
|
*/
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf( "\nArray in slnq: \n\n"));
|
|
for (i = 0; i < ncols - 1; i++)
|
|
{
|
|
row = i * (n + 1);
|
|
for (j = 0; j < ncols; j++)
|
|
{
|
|
output_msg(sformatf( "%10.2e", (double) a[row + j]));
|
|
}
|
|
output_msg(sformatf( "\n"));
|
|
}
|
|
output_msg(sformatf( "\n"));
|
|
}
|
|
|
|
if (n == 0)
|
|
return (OK);
|
|
/* Trivial case */
|
|
if (n == 1)
|
|
{
|
|
if (fabs(a[0]) < ZERO_TOL)
|
|
goto slnq_error;
|
|
l_delta[0] = a[1] / a[0];
|
|
return (OK);
|
|
}
|
|
|
|
/* Reduction loop */
|
|
for (i = 0; i < n - 1; i++)
|
|
{
|
|
b = fabs(a[i * ncols + i]);
|
|
m = i;
|
|
|
|
/* Find maximum value in column */
|
|
for (j = i + 1; j < n; j++)
|
|
{
|
|
if (fabs(a[j * ncols + i]) > b)
|
|
{
|
|
b = fabs(a[j * ncols + i]);
|
|
m = j;
|
|
}
|
|
}
|
|
|
|
/* Check for singularity */
|
|
if (b < ZERO_TOL)
|
|
goto slnq_error;
|
|
|
|
/* Exchange rows if necessary */
|
|
if (m != i)
|
|
{
|
|
for (j = i; j <= n; j++)
|
|
{
|
|
b = a[i * ncols + j];
|
|
a[i * ncols + j] = a[m * ncols + j];
|
|
a[m * ncols + j] = b;
|
|
}
|
|
}
|
|
|
|
/* Make a[i][i]=1.0 */
|
|
for (j = n; j >= i; j--)
|
|
{
|
|
a[i * ncols + j] /= a[i * ncols + i];
|
|
}
|
|
|
|
/* Reduction step */
|
|
for (j = i + 1; j < n; j++)
|
|
{
|
|
if (a[j * ncols + i] == 0.0)
|
|
continue;
|
|
b = -a[j * ncols + i];
|
|
for (k = i + 1; k <= n; k++)
|
|
{
|
|
a[j * ncols + k] += b * a[i * ncols + k];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Calculation of l_delta[n] */
|
|
if (fabs(a[(n - 1) * ncols + n - 1]) > ZERO_TOL)
|
|
{
|
|
l_delta[n - 1] = a[(n - 1) * ncols + n] / a[(n - 1) * ncols + n - 1];
|
|
}
|
|
else
|
|
{
|
|
output_msg(sformatf( "Error: Divide by zero in slnq.\n"));
|
|
l_delta[n] = 0.0;
|
|
goto slnq_error;
|
|
}
|
|
|
|
/* Back substitution for other delta values */
|
|
for (i = n - 2; i >= 0; i--)
|
|
{
|
|
l_delta[i] = a[i * ncols + n];
|
|
for (j = i + 1; j < n; j++)
|
|
{
|
|
l_delta[i] -= a[i * ncols + j] * l_delta[j];
|
|
}
|
|
}
|
|
if (print == TRUE)
|
|
{
|
|
output_msg(sformatf( "\nResults from slnq: \n\n"));
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
output_msg(sformatf( "%10.2e", (double) l_delta[i]));
|
|
}
|
|
output_msg(sformatf( "\n"));
|
|
}
|
|
return (OK);
|
|
|
|
slnq_error:{
|
|
error_string = sformatf(
|
|
"Error: Singular matrix in subroutine slnq. \n");
|
|
warning_msg(error_string);
|
|
}
|
|
return (ERROR);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
solve_misc(LDBLE * xxc1, LDBLE * xxc2, LDBLE tol)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, repeat, converged, max_iter;
|
|
LDBLE x1, x2, xb1, xb2;
|
|
LDBLE xc1, xc1_2, xc1_3, xc2, xc2_2, xc2_3;
|
|
LDBLE lc1, lc2, lb1, lb2;
|
|
LDBLE a[6], d[2];
|
|
LDBLE t;
|
|
|
|
d[0] = d[1] = 0;
|
|
xc1 = *xxc1;
|
|
xc2 = *xxc2;
|
|
x1 = 0;
|
|
x2 = 0;
|
|
converged = TRUE;
|
|
max_iter = 25;
|
|
for (i = 0; i < max_iter; i++)
|
|
{
|
|
/*
|
|
output_msg(sformatf( "%d xc1: %g\txc2 %g\n", i, xc1, xc2));
|
|
*/
|
|
xb1 = 1 - xc1;
|
|
xb2 = 1 - xc2;
|
|
xc1_2 = xc1 * xc1;
|
|
xc1_3 = xc1_2 * xc1;
|
|
xc2_2 = xc2 * xc2;
|
|
xc2_3 = xc2_2 * xc2;
|
|
|
|
lc1 = exp(xb1 * xb1 * (a0 - a1 * (3 - 4 * xb1)));
|
|
lb1 = exp(xc1 * xc1 * (a0 + a1 * (4 * xb1 - 1)));
|
|
lc2 = exp(xb2 * xb2 * (a0 - a1 * (3 - 4 * xb2)));
|
|
lb2 = exp(xc2 * xc2 * (a0 + a1 * (4 * xb2 - 1)));
|
|
|
|
/* -fb */
|
|
a[2] = -(xb1 * lb1 - xb2 * lb2);
|
|
|
|
/* -fc */
|
|
a[5] = -(xc1 * lc1 - xc2 * lc2);
|
|
|
|
if (fabs(a[2]) < tol && fabs(a[5]) < tol)
|
|
break;
|
|
|
|
/* dfb/dxc1 */
|
|
t = exp(a0 * xc1_2 - 4 * a1 * xc1_3 + 3 * a1 * xc1_2);
|
|
a[0] =
|
|
(2 * a0 * xc1 + 6 * a1 * xc1 - 2 * a0 * xc1_2 + 12 * a1 * xc1_3 -
|
|
18 * a1 * xc1_2 - 1) * t;
|
|
|
|
/* dfb/dxc2 */
|
|
t = exp(a0 * xc2_2 - 4 * a1 * xc2_3 + 3 * a1 * xc2_2);
|
|
a[1] =
|
|
(2 * a0 * xc2_2 - 12 * a1 * xc2_3 - 2 * a0 * xc2 +
|
|
18 * a1 * xc2_2 - 6 * a1 * xc2 + 1) * t;
|
|
|
|
|
|
/* dfc/dxc1 */
|
|
t = exp(a0 * xc1_2 - 2 * a0 * xc1 + a0 - 4 * a1 * xc1_3 +
|
|
9 * a1 * xc1_2 - 6 * a1 * xc1 + a1);
|
|
a[3] =
|
|
(2 * a0 * xc1_2 - 2 * a0 * xc1 - 12 * a1 * xc1_3 +
|
|
18 * a1 * xc1_2 - 6 * a1 * xc1 + 1) * t;
|
|
|
|
/* dfc/dxc2 */
|
|
t = exp(a0 * xc2_2 - 2 * a0 * xc2 + a0 - 4 * a1 * xc2_3 +
|
|
9 * a1 * xc2_2 - 6 * a1 * xc2 + a1);
|
|
a[4] =
|
|
(-2 * a0 * xc2_2 + 2 * a0 * xc2 + 12 * a1 * xc2_3 -
|
|
18 * a1 * xc2_2 + 6 * a1 * xc2 - 1) * t;
|
|
|
|
|
|
/* solve for dxc1 and dxc2 */
|
|
slnq(2, a, d, 3, FALSE);
|
|
|
|
repeat = TRUE;
|
|
while (repeat == TRUE)
|
|
{
|
|
x1 = xc1 + d[0];
|
|
x2 = xc2 + d[1];
|
|
if (x1 > 1 || x1 < 0 || x2 > 1 || x2 < 0)
|
|
{
|
|
d[0] *= 0.5;
|
|
d[1] *= 0.5;
|
|
}
|
|
else
|
|
{
|
|
repeat = FALSE;
|
|
}
|
|
};
|
|
xc1 = x1;
|
|
xc2 = x2;
|
|
|
|
if (fabs(xc1 - xc2) < .01)
|
|
{
|
|
converged = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (i == max_iter)
|
|
converged = FALSE;
|
|
*xxc1 = xc1;
|
|
*xxc2 = xc2;
|
|
return (converged);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
ss_calc_a0_a1(cxxSS *ss_ptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i, done;
|
|
LDBLE r, rt;
|
|
std::vector<LDBLE> p;
|
|
LDBLE q1, q2, xbq1, xbq2, xb1, xb2, xc1, xc2;
|
|
LDBLE r1, r2, pa1, pb1, pa2, pb2, xsm1, xsm2;
|
|
LDBLE pn9, pn10, c5, c6, pl9, pl10, pj9, pj10;
|
|
LDBLE xc, tc;
|
|
LDBLE spialy, azero, phi1, phi2, test;
|
|
LDBLE dq1, dq2, denom, ratio, dr1, dr2, x21, x22, x61, x62;
|
|
LDBLE l_a0, l_a1, ag0, ag1;
|
|
LDBLE wg2, wg1, alpha2, alpha3;
|
|
LDBLE l_kc, l_kb;
|
|
LDBLE xaly, xcaly, alpha0, alpha1, fx, fx1;
|
|
LDBLE tol;
|
|
|
|
tol = 1e-6;
|
|
rt = ss_ptr->Get_tk() * R_KJ_DEG_MOL;
|
|
if (ss_ptr->Get_ss_comps().size() < 2)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Two components not defined for solid solution ",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
cxxSScomp *comp0_ptr = &(ss_ptr->Get_ss_comps()[0]);
|
|
cxxSScomp *comp1_ptr = &(ss_ptr->Get_ss_comps()[1]);
|
|
int k;
|
|
class phase *phase0_ptr = phase_bsearch(comp0_ptr->Get_name().c_str(), &k, FALSE);
|
|
class phase *phase1_ptr = phase_bsearch(comp1_ptr->Get_name().c_str(), &k, FALSE);
|
|
if (phase0_ptr == NULL || phase1_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Two components were not defined for %s solid solution",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
l_kc = exp(k_calc(phase0_ptr->rxn.logk, ss_ptr->Get_tk(), REF_PRES_PASCAL) *
|
|
LOG_10);
|
|
l_kb = exp(k_calc(phase1_ptr->rxn.logk, ss_ptr->Get_tk(), REF_PRES_PASCAL) *
|
|
LOG_10);
|
|
|
|
p = ss_ptr->Get_p();
|
|
|
|
l_a0 = 0;
|
|
l_a1 = 0;
|
|
ag0 = 0;
|
|
ag1 = 0;
|
|
dq2 = 0;
|
|
switch (ss_ptr->Get_input_case())
|
|
{
|
|
/*
|
|
* dimensionless a0 and a1
|
|
*/
|
|
case cxxSS::SS_PARM_A0_A1:
|
|
l_a0 = p[0];
|
|
l_a1 = p[1];
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
/*
|
|
* two activity coefficients
|
|
* q1, q2, xbq1, xbq2
|
|
*/
|
|
case cxxSS::SS_PARM_GAMMAS:
|
|
q1 = p[0];
|
|
q2 = p[1];
|
|
xbq1 = p[2];
|
|
xbq2 = p[3];
|
|
done = FALSE;
|
|
if (fabs(1 - xbq1) > 0 && q1 > 0)
|
|
{
|
|
dq1 = log(q1) / ((1 - xbq1) * (1 - xbq1));
|
|
if (xbq2 <= 0 || xbq2 > 1)
|
|
{
|
|
l_a0 = dq1;
|
|
l_a1 = 0;
|
|
done = TRUE;
|
|
}
|
|
}
|
|
if (done == FALSE)
|
|
{
|
|
if (fabs(xbq2) < 0 || q2 <= 0)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No solution possible for A0 and A1 calculation from two activity coefficients, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
done = TRUE;
|
|
}
|
|
}
|
|
if (done == FALSE)
|
|
{
|
|
dq2 = log(q2) / (xbq2 * xbq2);
|
|
if (xbq1 < 0. || xbq2 > 1.)
|
|
{
|
|
l_a0 = dq2;
|
|
l_a1 = 0;
|
|
done = TRUE;
|
|
}
|
|
}
|
|
if (done == FALSE)
|
|
{
|
|
denom = 4 * (xbq1 - xbq2) + 2;
|
|
if (fabs(denom) >= tol)
|
|
{
|
|
if (fabs(1 - xbq1) > 0 && q1 > 0)
|
|
{
|
|
dq1 = log(q1) / ((1 - xbq1) * (1 - xbq1));
|
|
l_a0 = (dq1 * (3 - 4 * xbq2) +
|
|
dq2 * (4 * xbq1 - 1)) / denom;
|
|
l_a1 = (dq1 - dq2) / denom;
|
|
done = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (done == FALSE)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No solution possible for A0 and A1 calculation from two activity coefficients, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
/* io = 1 */
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
/*
|
|
* two distribution coefficients
|
|
* q1, q2, xbq1, xbq2
|
|
*/
|
|
case cxxSS::SS_PARM_DIST_COEF:
|
|
q1 = p[0];
|
|
q2 = p[1];
|
|
xbq1 = p[2];
|
|
xbq2 = p[3];
|
|
ratio = l_kc / l_kb;
|
|
dr1 = log(q1 / ratio);
|
|
x21 = 2 * xbq1 - 1;
|
|
if (fabs(xbq1 - xbq2) < tol || xbq2 < 0)
|
|
{
|
|
l_a0 = dr1 / x21;
|
|
l_a1 = 0;
|
|
}
|
|
else
|
|
{
|
|
dr2 = log(q2 / ratio);
|
|
x22 = 2 * xbq2 - 1;
|
|
if (xbq1 < 0.)
|
|
{
|
|
l_a0 = dr2 / x22;
|
|
l_a1 = 0;
|
|
}
|
|
else
|
|
{
|
|
x61 = 6 * xbq1 * xbq1 - 6 * xbq1 + 1;
|
|
x62 = 6 * xbq2 * xbq2 - 6 * xbq2 + 1;
|
|
if (fabs(x22 * x61 - x21 * x62) < tol)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No solution possible for A0 and A1 calculation from two distribution coefficients, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
l_a0 = (x61 * dr2 - x62 * dr1) / (x22 * x61 - x21 * x62);
|
|
l_a1 = (x21 * dr2 - x22 * dr1) / (x21 * x62 - x22 * x61);
|
|
}
|
|
}
|
|
|
|
/* io = 1 */
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
/*
|
|
* from miscibility gap fractions
|
|
* q1, q2
|
|
*/
|
|
case cxxSS::SS_PARM_MISCIBILITY:
|
|
q1 = p[0];
|
|
q2 = p[1];
|
|
xb1 = q1;
|
|
xb2 = q2;
|
|
xc1 = 1 - xb1;
|
|
xc2 = 1 - xb2;
|
|
r1 = log(xb1 / xb2);
|
|
r2 = log(xc1 / xc2);
|
|
pa1 = xc2 * xc2 - xc1 * xc1;
|
|
pb1 =
|
|
3 * (xc2 * xc2 - xc1 * xc1) - 4 * (xc2 * xc2 * xc2 -
|
|
xc1 * xc1 * xc1);
|
|
pa2 = xb2 * xb2 - xb1 * xb1;
|
|
pb2 =
|
|
-(3 * (xb2 * xb2 - xb1 * xb1) -
|
|
4 * (xb2 * xb2 * xb2 - xb1 * xb1 * xb1));
|
|
l_a0 = (r1 - pb1 / pb2 * r2) / (pa1 - pa2 * pb1 / pb2);
|
|
l_a1 = (r1 - pa1 / pa2 * r2) / (pb1 - pb2 * pa1 / pa2);
|
|
|
|
/* io = 1 */
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
/*
|
|
* from spinodal gap fractions
|
|
* q1, q2
|
|
*/
|
|
case cxxSS::SS_PARM_SPINODAL:
|
|
q1 = p[0];
|
|
q2 = p[1];
|
|
xsm1 = q1;
|
|
xsm2 = q2;
|
|
pn9 = 1 / xsm1;
|
|
pn10 = 1 / xsm2;
|
|
c5 = 1 - xsm1;
|
|
c6 = 1 - xsm2;
|
|
pl9 = 6 * c5 - 12 * c5 * c5;
|
|
pl10 = 6 * c6 - 12 * c6 * c6;
|
|
pj9 = 2 * c5;
|
|
pj10 = 2 * c6;
|
|
l_a0 = (pn9 - pl9 / pl10 * pn10) / (pj9 - pl9 / pl10 * pj10);
|
|
l_a1 = (pn9 - pj9 / pj10 * pn10) / (pl9 - pj9 / pj10 * pl10);
|
|
|
|
/* io = 1 */
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
/*
|
|
* from critical point
|
|
* q1, q2
|
|
*/
|
|
case cxxSS::SS_PARM_CRITICAL:
|
|
xc = p[0];
|
|
tc = p[1];
|
|
r = R_KJ_DEG_MOL;
|
|
ag1 = r * tc * (2 * xc - 1) / (12 * xc * xc * (1 - xc) * (1 - xc));
|
|
ag0 = (r * tc / (xc * (1 - xc)) - (12 * xc - 6) * ag1) / 2;
|
|
|
|
/* io = 0 */
|
|
l_a0 = ag0 / rt;
|
|
l_a1 = ag1 / rt;
|
|
break;
|
|
/*
|
|
* from alyotropic point
|
|
* q1, q2
|
|
*/
|
|
case cxxSS::SS_PARM_ALYOTROPIC:
|
|
q1 = p[0];
|
|
q2 = p[1];
|
|
xaly = q1;
|
|
r = log(l_kb / l_kc);
|
|
alpha0 = 2 * xaly - 1;
|
|
alpha1 = 6 * xaly * (xaly - 1) + 1;
|
|
spialy = pow((LDBLE) 10., q2);
|
|
l_a0 = -999.;
|
|
l_a1 = -999.;
|
|
if (fabs(alpha0) < tol)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"No solution possible for A0 and A1 calculation from alyotropic point, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
else
|
|
{
|
|
azero = 1;
|
|
if (fabs(alpha0) > tol)
|
|
azero = r / alpha0;
|
|
xcaly = 1 - xaly;
|
|
/*
|
|
* Solve for a0 by Newton's method
|
|
*/
|
|
for (i = 0; i < 50; i++)
|
|
{
|
|
phi1 =
|
|
xcaly * xcaly * (azero +
|
|
(r - azero * alpha0) * (4 * xaly -
|
|
1) / alpha1);
|
|
phi2 =
|
|
xaly * xaly * (azero +
|
|
(3 - 4 * xaly) * (azero * alpha0 -
|
|
r) / alpha1);
|
|
phi1 = xaly * l_kb * exp(phi1);
|
|
phi2 = xcaly * l_kc * exp(phi2);
|
|
fx = phi1 + phi2 - spialy;
|
|
fx1 =
|
|
xcaly * xcaly * (1 -
|
|
alpha0 * (4 * xaly -
|
|
1) / alpha1) * phi1 +
|
|
xaly * xaly * (1 +
|
|
alpha0 * (3 - 4 * xaly) / alpha1) * phi2;
|
|
if (fabs(fx1) < 1e-10)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Could not find A0 and A1 calculation from alyotropic point, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
l_a0 = azero - fx / fx1;
|
|
test = fabs(l_a0 - azero) + fabs(fx);
|
|
azero = l_a0;
|
|
if (test < tol)
|
|
break;
|
|
}
|
|
if (i == 50)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Too many iterations, could not find A0 and A1 calculation from alyotropic point, %s.\n",
|
|
ss_ptr->Get_name().c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
else
|
|
{
|
|
l_a1 = (r - l_a0 * alpha0) / alpha1;
|
|
|
|
/* io = 0 */
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
}
|
|
|
|
}
|
|
break;
|
|
/*
|
|
* dimensional (kJ/mol) Guggenheim parameters
|
|
* ag0, ag1
|
|
*/
|
|
case cxxSS::SS_PARM_DIM_GUGG:
|
|
ag0 = p[0];
|
|
ag1 = p[1];
|
|
l_a0 = ag0 / rt;
|
|
l_a1 = ag1 / rt;
|
|
break;
|
|
/*
|
|
* Waldbaum-Thompson
|
|
* wg2, wg1
|
|
*/
|
|
case cxxSS::SS_PARM_WALDBAUM:
|
|
wg2 = p[0];
|
|
wg1 = p[1];
|
|
ag0 = (wg2 + wg1) / 2;
|
|
ag1 = (wg2 - wg1) / 2;
|
|
l_a0 = ag0 / rt;
|
|
l_a1 = ag1 / rt;
|
|
break;
|
|
/*
|
|
* Margules
|
|
* alpha2, alpha3
|
|
*/
|
|
case cxxSS::SS_PARM_MARGULES:
|
|
alpha2 = p[0];
|
|
alpha3 = p[1];
|
|
l_a0 = alpha2 + 3 * alpha3 / 4;
|
|
l_a1 = alpha3 / 4;
|
|
ag0 = l_a0 * rt;
|
|
ag1 = l_a1 * rt;
|
|
break;
|
|
case cxxSS::SS_PARM_NONE:
|
|
break;
|
|
}
|
|
ss_ptr->Set_ag0(ag0);
|
|
ss_ptr->Set_ag1(ag1);
|
|
ss_ptr->Set_a0(l_a0);
|
|
ss_ptr->Set_a1(l_a1);
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_master_isotope(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
class master *master_ptr;
|
|
|
|
for (i = 0; i < (int)master_isotope.size(); i++)
|
|
{
|
|
/*
|
|
* Mark master species list as minor isotope
|
|
*/
|
|
if (master_isotope[i]->minor_isotope == TRUE)
|
|
{
|
|
master_ptr = master_bsearch(master_isotope[i]->name);
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"Did not find master species for isotope, %s",
|
|
master_isotope[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
master_isotope[i]->master = NULL;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
master_isotope[i]->master = master_ptr;
|
|
}
|
|
master_ptr->minor_isotope = TRUE;
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_isotope_ratios(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
class master *master_ptr;
|
|
class master_isotope *master_isotope_ptr;
|
|
class calculate_value *calculate_value_ptr;
|
|
|
|
for (i = 0; i < (int)isotope_ratio.size(); i++)
|
|
{
|
|
/*
|
|
* Mark master species list as minor isotope
|
|
*/
|
|
if (isotope_ratio[i]->isotope_name == NULL)
|
|
{
|
|
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_RATIO, did not find ISOTOPE name for this isotope ratio %s",
|
|
isotope_ratio[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
continue;
|
|
}
|
|
master_isotope_ptr =
|
|
master_isotope_search(isotope_ratio[i]->isotope_name);
|
|
if (master_isotope_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_RATIO %s, did not find ISOTOPE definition for this isotope, %s",
|
|
isotope_ratio[i]->name, isotope_ratio[i]->isotope_name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
master_ptr = master_bsearch(isotope_ratio[i]->isotope_name);
|
|
if (master_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_RATIO %s, did not find SOLUTION_MASTER_SPECIES for isotope, %s",
|
|
isotope_ratio[i]->name, isotope_ratio[i]->isotope_name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
calculate_value_ptr = calculate_value_search(isotope_ratio[i]->name);
|
|
if (calculate_value_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_RATIOS %s, did not find corresponding CALCULATE_VALUE definition",
|
|
isotope_ratio[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_isotope_alphas(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
int i;
|
|
class calculate_value *calculate_value_ptr;
|
|
class logk *logk_ptr;
|
|
|
|
for (i = 0; i < (int)isotope_alpha.size(); i++)
|
|
{
|
|
/*
|
|
* Mark master species list as minor isotope
|
|
*/
|
|
calculate_value_ptr = calculate_value_search(isotope_alpha[i]->name);
|
|
if (calculate_value_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_ALPHAS %s, did not find corresponding CALCULATE_VALUE definition",
|
|
isotope_alpha[i]->name);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
if (isotope_alpha[i]->named_logk != NULL)
|
|
{
|
|
logk_ptr = logk_search(isotope_alpha[i]->named_logk);
|
|
if (logk_ptr == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf(
|
|
"For ISOTOPE_ALPHAS %s, did not find corresponding NAMED_EXPRESSION definition %s.",
|
|
isotope_alpha[i]->name, isotope_alpha[i]->named_logk);
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
reset_last_model(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Initialize model
|
|
*/
|
|
last_model.force_prep = true;
|
|
last_model.gas_phase.clear();
|
|
last_model.ss_assemblage.clear();
|
|
last_model.pp_assemblage.clear();
|
|
last_model.add_formula.clear();
|
|
last_model.si.clear();
|
|
last_model.dl_type = cxxSurface::NO_DL;
|
|
last_model.surface_comp.clear();
|
|
last_model.surface_charge.clear();
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
tidy_exchange(void)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* If exchanger is related to mineral, exchanger amount is
|
|
* set in proportion
|
|
*/
|
|
{
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
//for ( ; it != Rxn_exchange_map.end(); it++)
|
|
//for (size_t nn = 0; nn < Rxn_new_exchange.size(); nn++)
|
|
//{
|
|
// std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(Rxn_new_exchange[nn]);
|
|
for (std::set<int>::const_iterator nit = Rxn_new_exchange.begin(); nit != Rxn_new_exchange.end(); nit++)
|
|
{
|
|
std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.find(*nit);
|
|
if (it == Rxn_exchange_map.end())
|
|
{
|
|
assert(false);
|
|
}
|
|
//std::map<int, cxxExchange>::iterator it = Rxn_exchange_map.begin();
|
|
cxxExchange * exchange_ptr = &(it->second);
|
|
//if (!exchange_ptr->Get_new_def())
|
|
// continue;
|
|
//if (exchange_ptr->Get_n_user() < 0)
|
|
// continue;
|
|
// check elements
|
|
for (size_t j = 0; j < exchange_ptr->Get_exchange_comps().size(); j++)
|
|
{
|
|
cxxExchComp & comp_ref = exchange_ptr->Get_exchange_comps()[j];
|
|
if (comp_ref.Get_phase_name().size() > 0)
|
|
continue;
|
|
if (comp_ref.Get_rate_name().size() > 0)
|
|
continue;
|
|
|
|
/* Check elements */
|
|
cxxNameDouble nd = comp_ref.Get_totals();
|
|
cxxNameDouble::iterator kit = nd.begin();
|
|
for (; kit != nd.end(); kit++)
|
|
{
|
|
/* Find master species */
|
|
class element *elt_ptr = element_store(kit->first.c_str());
|
|
if (elt_ptr == NULL || elt_ptr->master == NULL)
|
|
{
|
|
input_error++;
|
|
error_string = sformatf( "Master species not in database "
|
|
"for %s, skipping element.",
|
|
kit->first.c_str());
|
|
error_msg(error_string, CONTINUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|