mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-16 00:28:23 +01:00
2243d25 Merge commit '013c822f76e5dc2e4fc19e87c6e5777aea6151d2' c1af6f3 added newlines for CRAN 013c822 added newlines for CRAN e4bd9ba [phreeqc3] fixes -Wclass-memaccess warnings for CRAN 29f06d2 fixed alignment in Description of solution 09a2680 guarded write_banner with NO_UTF8_ENCODING 082edbb changed src/print.cpp back to windows-1252 encoding; updated check_utf.sh 8d7c1fc adding mcd_Jtot and mcd_Jconc 9f0f622 Merge branch 'master' of github.com:usgs-coupled/phreeqc3 1040066 Merge remote-tracking branch 'usgs-coupled/master' 2a94644 cleaned up to eliminate some prints 07a864d all jacobians are consistent. Looks pretty good. 56975a7 Saved surface for numerical derivatives df0d68b Runs all the test cases. Numerical derivatives work, but still some changes in residuals before and after jacobian calculations. 6bd936e Fixed numerical derivative (non-pitzer) 0dde2b0 removed comments aef51fa Finally have derivatives right, I think 20281a0 always reset gases 13ec2fc best I could do for H2S while maintaining old tests. Used INCREMENTAL reactions 8be1ba8 revised jacobian_pz with new logic. Works with fixed_pressure examples H2S, H2S_pz, H2S_pz_appt, H2S_NaCl_Na2SO4. 71cf2a9 still produces different residuals 9022ded Tony H2S. Amm.dat, phreeqc.dat, pitzer.dat, utf8, updated test cases cb1f9af Finished up C, Fortran, documentation. Need to check DOxygen 9dad447 Merge remote-tracking branch 'origin/master' into state d647eec Added StateSave, StateApply, StateDelete with documentation for C++. Need testing, Fortran, and C 48cb5e8 Including OH- in converting units. Revised calculated density for H+ and OH-. Makes a difference in several test cases. Removed timing at end of .out in test cases. Checking in all test cases and selected output. 47e1ce5 added OH in density iteration calculation, test case NaOH_density 4aefb06 allow Fe(+3), equivalent to Fe(3), in TOT and TOTMOL. Previously fixed in SELECTED_OUTPUT -total bea0ad1 unused variable, punch Fe(+3) eaf788b fixed add_constant, undefined surface null pointer, added test cases 2212f9c fixed bug in reprep when sit had surface species. Added capability of sit + edl, have not tested it 79956e3 made tally_table a vector of class tally 58b0d1f Merge commit 'd77c11ec700085f19b76af6543013e23ee0739d3' d77c11e [phreeqci] fixed header error with phast 63175ab [phreeqci] fixed header error with phast 0feb715 [phreeqci] fixed WINDOWS.H already included error on windows builds 123cc8a [phreeqci] fixed _ASSERTE error on linux builds 22c4a62 [phreeqci] struct to class changes 4cee19d Merge commit '2d8ca2d0f37d13ad67be582208a4e65edfcf702f' 2d8ca2d [phreeqci] added 'new' debugging d0c8212 [phreeqci] added 'new' debugging 9661fea tokadd_heading leak 4565c5d catching upMerge remote-tracking branch 'origin/master' into classify c22d792 fix notab leak 6d2b45a Merge remote-tracking branch 'usgs-coupled/master' 38cfe18 memory leak user_print, pitz/sit store, add uphill_NPa, remove TESTINT 24f9bf7 removed TESTING definition e2ce928 Tony agreed with change for all_cells, new test case d2a5d63 reset all_cells in all cases e3c0d61 initialize aphi c960e05 builds on vs2005; still needs to initialize class pitz_param* aphi 71dc944 cl1mp, bad initialization 2e5f255 fixed errors/warnings from ming and intel 369733e converted to classes 7961b16 release.txt, couple size_t 5d76f82 copy operator works well enough 7ce8947 updated InternalCopy for operator equal 7bd13ff new/delete theta params, pitz_param_copy 50e8903 new/delete pitz_params 87d6792 reverting changes to sit_params and theta_params. Will consider using new and delet dcb9efe sit_params ac3335e theta_params 8878232 delete rate, unused cptr 492df61 descriptions 25e0621 cell_data 051ddba stag_data 33157a2 fixed more size_t and initialized all structs f86f430 back to original set of files I think af1b761 removing CReaction and Classes files 006d1de reorganizing 287f81c elt_list vectorized 7228bd0 move struct rxn_token 28de8b5 more size_t d2e3a4e Removed cxxChemRxn ce64720 cleaned up, removed struct reaction 028e908 moving to CReaction dc2dc53 vectorized token 9fd3f2a save_values rewritten with map 8a6cef5 vectorized save_values 8685225 fixed clang errors, needed .c_str 318e267 (size_t) max and count 1547d91 finished up spread b5c7ba4 going to work on warnings 4c848b4 all inverse structures vectorized. Starting on solver workspace 980d58e finished vectorizing struct inverse. Need to do sub structs d13bb76 removed count_elts 89ab28d vector inverse elts d575ade tidy.cpp, title_x 16fd18f removed string_duplicate from prep.cpp 82a10d6 revised get_elt and get_token d7e3be4 cleaned up some string_duplicate 76366a6 fixed processing file names 157a458 description_x 51fec19 class_main c748922 added const qualifier for all the parsing 380a6ea methods set to const, variables need to follow 6d67e22 copier and dash 48e6b93 fixed a new master, advection punch_temp and print_temp, some tidying 5f21daf unknown->master now a vector. Using size instead of a null to end list. 3c432d0 user_graph commands, alk_list 2b14f80 last_model 7a6b8b6 Merge branch 'warnings_redux' into vectorize_2 885a2f7 Fix memory bug in ex13_impl, tweak Makefile. 6907bb0 base, sit arrays 90e8412 starting on pitzer bd0cad9 vector kinetics arrays 1850c32 basic commands are now std::string 78a83ed c,d in polint d82d5d6 vector llnl parameters, removed hash references 7c538b6 Revert "delete s[i]" 97bcfd7 Merge branch 'warnings_redux' into vectorize 15a8991 delete s[i] 0b19404 master new/delete b100f85 more new/delete. Fixed str_tolower for ming fd93f84 needed to new/delete species and phase structs 1986e00 alphabetize tokens ee6fa53 bool analytic cc614e6 add_logk for logk, species, phases 67447c5 Removed hashtable, all hashes have been replaced with maps. ee7d2c5 replaced hash for isotope_ratio, isotope_alpha, calculate_value with maps. Fixed some case errors with new maps. 52e0622 replase master_isotope_hash_table with master_isotope_map c01c8d6 replace logk_hash_table with logk_map. Added str_tolower(std::string) 3e69461 replaced phases_hash_table with phases_map effafe0 replace species_hash_table with species_map 8bff6d3 removed HASH code. replaced elements_hash_table with elements_map 90e9ee0 removed ineq_init. Vector advection_print, advection_punch 2f38047 size_t for subscripts 5161ea7 Merged origin/master, Alphabetized Basic toks f8e05c1 only call qsort with more than one element 1ab8641 remove _v, use std::vector only, alloc at least 1 scratch 9732a1c cannot qsort size 0 vector 67fc478 one more .data 2f0f5e1 Some replacements of .data() were incorrect ba9813a remove .data() 43765f8 need <struct xxx> 0feb20d after merging origin/master, one fix needed f136feb Merging origin/master. Merge remote-tracking branch 'origin/master' into warnings_redux 71aa5b9 bug count_sys not incremented e43550c vector inverse d4cc14e vector x 6c0edef vector rates e3cc46a vector save_values 41b9965 vector species_list 449a54f vector mb_unknowns 51514eb vector delta, sum_jacobx f0707aa vector sum_mb1, sum_mb2 7d303de vector trxn.token 83cfb29 elt_list, moved qsort to elt_list_combine e8c9027 vector elt_list 0957a52 vector theta_params b1af156 vector pitz_params e3ea010 vector sit_params b87d0cd vector my_array, residual, delta e43471a vector s_x 622d361 vector s_x 3d41ef8 vector logk e8dd208 vector sys 3c9f594 vector master de1ba62 vector s e7c78a8 vector phases f2c64fe vector elements e8af689 vector isotope_alpha ba2601a vector isotope_ratio 76da4f8 finished master_isotope 4bb1c80 vector master_isotope 97e574d vector calculate_value** 9d9fbfb cl1 variables converted to std::vector 1e0d410 using memset 54b0d4d starting on space 5a649c2 Merge pull request #2 from usgs-coupled/gasphasepressures a992537 (void)sscanf, removed SKIP, removed PHREEQ98 6a5bb8a Merge pull request #1 from usgs-coupled/mar10 d9ced82 Fixed uninitialized constructors and couple of other warnings c79d2c2 working on UTF-8 fcee4d5 Added delta_h_species, delta_h_phase, dh_a0, dh_bdot Basic functions 81e862d Tonys changes Mar 10. SIs in inverse calulations 9e8b382 Merge remote-tracking branch 'usgs-coupled/master' 053b4c6 Merge remote-tracking branch 'origin/master' 20091aa Merge branch 'log10molalities' into gasphasepressures 41e1112 Last of changes for GetGasPhasePressures and GetGasPhasePhi, openmp and mpi. MPI fortrans not tested. e1f9cb1 more checking in. Should be down to tweaks for SetGasPhaseMoles. 00ee6e3 C++ is working with OpenMP and MPI for Get/SetGasPhaseMoles. Need to add c and F90. c3a3153 Added GetSpeciesLog10Molalities. Tested OpenMP with VS. Tested MPI with MinGW. Fortran, C, and C++ seem to work. e8b11f3 added optional 6th argument to Basic function sys to change sort order from molality or moles to the name. Added synonym PAD$. Added new mytest/sys_sort. 3e4fc7e cleanup commented lines 54b992f working on tabs and no newline 2181847 Merge branch 'master' of https://github.com/usgs-coupled/phreeqc3 deeecb0 needed strexpr in ADD_HEADING to allow expressions 9b7785f [iphreeqccom] updated date 711b1d0 Merge commit '608e74f5d3c55a4d91a4e08d86f2fd6df0ce0a05' 608e74f [wphast] updated date 5128e13 [phreeqc3] updated image location fba8ae2 [phreeqc3] updated image location 43988f0 initialize punch_newline 176fb02 Moved initialization from header to constructor, special characters in As.out c9f796a added ADD_HEADING for IPhreeqc 1362f0f Added EOL_NOTAB$ and NO_NEWLINE$, updated release notes 2b4dbbd Merge commit 'cd51d8aeed46909e5f028a19089acfef43d6ede9' f2023c4 Merge branch 'gtest' into 'master' cd51d8a reset for dlls 54161f4 reset for dlls 01c99a7 Merge remote-tracking branch 'github/master' 23f3917 Merge remote-tracking branch 'scharlton2/master' f6644e6 check for null pointer. Encoding for .out file 9319c9d Merge commit '5b816fa1fd82eb94e2702b6bd9df6066fb71267b' 5b816fa added src/phreeqcpp/common/PHRQ_exports.h 07717b1 added src/phreeqcpp/common/PHRQ_exports.h d8c638f Merge remote-tracking branch 'origin/master' into gtest 87bbb6a adjusted alignment for utf-8 strings 03bda16 added write_banner to non-DOS and added UTF8 define 995de52 converted to utf-8 fc8fe3e re-added src/ZedGraph.dll fbae3e9 code change for extending porosity definition. Change to TonyLitharge2a 46257e7 added googletest and fixed some minor bugs 13ca055 added googletest and fixed some minor bugs f1dda6c Fixed problem with exchange-related when exchanger is defined as CaX2 20daad4 I guess cxxSurface::NO_EDL is correct 801812d Tony's changes to implicit Nernst-Planck calculation 6b4892c added Basic function DEBYE_LENGTH and test case zeta 921ab10 Changed tidy_exchange_min and tidy_exchange_kin to tidy only for new_def and n_user >= 0. Fixed bug if surf_charge not defined for NO_EDL. Added test MoreExchMix 2aef60a Finished up surface and exchange related for cases where related phase or kinetic reaction was modified. Proportionality should now be maintained. Added test cases. 569e1e1 Exchange related. Needed to update in case the related entity changed. ea54e02 Free str in callback in PBasic a87cd1f Merge commit '1871b026ca8487c23a025415dbc0b2eca01f9af4' 1871b02 fixed some c2011 warnings, added more info for -formula errors, fixed pressure llnl examples aa4d023 fixed some c2011 warnings, added more info for -formula errors, fixed pressure llnl examples e1465e3 Commit from David's Email 2020-05-22; Implementing llnl-type databases with higher temperature nad pressure e18e1ec Tony bug fix for TRANSPORT. Harmonic mean for boundary? Added Cub example. 44f077e Merge commit 'e68934133fc9cd45e7cccc397c55e13f7ee92e5b' e689341 [phreeqci] Testing subtree merges 4f34fd0 [phreeqci] Testing subtree merges 69c0bb3 fixed conflict on merge 55c4dba Merge commit 'b25fc5bdd48b6d3ab8d677f7d38ad3a462789500' b25fc5b fixed conflict on merge ca80be6 fixed conflict on merge 49a74a6 [phreeqc3] Testing subtree merges aec6f90 [phreeqc3] Testing subtree merges c4c224a Merge commit '84865ad5ac30a9edb86c89ced4194d127ee896fd' 0bf4138 Merge commit '4a8727cecd9fefd1587485820e913c0e666b77d9' 553875f Merge commit 'aab8bc12ea8be8aec5943e1c77a54b19d28168cb' aab8bc1 Merge commit '84865ad5ac30a9edb86c89ced4194d127ee896fd' 7bd02ff Fixed bug with more porosities than cells in TRANSPORT. Added silica sorption to databases. Revised CalPortDiff 84865ad Added .gitlab-ci.yml d398195 Added .gitlab-ci.yml 40c2787 Added .gitlab-ci.yml 3b6ce6c Added .gitlab-ci.yml daf64a1 Added .gitlab-ci.yml ae06f35 Fixed GFW bug on new elements in TRANSPORT 9cc783b added Basic functions for PHAST: velocity_x, velocity_y, velocity_z, transport_cell_no 79f768a Merge branch 'master' into 'master' bd7634a removed j = j in loop 542394c IPhreeqc: ifdef'd out references to std::cerr and std::cout 6067ce8 Merge branch 'implicit3' into 'master' 21bd20f Fixed more compile warnings. Removed andra_kin_ss from testing, results are inconsistent between Linux and Windows, presumably the ifs in RATES 97b9c58 Merge branch 'implicit3' into 'master' 45db5cf Another Linux warning, lower tol on andra_kin_ss. 443be1c Merge branch 'implicit3' into 'master' 9a29aaf Last Linux compile warnings. Added more precision to andra_kin_ss. 6dafd7d Merge branch 'implicit3' into 'master' fbde633 Fixing Linux compiler warnings, checking in new regression test files. 2207711 Merge branch 'implicit3' into 'master' 77e36a2 Tony fixed some transport, revised colloid_U. New cases added to Makefile. f07caf9 Changed back print to allow incremental_reactions to work correctly beadd07 Merge commit '5947da90657d1cb8f832152b4573dca0bbefb49e' 6a49d41 changes to make related and mixing items independent of case. surface_mix test case. 5947da9 initial Tony changes 8089c10 initial Tony changes 009aec7 Merge remote-tracking branch 'coupled/master' 4676ee4 added more P-R gas paramteters c07314c Merge commit '492a4d257f300b7a9e0b5dc7e212c8f85ecb7f6e' 492a4d2 Merge remote-tracking branch 'coupled/master' 81ca633 Merge remote-tracking branch 'coupled/master' 950fca2 CRAN: replaced deprecated std::ptr_fun with lambda function 597bcd7 CRAN: replaced deprecated std::ptr_fun with lambda function 044e0ea phreeqc_ptr bug in internal copy 5934297 Merge commit '5c53fb207238bc0e846123a7e0d71a48bd9976ab' 5c53fb2 Merge commit '1327e93127e40e7a55ec629dcc9dd91ec29e77fe' c117e18 Tony fix of index error b90ddb5 Fixed Tony's fix, added implicit_as example 03acc3f changed abs to fabs 1fef40e added implicit, max_mixf to internal copy 32939ba Merge commit '1327e93127e40e7a55ec629dcc9dd91ec29e77fe' b3bf691 fixed > > in templates for gcc c929113 Tony fix May 31 1327e93 Implicit seems to be working with Tony's latest changes 55ea163 Implicit seems to be working with Tony's latest changes c7111f7 Sort of works, still bugs and serious errors compared to explicit 600c7ee Fixed some bugs with iso.dat inverse modeling, added test case. Still does not generate [13C](4) and [13C](-4) from SOLUTION 2291700 Fixed gas_phase_mix bug, added test case 035a4e0 Tony tweak to transport.cpp bd4fc25 Merge branch 'tony20190117' into 'master' 71c994b skipping restart 1257f8c Merge branch 'issue-3' into 'master' ce33478 Fixed -Wcatch-value warnings reported by CRAN 040fd95 include restart, remove ex20_debug d57264d 2. changes to solid solution numerical method 3fd8155 changes to solid solution numerical method 2b14a94 Tony's changes 20190117 ae6e8b0 added modify methods for restart files b500c54 changed restart file to include UZ fffac6d another try for ex20_debug fa5ee50 fix problem with ex20_debug d993901 encoding, limit.h 92c81f9 Revised logic for nmix 3cc84da Merge remote-tracking branch 'coupled/master' into ss_trans 56b5bf3 create valid ranges when sscanf doesn't return 2 c43c9af tweaked ss, changed surf function per Kinniburgh b10df16 Corrected syntax of integer limit, previous commit actually changed ss convergence parameter, used to multiply by 0.99 d74c8ff Corrected syntax of integer limit 906cfd4 Check value of nmix 058375c removed check of ss when sum of components is small 2977db4 Tonys fix to diffusion bug with porosity change f904467 revised lists to be cumulative for eq, gas, kin, ss 9285985 merging coupled/master into copy 7c23b62 Fixed string_duplicate memory error 2d5551a fixed sc7 for copy and initial time 4842d9e inverse iter 100000; finished copy operator; a bit more testing to go 4eefe43 ex20_debug fix 78e39cd still debugging copy cee10e7 fixing bugs in copy operator ebab4bc fixing bugs in copy operator 5a35e02 Fixed Linux warnings, memory errors b86f793 Beginning to test copy operator 5d40e69 [IPhreeqc] added parens for clang++ -Wlogical-op-parentheses 936de38 removed register keywords and updated for misc clang warnings ec9de4c beginning of checking copy operation ebeddcd [iphreeqc] Changes for CRAN 3.4.7 9592d6e Merge branch 'dlpark-phreeqc3-TonyApr2018' into 'master' 7c0fb65 [phreeqc3] needed to check gas phase type for same model, added test case 9152ca2 Closes #1 ebc4f69 Merge branch 'dlpark-phreeqc3-TonyApr2018' into 'master' 97a0cec Fixed bug where 1W was interpreted as an isotope 2deb4ed added option -ddl to surface. Added test case df7d5de Merge branch 'gammas' into 'master' 34abb5b gammas finished, working on reactants 5314827 Tony's changes; diffuse layer with pitzer 4271ca4 Tonys corrections, added balonis test 2e390fd commit fix for Mtg git-subtree-dir: phreeqcpp git-subtree-split: 2243d25babbc524e7875b3d591bb6b91c4399a95
5577 lines
153 KiB
C++
5577 lines
153 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
|
|
*/
|
|
|
|
/* species */
|
|
if (new_model == TRUE)
|
|
{
|
|
if (s.size() > 1) qsort(&s[0], s.size(), sizeof(class species *), s_compare);
|
|
|
|
/* 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);
|
|
/* phases */
|
|
if (phases.size() > 1) qsort(&phases[0], phases.size(), sizeof(class phase *), phase_compare);
|
|
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
strcpy(token, 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 */
|
|
#ifdef NPP
|
|
if (!isnan(gas_phase_ptr->Get_gas_comps()[j].Get_p_read()))
|
|
#else
|
|
if (gas_phase_ptr->Get_gas_comps()[j].Get_p_read() != NAN)
|
|
#endif
|
|
{
|
|
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())
|
|
{
|
|
#ifdef NPP
|
|
if (!isnan(gas_phase_ptr->Get_gas_comps()[j].Get_p_read()))
|
|
#else
|
|
if (gas_phase_ptr->Get_gas_comps()[j].Get_p_read() != NAN)
|
|
#endif
|
|
{
|
|
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;
|
|
}
|
|
#ifdef NPP
|
|
if (isnan(comp_ptr->Get_moles()))
|
|
#else
|
|
if (comp_ptr->Get_moles() == NAN)
|
|
#endif
|
|
{
|
|
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);
|
|
}
|
|
//strcpy(token, "m_");
|
|
//strcat(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);
|
|
}
|
|
//strcpy(token, "la_");
|
|
//strcat(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);
|
|
}
|
|
//strcpy(token, "d_");
|
|
//strcat(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);
|
|
}
|
|
//strcpy(token, "si_");
|
|
//strcat(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);
|
|
}
|
|
//strcpy(token, "g_");
|
|
//strcat(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()));
|
|
//strcpy(token, "k_");
|
|
//strcat(token, punch.kinetics[i].name);
|
|
//fpunchf_heading(sformatf("%*s\t", l, token));
|
|
//strcpy(token, "dk_");
|
|
//strcat(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()));
|
|
//strcpy(token, "s_");
|
|
//strcat(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);
|
|
//}
|
|
//strcpy(token, "I_");
|
|
//strcat(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);
|
|
//}
|
|
//strcpy(token, "V_");
|
|
//strcat(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 (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);
|
|
#ifdef NPP
|
|
if (!isnan(master[k]->isotope_ratio_uncertainty))
|
|
#else
|
|
if (master[k]->isotope_ratio_uncertainty != NAN)
|
|
#endif
|
|
{
|
|
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 coresponding 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
|
|
*/
|
|
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);
|
|
}
|
|
|