void GeneralVaporMixtureFluidProperties::p_T_from_v_e(Real v, Real e, std::vector<Real> x, Real & p, Real & dp_dv, Real & dp_de, std::vector<Real> & dp_dx, Real & T, Real & dT_dv, Real & dT_de, std::vector<Real> & dT_dx) const { p_T_from_v_e(v, e, x, p, T); // specific volume residual and Jacobians from primary vapor and mixture Real v_unused, dv_dp, dv_dT; std::vector<Real> dv_dx; v_from_p_T(p, T, x, v_unused, dv_dp, dv_dT, dv_dx); // specific internal energy residual and Jacobians from primary vapor and mixture Real e_unused, de_dp, de_dT; std::vector<Real> de_dx; e_from_p_T(p, T, x, e_unused, de_dp, de_dT, de_dx); // Compute derivatives using the following rules: // * Reciprocity: da/db|_c = (db/da|_c)^{-1} // * Chain rule: da/db|_c = da/dc|_b * dc/db|_a // * Triple product rule: da/db|_c * db/dc|_a * dc/da|_b = -1 dp_dv = de_dT / (dv_dp * de_dT - dv_dT * de_dp); dp_de = dv_dT / (de_dp * dv_dT - de_dT * dv_dp); dT_dv = de_dp / (dv_dT * de_dp - dv_dp * de_dT); dT_de = dv_dp / (de_dT * dv_dp - de_dp * dv_dT); // Derivatives with respect to mass fractions are more complicated, so a // finite difference approximation is used (this is expensive of course). for (unsigned int i = 0; i < _n_secondary_vapors; ++i) { Real p_perturbed, T_perturbed; std::vector<Real> x_perturbed(x); x_perturbed[i] += 1e-6; p_T_from_v_e(v, e, x_perturbed, p_perturbed, T_perturbed); dp_dx[i] = (p_perturbed - p) / 1e-6; dT_dx[i] = (T_perturbed - T) / 1e-6; } }
/// Implementation of the constraints computation. /// Add noises to the decision vector before calling the actual constraint function. void robust::compute_constraints_impl(constraint_vector &c, const decision_vector &x) const { // Temporary storage used for averaging constraint_vector tmp(c.size(), 0.0); c = tmp; // Set the seed m_drng.seed(m_seed); // Perturb decision vector and evaluate decision_vector x_perturbed(x); for(unsigned int i = 0; i < m_trials; ++i){ inject_noise_x(x_perturbed); m_original_problem->compute_constraints(tmp, x_perturbed); for(constraint_vector::size_type j = 0; j < c.size(); ++j){ c[j] = tmp[j] / (double)m_trials; } } }
/// Implementation of the objective function. /// Add noises to the decision vector before calling the actual objective function. void robust::objfun_impl(fitness_vector &f, const decision_vector &x) const { // Temporary storage used for averaging fitness_vector tmp(f.size(),0.0); f = tmp; // Set the seed m_drng.seed(m_seed); // Perturb decision vector and evaluate decision_vector x_perturbed(x); for(unsigned int i = 0; i < m_trials; ++i){ inject_noise_x(x_perturbed); m_original_problem->objfun(tmp, x_perturbed); for(fitness_vector::size_type j = 0; j < f.size(); ++j){ f[j] += tmp[j] / (double)m_trials; } } }
void IdealRealGasMixtureFluidProperties::c_from_T_v(Real T, Real v, const std::vector<Real> & x, Real & c, Real & dc_dT, Real & dc_dv, std::vector<Real> & dc_dx) const { Real T_perturbed, v_perturbed, c_perturbed; c = c_from_T_v(T, v, x); // For derived properties, we would need higher order derivatives; // therefore, numerical derivatives are used here. Real dT = 1.e-6; T_perturbed = T + dT; c_perturbed = c_from_T_v(T_perturbed, v, x); dc_dT = (c_perturbed - c) / (dT); v_perturbed = v * 1.e-6; c_perturbed = c_from_T_v(T, v_perturbed, x); dc_dv = (c_perturbed - c) / (v_perturbed - v); dc_dx.resize(_n_secondary_vapors); for (unsigned int i = 0; i < _n_secondary_vapors; i++) { Real c_perturbed; std::vector<Real> x_perturbed(x); Real dx_i = 1e-6; for (unsigned int j = 0; j < _n_secondary_vapors; j++) { if (j != i) x_perturbed[j] = x[j] * (1.0 - (x[i] + dx_i)) / (1.0 - x[i]); // recalculate new mass fractions } x_perturbed[i] += dx_i; c_perturbed = c_from_T_v(T, v, x_perturbed); dc_dx[i] = ((c_perturbed - c) / dx_i); } }