/* ---------------------------------------------------------------------- */ static int reaction_calc (struct irrev *irrev_ptr) /* ---------------------------------------------------------------------- */ { /* * Go through irreversible reaction initially to * determine a list of elements and amounts in * the reaction. */ int i, j, return_value; LDBLE coef; char token[MAX_LENGTH]; char *ptr; struct phase *phase_ptr; /* * Go through list and generate list of elements and * coefficient of elements in reaction */ return_value = OK; count_elts = 0; paren_count = 0; for (i = 0; i < irrev_ptr->count_list; i++) { coef = irrev_ptr->list[i].coef; strcpy (token, irrev_ptr->list[i].name); phase_ptr = phase_bsearch (token, &j, FALSE); /* * Reactant is a pure phase, copy formula into token */ if (phase_ptr != NULL) { add_elt_list (phase_ptr->next_elt, coef); } else { ptr = &(token[0]); get_elts_in_species (&ptr, coef); } } /* * Check that all elements are in database */ for (i = 0; i < count_elts; i++) { if (elt_list[i].elt->master == NULL) { sprintf (error_string, "Element or phase not defined in database, %s.", elt_list[i].elt->name); error_msg (error_string, CONTINUE); input_error++; return_value = ERROR; } } irrev_ptr->elts = elt_list_save (); return (return_value); }
/* ---------------------------------------------------------------------- */ int gas_phase_check (struct gas_phase *gas_phase_ptr) /* ---------------------------------------------------------------------- */ { /* * Check for missing elements */ int i, j; struct gas_comp *gas_comp_ptr; struct master *master_ptr; if (gas_phase_ptr == NULL) return (OK); gas_comp_ptr = gas_phase_ptr->comps; /* * Check that all elements are in solution for phases with zero mass */ for (i = 0; i < gas_phase_ptr->count_comps; i++) { count_elts = 0; paren_count = 0; if (gas_comp_ptr[i].moles <= 0.0) { add_elt_list (gas_comp_ptr[i].phase->next_elt, 1.0); for (j = 0; j < count_elts; j++) { master_ptr = elt_list[j].elt->primary; if (master_ptr->s == s_hplus) { continue; } else if (master_ptr->s == s_h2o) { continue; } else if (master_ptr->total > MIN_TOTAL) { continue; } else { if (state != ADVECTION && state != TRANSPORT && state != PHAST) { sprintf (error_string, "Element %s is contained in gas %s (which has 0.0 mass),\nbut is not in solution or other phases.", elt_list[j].elt->name, gas_comp_ptr[i].phase->name); warning_msg (error_string); } } } } } return (OK); }
/* ---------------------------------------------------------------------- */ int add_gas_phase (struct gas_phase *gas_phase_ptr) /* ---------------------------------------------------------------------- */ { /* * Accumulate gas data in master->totals and _x variables. */ int i; struct gas_comp *gas_comp_ptr; struct master *master_ptr; if (gas_phase_ptr == NULL) return (OK); gas_comp_ptr = gas_phase_ptr->comps; /* * calculate reaction */ count_elts = 0; paren_count = 0; for (i = 0; i < gas_phase_ptr->count_comps; i++) { add_elt_list (gas_comp_ptr[i].phase->next_elt, gas_comp_ptr[i].moles); } /* * Sort elements in reaction and combine */ if (count_elts > 0) { qsort (elt_list, (size_t) count_elts, (size_t) sizeof (struct elt_list), elt_list_compare); elt_list_combine (); } /* * Add gas elements to totals */ for (i = 0; i < count_elts; i++) { master_ptr = elt_list[i].elt->primary; if (master_ptr->s == s_hplus) { total_h_x += elt_list[i].coef; } else if (master_ptr->s == s_h2o) { total_o_x += elt_list[i].coef; } else { master_ptr->total += elt_list[i].coef; } } return (OK); }
/* ---------------------------------------------------------------------- */ int add_pp_assemblage (struct pp_assemblage *pp_assemblage_ptr) /* ---------------------------------------------------------------------- */ { /* * Add a small amount of each phase if necessary to insure * all elements exist in solution. */ int i, j; LDBLE amount_to_add, total; char token[MAX_LENGTH]; char *ptr; struct pure_phase *pure_phase_ptr; struct master *master_ptr; if (check_pp_assemblage (pp_assemblage_ptr) == OK) return (OK); /* * Go through list and generate list of elements and * coefficient of elements in reaction */ count_elts = 0; paren_count = 0; /* * Check that all elements are in solution for phases with greater than zero mass */ pure_phase_ptr = pp_assemblage_ptr->pure_phases; for (j = 0; j < pp_assemblage_ptr->count_comps; j++) { count_elts = 0; paren_count = 0; amount_to_add = 0.0; pure_phase_ptr[j].delta = 0.0; if (pure_phase_ptr[j].add_formula != NULL) { strcpy (token, pure_phase_ptr[j].add_formula); ptr = &(token[0]); get_elts_in_species (&ptr, 1.0); } else { strcpy (token, pure_phase_ptr[j].phase->formula); add_elt_list (pure_phase_ptr[j].phase->next_elt, 1.0); } if (pure_phase_ptr[j].moles > 0.0) { for (i = 0; i < count_elts; i++) { master_ptr = elt_list[i].elt->primary; if (master_ptr->s == s_hplus) { continue; } else if (master_ptr->s == s_h2o) { continue; } else if (master_ptr->total > MIN_TOTAL) { continue; } else { total = (-master_ptr->total + 1e-10) / elt_list[i].coef; if (amount_to_add < total) { amount_to_add = total; } } } if (pure_phase_ptr[j].moles < amount_to_add) { amount_to_add = pure_phase_ptr[j].moles; } } if (amount_to_add > 0.0) { pure_phase_ptr[j].moles -= amount_to_add; pure_phase_ptr[j].delta = amount_to_add; /* * Add reaction to totals */ for (i = 0; i < count_elts; i++) { master_ptr = elt_list[i].elt->primary; if (master_ptr->s == s_hplus) { total_h_x += elt_list[i].coef * amount_to_add; } else if (master_ptr->s == s_h2o) { total_o_x += elt_list[i].coef * amount_to_add; } else { master_ptr->total += elt_list[i].coef * amount_to_add; } } } } return (OK); }
/* ---------------------------------------------------------------------- */ int s_s_assemblage_check (struct s_s_assemblage *s_s_assemblage_ptr) /* ---------------------------------------------------------------------- */ { /* * Check for missing elements */ int i, j, k, l; struct master *master_ptr; if (s_s_assemblage_ptr == NULL) return (OK); /* * Check that all elements are in solution for phases with zero mass */ for (i = 0; i < s_s_assemblage_ptr->count_s_s; i++) { for (j = 0; j < s_s_assemblage_ptr->s_s[i].count_comps; j++) { count_elts = 0; paren_count = 0; if (s_s_assemblage_ptr->s_s[i].comps[j].moles <= 0.0) { add_elt_list (s_s_assemblage_ptr->s_s[i].comps[j].phase->next_elt, 1.0); for (l = 0; l < count_elts; l++) { master_ptr = elt_list[l].elt->primary; if (master_ptr->s == s_hplus) { continue; } else if (master_ptr->s == s_h2o) { continue; } else if (master_ptr->total > MIN_TOTAL_SS) { continue; } else { if (state != ADVECTION && state != TRANSPORT && state != PHAST) { sprintf (error_string, "Element %s is contained in solid solution %s (which has 0.0 mass),\nbut is not in solution or other phases.", elt_list[l].elt->name, s_s_assemblage_ptr->s_s[i].comps[j].phase->name); warning_msg (error_string); } } /* * Make la's of all master species for the element small, * so SI will be small * and no mass transfer will be calculated */ for (k = 0; k < count_master; k++) { if (master[k]->elt->primary == master_ptr) { master[k]->s->la = -9999.999; } } } } } } return (OK); }
/* ---------------------------------------------------------------------- */ int pp_assemblage_check (struct pp_assemblage *pp_assemblage_ptr) /* ---------------------------------------------------------------------- */ { /* * Check for missing elements */ int i, j, k; char token[MAX_LENGTH]; char *ptr; struct pure_phase *pure_phase_ptr; struct master *master_ptr; if (check_pp_assemblage (pp_assemblage_ptr) == OK) return (OK); /* * Check that all elements are in solution for phases with zero mass */ pure_phase_ptr = pp_assemblage_ptr->pure_phases; for (j = 0; j < pp_assemblage_ptr->count_comps; j++) { count_elts = 0; paren_count = 0; if (pure_phase_ptr[j].moles <= 0.0) { pure_phase_ptr[j].delta = 0.0; if (pure_phase_ptr[j].add_formula != NULL) { strcpy (token, pure_phase_ptr[j].add_formula); ptr = &(token[0]); get_elts_in_species (&ptr, 1.0); } else { strcpy (token, pure_phase_ptr[j].phase->formula); add_elt_list (pure_phase_ptr[j].phase->next_elt, 1.0); } for (i = 0; i < count_elts; i++) { master_ptr = elt_list[i].elt->primary; if (master_ptr->s == s_hplus) { continue; } else if (master_ptr->s == s_h2o) { continue; } else if (master_ptr->total > MIN_TOTAL) { continue; } else { if (state != ADVECTION && state != TRANSPORT && state != PHAST) { sprintf (error_string, "Element %s is contained in %s (which has 0.0 mass)," "\t\nbut is not in solution or other phases.", elt_list[i].elt->name, pure_phase_ptr[j].phase->name); warning_msg (error_string); } /* * Make la's of all master species for the element small, so SI will be small * and no mass transfer will be calculated */ for (k = 0; k < count_master; k++) { if (master[k]->elt->primary == master_ptr) { master[k]->s->la = -9999.999; } } } } } } return (OK); }
/* ---------------------------------------------------------------------- */ int sum_diffuse_layer (struct surface_charge *surface_charge_ptr1) /* ---------------------------------------------------------------------- */ { int i, j, count_g; LDBLE mass_water_surface; LDBLE molality, moles_excess, moles_surface; if (use.surface_ptr == NULL) return (OK); /* * Find position of component in list of components */ i = 0; for (j = 0; j < use.surface_ptr->count_charge; j++) { if (&(use.surface_ptr->charge[j]) == surface_charge_ptr1) { i = j; break; } } if (j >= use.surface_ptr->count_charge) { sprintf (error_string, "In sum_diffuse_layer, component not found, %s.", surface_charge_ptr1->name); error_msg (error_string, STOP); } /* * Loop through all surface components, calculate each H2O surface (diffuse layer), * H2O aq, and H2O bulk (diffuse layers plus aqueous). */ count_elts = 0; paren_count = 0; mass_water_surface = surface_charge_ptr1->mass_water; for (j = 0; j < count_s_x; j++) { if (s_x[j]->type > HPLUS) continue; molality = under (s_x[j]->lm); count_g = s_x[j]->diff_layer[i].count_g; #ifdef SKIP moles_excess = mass_water_bulk_x * /* s_x[j]->diff_layer[i].charge->g[count_g].g * molality; */ surface_charge_ptr1->g[count_g].g * molality; #endif moles_excess = mass_water_aq_x * molality * surface_charge_ptr1->g[count_g].g; moles_surface = mass_water_surface * molality + moles_excess; /* * Accumulate elements in diffuse layer */ add_elt_list (s_x[j]->next_elt, moles_surface); } add_elt_list (s_h2o->next_elt, mass_water_surface / gfw_water); if (count_elts > 0) { qsort (elt_list, (size_t) count_elts, (size_t) sizeof (struct elt_list), elt_list_compare); elt_list_combine (); } return (OK); }
/* ---------------------------------------------------------------------- */ int Phreeqc:: build_fixed_volume_gas(void) /* ---------------------------------------------------------------------- */ { /* * Put coefficients into lists to sum iaps to test for equilibrium * Put coefficients into lists to build jacobian for * sum of partial pressures equation and * mass balance equations for elements contained in gases */ int row, col; struct master *master_ptr; struct rxn_token *rxn_ptr; struct unknown *unknown_ptr; LDBLE coef, coef_elt; if (gas_unknown == NULL) return (OK); cxxGasPhase *gas_phase_ptr = use.Get_gas_phase_ptr(); for (size_t i = 0; i < gas_phase_ptr->Get_gas_comps().size(); i++) { const cxxGasComp *comp_ptr = &(gas_phase_ptr->Get_gas_comps()[i]); int j; struct phase *phase_ptr = phase_bsearch(comp_ptr->Get_phase_name().c_str(), &j, FALSE); /* * Determine elements in gas component */ count_elts = 0; paren_count = 0; if (phase_ptr->rxn_x == NULL) continue; add_elt_list(phase_ptr->next_elt, 1.0); #define COMBINE #ifdef COMBINE change_hydrogen_in_elt_list(0); #endif /* * Build mass balance sums for each element in gas */ if (debug_prep == TRUE) { output_msg(sformatf( "\n\tMass balance summations %s.\n\n", phase_ptr->name)); } /* All elements in gas */ for (j = 0; j < count_elts; j++) { unknown_ptr = NULL; if (strcmp(elt_list[j].elt->name, "H") == 0) { unknown_ptr = mass_hydrogen_unknown; } else if (strcmp(elt_list[j].elt->name, "O") == 0) { unknown_ptr = mass_oxygen_unknown; } else { if (elt_list[j].elt->primary->in == TRUE) { unknown_ptr = elt_list[j].elt->primary->unknown; } else if (elt_list[j].elt->primary->s->secondary != NULL) { unknown_ptr = elt_list[j].elt->primary->s->secondary->unknown; } } if (unknown_ptr != NULL) { coef = elt_list[j].coef; store_mb(&(gas_unknowns[i]->moles), &(unknown_ptr->f), coef); if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%-24s%10.3f\n", unknown_ptr->description, (double) coef)); } } } if (gas_phase_ptr->Get_type() == cxxGasPhase::GP_PRESSURE) { /* Total pressure of gases */ store_mb(&(phase_ptr->p_soln_x), &(gas_unknown->f), 1.0); } /* * Build jacobian sums for mass balance equations */ if (debug_prep == TRUE) { output_msg(sformatf( "\n\tJacobian summations %s.\n\n", phase_ptr->name)); } for (j = 0; j < count_elts; j++) { unknown_ptr = NULL; if (strcmp(elt_list[j].elt->name, "H") == 0) { unknown_ptr = mass_hydrogen_unknown; } else if (strcmp(elt_list[j].elt->name, "O") == 0) { unknown_ptr = mass_oxygen_unknown; } else { if (elt_list[j].elt->primary->in == TRUE) { unknown_ptr = elt_list[j].elt->primary->unknown; } else if (elt_list[j].elt->primary->s->secondary != NULL) { unknown_ptr = elt_list[j].elt->primary->s->secondary->unknown; } } if (unknown_ptr == NULL) { continue; } if (debug_prep == TRUE) { output_msg(sformatf( "\n\t%s.\n", unknown_ptr->description)); } row = unknown_ptr->number * (count_unknowns + 1); coef_elt = elt_list[j].coef; for (rxn_ptr = phase_ptr->rxn_x->token + 1; rxn_ptr->s != NULL; rxn_ptr++) { if (rxn_ptr->s->secondary != NULL && rxn_ptr->s->secondary->in == TRUE) { master_ptr = rxn_ptr->s->secondary; } else if (rxn_ptr->s->primary != NULL && rxn_ptr->s->primary->in == TRUE) { master_ptr = rxn_ptr->s->primary; } else { master_ptr = master_bsearch_primary(rxn_ptr->s->name); master_ptr->s->la = -999.0; } if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%s\n", master_ptr->s->name)); } if (master_ptr->unknown == NULL) { continue; } if (master_ptr->in == FALSE) { error_string = sformatf( "Element, %s, in phase, %s, is not in model.", master_ptr->elt->name, phase_ptr->name); error_msg(error_string, CONTINUE); input_error++; } col = master_ptr->unknown->number; coef = coef_elt * rxn_ptr->coef; store_jacob(&(gas_unknowns[i]->moles), &(array[row + col]), coef); if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%-24s%10.3f\t%d\t%d\n", master_ptr->s->name, (double) coef, row / (count_unknowns + 1), col)); } } if (gas_phase_ptr->Get_type() == cxxGasPhase::GP_PRESSURE) { /* derivative wrt total moles of gas */ store_jacob(&(phase_ptr->fraction_x), &(array[row + gas_unknown->number]), coef_elt); if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%-24s%10.3f\t%d\t%d\n", "gas moles", (double) elt_list[j].coef, row / (count_unknowns + 1), gas_unknown->number)); } } } /* * Build jacobian sums for sum of partial pressures equation */ if (gas_phase_ptr->Get_type() != cxxGasPhase::GP_PRESSURE) continue; if (debug_prep == TRUE) { output_msg(sformatf( "\n\tPartial pressure eqn %s.\n\n", phase_ptr->name)); } unknown_ptr = gas_unknown; row = unknown_ptr->number * (count_unknowns + 1); for (rxn_ptr = phase_ptr->rxn_x->token + 1; rxn_ptr->s != NULL; rxn_ptr++) { if (rxn_ptr->s != s_eminus && rxn_ptr->s->in == FALSE) { error_string = sformatf( "Element in species, %s, in phase, %s, is not in model.", rxn_ptr->s->name, phase_ptr->name); warning_msg(error_string); } else { if (rxn_ptr->s->secondary != NULL && rxn_ptr->s->secondary->in == TRUE) { master_ptr = rxn_ptr->s->secondary; } else if (rxn_ptr->s->primary != NULL && rxn_ptr->s->primary->in == TRUE) { master_ptr = rxn_ptr->s->primary; } else { master_ptr = master_bsearch_primary(rxn_ptr->s->name); if (master_ptr && master_ptr->s) { master_ptr->s->la = -999.0; } } if (master_ptr == NULL) { error_string = sformatf( "Master species for %s, in phase, %s, is not in model.", rxn_ptr->s->name, phase_ptr->name); error_msg(error_string, CONTINUE); input_error++; } else { if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%s\n", master_ptr->s->name)); } if (master_ptr->unknown == NULL) { assert(false); continue; } if (master_ptr->in == FALSE) { error_string = sformatf( "Element, %s, in phase, %s, is not in model.", master_ptr->elt->name, phase_ptr->name); warning_msg(error_string); } col = master_ptr->unknown->number; coef = rxn_ptr->coef; store_jacob(&(phase_ptr->p_soln_x), &(array[row + col]), coef); if (debug_prep == TRUE) { output_msg(sformatf( "\t\t%-24s%10.3f\t%d\t%d\n", master_ptr->s->name, (double) coef, row / (count_unknowns + 1), col)); } } } } } return (OK); }