Fixed numerical derivative (non-pitzer)

This commit is contained in:
David Parkhurst 2021-07-15 20:37:58 -06:00
parent 0dde2b010f
commit 6bd936e0d7
2 changed files with 243 additions and 3 deletions

243
model.cpp
View File

@ -5304,7 +5304,7 @@ ss_f(LDBLE xb, LDBLE l_a0, LDBLE l_a1, LDBLE l_kc, LDBLE l_kb, LDBLE xcaq,
f = xcaq * (xb / r + xc) + xbaq * (xb + r * xc) - 1;
return (f);
}
#ifdef ORIGINAL
/* ---------------------------------------------------------------------- */
int Phreeqc::
numerical_jacobian(void)
@ -5545,7 +5545,248 @@ numerical_jacobian(void)
calculating_deriv = FALSE;
return OK;
}
#endif
/* ---------------------------------------------------------------------- */
int Phreeqc::
numerical_jacobian(void)
/* ---------------------------------------------------------------------- */
{
std::vector<double> base;
LDBLE d, d1, d2;
int i, j;
cxxGasPhase* gas_phase_ptr = use.Get_gas_phase_ptr();
std::vector<class phase*> phase_ptrs;
std::vector<class phase> base_phases;
double base_mass_water_bulk_x = 0, base_moles_h2o = 0;
cxxGasPhase base_gas_phase;
if (!
(numerical_deriv ||
(use.Get_surface_ptr() != NULL && use.Get_surface_ptr()->Get_type() == cxxSurface::CD_MUSIC) ||
(gas_phase_ptr != NULL && gas_phase_ptr->Get_type() == cxxGasPhase::GP_VOLUME &&
(gas_phase_ptr->Get_pr_in() || force_numerical_fixed_volume) && numerical_fixed_volume)
))
return(OK);
calculating_deriv = TRUE;
jacobian_sums();
if (use.Get_gas_phase_ptr() != NULL)
{
//cxxGasPhase* gas_phase_ptr = use.Get_gas_phase_ptr();
base_gas_phase = *gas_phase_ptr;
base_phases.resize(gas_phase_ptr->Get_gas_comps().size());
for (size_t i = 0; i < gas_phase_ptr->Get_gas_comps().size(); i++)
{
const cxxGasComp* gas_comp_ptr = &(gas_phase_ptr->Get_gas_comps()[i]);
class phase* phase_ptr = phase_bsearch(gas_comp_ptr->Get_phase_name().c_str(), &j, FALSE);
phase_ptrs.push_back(phase_ptr);
base_phases[i] = *phase_ptr;
}
}
//gammas(mu_x);
molalities(TRUE);
mb_sums();
//mb_gases();
//mb_ss();
residuals();
/*
* Clear array, note residuals are in array[i, count_unknowns+1]
*/
//for (i = 0; i < count_unknowns; i++)
//{
// my_array[i] = 0.0;
//}
//for (i = 1; i < count_unknowns; i++)
//{
// memcpy((void*)&(my_array[(size_t)i * (count_unknowns + 1)]),
// (void*)&(my_array[0]), count_unknowns * sizeof(LDBLE));
//}
base.resize(count_unknowns);
base = residual;
d = 0.0001;
d1 = d * LOG_10;
d2 = 0;
for (i = 0; i < count_unknowns; i++)
{
switch (x[i]->type)
{
case MB:
case ALK:
case CB:
case SOLUTION_PHASE_BOUNDARY:
case EXCH:
case SURFACE:
case SURFACE_CB:
case SURFACE_CB1:
case SURFACE_CB2:
x[i]->master[0]->s->la += d;
d2 = d;// *LOG_10;
break;
case MH:
s_eminus->la += d;
d2 = d;// *LOG_10;
break;
case AH2O:
x[i]->master[0]->s->la += d;
d2 = d;// *LOG_10;
break;
case PITZER_GAMMA:
x[i]->s->lg += d;
d2 = d;
break;
case MH2O:
//mass_water_aq_x *= (1 + d);
//x[i]->master[0]->s->moles = mass_water_aq_x / gfw_water;
//d2 = log(1.0 + d);
//break;
// DL_pitz
d1 = mass_water_aq_x * d;
mass_water_aq_x += d1;
if (use.Get_surface_in() && dl_type_x == cxxSurface::DONNAN_DL)
mass_water_bulk_x += d1;
x[i]->master[0]->s->moles = mass_water_aq_x / gfw_water;
d2 = d1;
break;
case MU:
d2 = d * mu_x;
mu_x += d2;
gammas(mu_x);
break;
case PP:
for (j = 0; j < count_unknowns; j++)
{
delta[j] = 0.0;
}
d2 = -1e-8;
delta[i] = d2;
reset();
d2 = delta[i];
break;
case SS_MOLES:
if (x[i]->ss_in == FALSE)
continue;
for (j = 0; j < count_unknowns; j++)
{
delta[j] = 0.0;
}
/*d2 = -1e-8; */
d2 = d * 10 * x[i]->moles;
//d2 = -.1 * x[i]->moles;
/*
if (d2 > -1e-10) d2 = -1e-10;
calculating_deriv = FALSE;
*/
delta[i] = d2;
/*fprintf (stderr, "delta before reset %e\n", delta[i]); */
reset();
d2 = delta[i];
/*fprintf (stderr, "delta after reset %e\n", delta[i]); */
break;
case GAS_MOLES:
if (gas_in == FALSE)
continue;
d2 = (x[i]->moles > 1 ? 1 : 30);
d2 *= d * x[i]->moles;
d2 = (d2 < ineq_tol ? ineq_tol : d2);
//if (d2 < 1e-14)
// d2 = 1e-14;
x[i]->moles += d2;
break;
}
//gammas(mu_x);
molalities(TRUE);
mb_sums();
//mb_gases();
//mb_ss();
residuals();
for (j = 0; j < count_unknowns; j++)
{
my_array[(size_t)j * (count_unknowns + 1) + (size_t)i] = -(residual[j] - base[j]) / d2;
if (x[i]->type == MH2O) // DL_pitz
my_array[(size_t)j * (count_unknowns + 1) + (size_t)i] *= mass_water_aq_x;
}
switch (x[i]->type)
{
case MB:
case ALK:
case CB:
case SOLUTION_PHASE_BOUNDARY:
case EXCH:
case SURFACE:
case SURFACE_CB:
case SURFACE_CB1:
case SURFACE_CB2:
case AH2O:
x[i]->master[0]->s->la -= d2;
break;
case MH:
s_eminus->la -= d2;
if (my_array[(size_t)i * (count_unknowns + 1) + (size_t)i] == 0)
{
/*output_msg(sformatf( "Zero diagonal for MH\n")); */
my_array[(size_t)i * (count_unknowns + 1) + (size_t)i] =
under(s_h2->lm) * 2;
}
break;
case PITZER_GAMMA:
x[i]->s->lg -= d2;
break;
case MH2O:
//mass_water_aq_x /= (1 + d);
//x[i]->master[0]->s->moles = mass_water_aq_x / gfw_water;
//break;
//DL_pitz
mass_water_aq_x -= d2;
if (use.Get_surface_in() && dl_type_x == cxxSurface::DONNAN_DL)
mass_water_bulk_x -= d2;
x[i]->master[0]->s->moles = mass_water_aq_x / gfw_water;
break;
case MU:
mu_x -= d2;
gammas(mu_x);
break;
case PP:
delta[i] = -d2;
reset();
break;
case SS_MOLES:
delta[i] = -d2;
reset();
break;
case GAS_MOLES:
x[i]->moles -= d2;
break;
}
if (use.Get_gas_phase_ptr() != NULL)
{
*use.Get_gas_phase_ptr() = base_gas_phase;
for (size_t g = 0; g < base_phases.size(); g++)
{
*phase_ptrs[g] = base_phases[g];
}
}
gammas(mu_x);
molalities(TRUE);
mb_sums();
//mb_gases();
//mb_ss();
residuals();
//for (size_t i2 = 0; i2 < count_unknowns; i2++)
//{
// if (fabs(2.0 * (residual[i2] - base[i2]) / (residual[i2] + base[i2])) > 1e-6)
// {
// //std::cerr << "iter: " << iterations << ". " << std::endl;
// std::cerr << i2 << ": " << x[i2]->description << " " << residual[i2] << " " << base[i2] << std::endl;
// }
//}
}
base.clear();
calculating_deriv = FALSE;
return OK;
}
/* ---------------------------------------------------------------------- */
void Phreeqc::
set_inert_moles(void)

View File

@ -1947,10 +1947,9 @@ int Phreeqc::
jacobian_pz(void)
/* ---------------------------------------------------------------------- */
{ // calculate the derivatives numerically
std::vector<double> base, base_x, base_gas_moles;
std::vector<double> base;
std::vector<class phase*> phase_ptrs;
std::vector<class phase> base_phases;
double base_mass_water_bulk_x = 0, base_moles_h2o = 0;
cxxGasPhase base_gas_phase;
LDBLE d, d1, d2;
int i, j;