Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove penalization in fugacity computations and improve Gibbs energy calculation #5

Draft
wants to merge 64 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
afea63e
Separate CubicEOS python bindings in a proper file
volpatto Jan 29, 2021
bb7ed6b
Remove redundant includes in PyCubicEos.cpp
volpatto Jan 29, 2021
f64d2fb
Rename CubicEos -> CubicEOS
volpatto Jan 29, 2021
6b6af9e
Expose an interface to define BIPs values
volpatto Feb 1, 2021
5310496
Add some docs toInteractionParamsResult
volpatto Feb 1, 2021
a71d8ca
Expose function that calculate BIPs through CubicEOSParams
volpatto Feb 2, 2021
7d5fbf8
Use MatrixXd as default initialization in BinaryInteractionParams
volpatto Feb 2, 2021
4cbf627
Merge branch 'add-hydrocarbon-tests' into hydrocarbon-mixtures-tests
volpatto Feb 2, 2021
5dd15d4
Improve BIPs asserts and add docs for the tests
volpatto Feb 2, 2021
96cfee3
Add a sanity check for BIPs setup in CubicEOS
volpatto Feb 2, 2021
60f9206
Add the BIPs sanity check and improve docs
volpatto Feb 2, 2021
adff826
Improve test_bips_setup_without_derivatives
volpatto Feb 2, 2021
837d5e7
Remove leftovers in test_cubiceos.py
volpatto Feb 2, 2021
12ee1e8
Merge branch 'refactor-cubiceos-bindings' into hydrocarbon-mixtures-t…
volpatto Feb 2, 2021
b0fc3ae
Fix BIPs sanity check logic
volpatto Feb 2, 2021
45c92b4
Add test comparing results with and without BIPs setup
volpatto Feb 2, 2021
39a35ef
Fix database parses for Liquid type species
volpatto Feb 2, 2021
8215c84
Add HC equilibrium test cases with and without BIPs
volpatto Feb 2, 2021
951b4e6
Add forgotten assert test_equilibrium_CH4_CO2_pedersen
volpatto Feb 2, 2021
b464378
Merge branch 'refactor-cubiceos-bindings' into hydrocarbon-mixtures-t…
volpatto Feb 3, 2021
fba8e38
Add ex C1-CO2 from Pedersen, table 6.3
volpatto Feb 4, 2021
8466980
Update python deps to allow pandas to read xlsx
volpatto Feb 4, 2021
8b22d0d
Fix activity indicies usage
volpatto Feb 4, 2021
8e0e84e
Add phase composition comparison for pedersen 63 ex
volpatto Feb 7, 2021
96da719
Add plots improvements to the script of the cases
volpatto Feb 9, 2021
5ad0328
Remove unnecessary tracked file
volpatto Feb 9, 2021
fd4eb12
Merge branch 'master' into hydrocarbon-mixtures-tests
volpatto Feb 13, 2021
4919ff2
Merge branch 'master' into hydrocarbon-mixtures-tests
Mar 1, 2021
2f18f46
Update CubicEOS with BIPs sanitizer from master
Mar 1, 2021
b23efeb
Add a TODO for commented code in CubicEOS.cpp
Mar 1, 2021
e78f257
Replace pvtlib xlsx by a csv with data used only
Mar 1, 2021
fbace21
Remove unnecessary example scripts
Mar 1, 2021
17a1d8a
Remove unused utility function in Pedersen and Whitson examples
Mar 1, 2021
0780086
Convert Pedersen scripts to tests
Mar 2, 2021
abdca09
Move Pedersen tests to regression tests dir
Mar 2, 2021
2eb0381
Add regression check for fugacities in Pedersen test
Mar 2, 2021
3311073
Add regression files for Pedersen tests
Mar 2, 2021
ef163e2
Update Pythons dependencies
Mar 2, 2021
7f17d2d
Add Whitson ex 18 tests for equilibrium calculations
Mar 3, 2021
56bb082
Minor fix in a fixture for Pedersen case
Mar 3, 2021
2556c3d
Add fugacities/activities tests for Whitson ex 18
Mar 3, 2021
633afbd
Remove Whitson ex 18 scripts
Mar 3, 2021
df2caad
Update LV equilibrium regression for CH4-H2S system
Mar 4, 2021
e99016e
Fix small typo in PhaseIdentification.hpp
Mar 4, 2021
1fdfb9a
Small refactor in gibbsResidualEnergyComparison for phase identification
Mar 4, 2021
04fa0db
Add free function to compute species fugacity in CubicEOS.cpp
Mar 5, 2021
91b25eb
Move normalized Gibbs function to above CubicEOS Impl
Mar 5, 2021
f251727
Add a free function to select Z based on Gibbs energy
Mar 5, 2021
6e1961e
Expose and add bindings for Z through ChemicalProperties
Mar 8, 2021
1ceaf37
WIP: restore Z selection in Cubic EOS just for some tests
Mar 8, 2021
0e29074
Remove hanging "private" in CubicEOS Impl
Mar 10, 2021
4cc33af
Improve Reaktoro python install while developing
Mar 10, 2021
a08d878
Merge branch 'master' into fb-RES-166-improve-cubiceos-gibbs-energy
May 27, 2021
669c193
Put xfail mark in tests with liq phase which are failing
May 27, 2021
1f91ad0
Enable Z selection by Gibbs energy
Jul 1, 2021
d3a73fd
Add comment about phase identification switch-case
Jul 1, 2021
dcb2e8e
remove unnecessary dependencies
alexandrebbruno Jul 5, 2021
d64160e
removing xfail and update results
alexandrebbruno Jul 5, 2021
35a34a7
selecting Z based on min and max and using penalty
alexandrebbruno Jul 5, 2021
ff05efb
removing phase_identification_method to set default value
alexandrebbruno Jul 5, 2021
f5db28c
Merge branch 'fb-RES-166-improve-cubiceos-gibbs-energy' of github.com…
alexandrebbruno Jul 5, 2021
ff3c7af
remove unnecessary comment
alexandrebbruno Jul 5, 2021
c7a595b
absolute difference is bigger than a threshold instead of directly co…
alexandrebbruno Jul 5, 2021
a2a6b0b
fix indentation
alexandrebbruno Jul 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dependencies/python.devenv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
dependencies:
- numpy
- pandas
- matplotlib
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this one could also be removed?

- pip
- tabulate
- colorama
Expand Down
7 changes: 7 additions & 0 deletions Reaktoro/Core/ChemicalProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ auto ChemicalProperties::phaseSpecificVolumes() const -> ChemicalVector
return phaseAmounts()/phaseMasses() % phaseMolarVolumes();
}

auto ChemicalProperties::phaseCompressibilityFactors() const -> ChemicalVector
{
const auto& R = universalGasConstant;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am curious. Why did you use const auto& since universalGasConstant is just a const double? Maybe const auto fit better here.

const auto& v = phaseMolarVolumes();
return P * v / (R * T);
}

auto ChemicalProperties::phaseSpecificEntropies() const -> ChemicalVector
{
return phaseAmounts()/phaseMasses() % phaseMolarEntropies();
Expand Down
3 changes: 3 additions & 0 deletions Reaktoro/Core/ChemicalProperties.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ class ChemicalProperties
/// Return the specific volumes of the phases (in units of m3/kg).
auto phaseSpecificVolumes() const -> ChemicalVector;

/// Return the compressibility factor of the phases.
auto phaseCompressibilityFactors() const -> ChemicalVector;

/// Return the specific entropies of the phases (in units of J/(kg*K)).
auto phaseSpecificEntropies() const -> ChemicalVector;

Expand Down
146 changes: 138 additions & 8 deletions Reaktoro/Thermodynamics/EOS/CubicEOS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,131 @@ auto Psi(CubicEOS::Model type) -> double

} // namespace internal

auto computeSpeciesFugacity(
const ThermoScalar& P,
const ThermoScalar& T,
const ChemicalScalar& xi,
const ChemicalScalar& ai,
const double& bi,
const ChemicalScalar& aiT,
const ChemicalScalar& amix,
const ChemicalScalar& amixT,
const ChemicalScalar& bmix,
const ChemicalScalar& A,
const ChemicalScalar& B,
const ChemicalScalar& C,
const ChemicalScalar& Z,
const double epsilon,
const double sigma) -> ChemicalScalar
{
const double R = universalGasConstant;

const double almost_zero = 1e-20;

const ChemicalScalar q = amix/(bmix*R*T);
const ChemicalScalar qT = q*(amixT/amix - 1.0/T);

const ChemicalScalar beta = P*bmix/(R*T);
const ThermoScalar betai = P*bi/(R*T);

const ChemicalScalar qi = q*(1 + ai/amix - bi/bmix);
const ChemicalScalar qiT = qi*qT/q + q*(aiT - ai*amixT/amix)/amix;

const ThermoScalar Ai = (epsilon + sigma - 1.0)*betai - 1.0;
const ChemicalScalar Bi = (epsilon*sigma - epsilon - sigma)*(2*beta*betai - beta*beta) - (epsilon + sigma - q)*(betai - beta) - (epsilon + sigma - qi)*beta;
const ChemicalScalar Ci = -3*sigma*epsilon*beta*beta*betai + 2*epsilon*sigma*beta*beta*beta - (epsilon*sigma + qi)*beta*beta - 2*(epsilon*sigma + q)*(beta*betai - beta*beta);
const ChemicalScalar Zi = -(Ai*Z*Z + (Bi + B)*Z + Ci + 2*C)/(3*Z*Z + 2*A*Z + B);

// Calculate the integration factor I
ChemicalScalar I;
if(std::abs(epsilon - sigma) > almost_zero) I = log((Z + sigma*beta)/(Z + epsilon*beta))/(sigma - epsilon);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, assignments like this would be more legible if you use a ternary operator, or even curly brackets in each block.

else I = beta/(Z + epsilon*beta);

// Calculate the integration factor I for each component
ChemicalScalar Ii;
if(std::abs(epsilon - sigma) > almost_zero) Ii = I + ((Zi + sigma*betai)/(Z + sigma*beta) - (Zi + epsilon*betai)/(Z + epsilon*beta))/(sigma - epsilon);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

else Ii = I * (1 + betai/beta - (Zi + epsilon*betai)/(Z + epsilon*beta));

auto Gi_res = R*T*(Zi - (Zi - betai)/(Z - beta) - log(Z - beta) - qi*I - q*Ii + q*I);
auto ln_fi = Gi_res/(R*T) + log(xi * P);
auto fi = exp(ln_fi);
return fi;
}

auto calculateNormalizedPhaseGibbsEnergy(
const unsigned& nspecies,
const ThermoScalar& P,
const ThermoScalar& T,
const ChemicalVector& x,
const ChemicalVector& abar,
const Vector& bbar,
const ChemicalVector& abarT,
const ChemicalScalar& amix,
const ChemicalScalar& amixT,
const ChemicalScalar& bmix,
const ChemicalScalar& A,
const ChemicalScalar& B,
const ChemicalScalar& C,
const ChemicalScalar& Z,
const double epsilon,
const double sigma) -> ChemicalScalar
{
ChemicalScalar G_normalized;
for(unsigned i = 0; i < nspecies; ++i)
{
auto xi = x[i];
auto fi = computeSpeciesFugacity(P, T, xi, abar[i], bbar[i], abarT[i], amix, amixT, bmix, A, B, C, Z, epsilon, sigma);
G_normalized += xi * log(fi);
}
return G_normalized;
}

auto selectCompressibilityFactorByGibbsEnergy(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function unused?

const unsigned& nspecies,
std::vector<ChemicalScalar> Zs,
const ThermoScalar& P,
const ThermoScalar& T,
const ChemicalVector& x,
const ChemicalVector& abar,
const Vector& bbar,
const ChemicalVector& abarT,
const ChemicalScalar& amix,
const ChemicalScalar& amixT,
const ChemicalScalar& bmix,
const ChemicalScalar& A,
const ChemicalScalar& B,
const ChemicalScalar& C,
const double epsilon,
const double sigma) -> ChemicalScalar
{
ChemicalScalar Z(nspecies);
if (Zs.size() == 1)
{
Z = Zs[0];
return Z;
}

if (Zs.size() != 2) {
Exception exception;
exception.error << "selectCompressibilityByGibbsEnergy received invalid input";
exception.reason << "Zs should have size 1 or 2 in selectCompressibilityByGibbsEnergy, "
<< "but has a size of " << Zs.size();
RaiseError(exception);
}

std::vector<ChemicalScalar> normalized_Gs;
normalized_Gs.push_back(
calculateNormalizedPhaseGibbsEnergy(nspecies, P, T, x, abar, bbar, abarT, amix, amixT, bmix, A, B, C, Zs[0], epsilon, sigma)
);
normalized_Gs.push_back(
calculateNormalizedPhaseGibbsEnergy(nspecies, P, T, x, abar, bbar, abarT, amix, amixT, bmix, A, B, C, Zs[1], epsilon, sigma)
);

Z = normalized_Gs[0] < normalized_Gs[1] ? Zs[0] : Zs[1];

return Z;
}

struct CubicEOS::Impl
{
/// The number of species in the phase.
Expand Down Expand Up @@ -340,11 +465,15 @@ struct CubicEOS::Impl
const auto cubic_size = cubicEOS_roots.size();

std::vector<ChemicalScalar> Zs;
if (cubic_size == 1 || cubic_size == 2)
if (cubic_size == 1)
{
//even if cubicEOS_roots has 2 roots, assume that the smallest does not have physical meaning
Zs.push_back(ChemicalScalar(nspecies, cubicEOS_roots[0]));
}
else if (cubic_size == 2)
{
Zs.push_back(ChemicalScalar(nspecies, cubicEOS_roots[0]));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid temporary objects, use emplace_back instead of push_back

Zs.push_back(ChemicalScalar(nspecies, cubicEOS_roots[1]));
}
else
{
if (cubic_size != 3) {
Expand All @@ -357,16 +486,18 @@ struct CubicEOS::Impl
Zs.push_back(ChemicalScalar(nspecies, cubicEOS_roots[2])); // Z_min
}

// Selecting compressibility factor - Z_liq < Z_gas
ChemicalScalar Z(nspecies);

// Selecting compressibility factor - Z_liq < Z_gas
//TODO: study the possibilty to use selectCompressibilityFactorByGibbsEnergy for Z selection
if (isvapor)
Z.val = *std::max_element(cubicEOS_roots.begin(), cubicEOS_roots.end());
else
Z.val = *std::min_element(cubicEOS_roots.begin(), cubicEOS_roots.end());

auto input_phase_type = isvapor ? PhaseType::Gas : PhaseType::Liquid;
auto identified_phase_type = input_phase_type;

auto identified_phase_type = input_phase_type;
switch (phase_identification_method)
{
case PhaseIdentificationMethod::None:
Expand All @@ -390,8 +521,7 @@ struct CubicEOS::Impl
throw std::logic_error("CubicEOS received an unexpected phaseIdentificationMethod");
}

if (identified_phase_type != input_phase_type)
{
if (identified_phase_type != input_phase_type) {
// Since the phase is identified as different than the expect input phase type, it is
// deemed inappropriate. Artificially high values are configured for fugacities, so that
// this condition is "removed" by the optimizer.
Expand All @@ -403,7 +533,7 @@ struct CubicEOS::Impl
result.partial_molar_volumes.fill(0.0);
result.residual_partial_molar_gibbs_energies.fill(0.0);
result.residual_partial_molar_enthalpies.fill(0.0);
result.ln_fugacity_coefficients.fill(100.0);
result.ln_fugacity_coefficients.fill(0.0);
return result;
}

Expand Down Expand Up @@ -493,7 +623,7 @@ CubicEOS::Result::Result(unsigned nspecies)
{}

/// Sanity check free function to verify if BIPs matrices have proper dimensions. Considering that the phase has
/// n species, the BIP matricies k, kT and kTT should have (n, n) as dimensions.
/// n species, the BIP matrices k, kT and kTT should have (n, n) as dimensions.
/// @see CubicEOS::setInteractionParamsFunction
auto sanityCheckInteractionParamsFunction(const unsigned& nspecies, const CubicEOS::InteractionParamsFunction& func) -> void
{
Expand Down
3 changes: 3 additions & 0 deletions Reaktoro/Thermodynamics/EOS/CubicEOS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ class CubicEOS
/// Note that the BIPs can depend on the temperature, thus kT and kTT should be also provided.
struct InteractionParamsResult
{
/// The BIPs matrix. The size must be (n, n), where n is the number of species
alexandrebbruno marked this conversation as resolved.
Show resolved Hide resolved
MatrixXd k;

/// The derivative of each k entry w.r.t T.
MatrixXd kT;

/// The derivative of each kT entry w.r.t T.
MatrixXd kTT;
};

Expand Down
58 changes: 45 additions & 13 deletions Reaktoro/Thermodynamics/EOS/PhaseIdentification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,38 @@ auto pressureComparison(const ThermoScalar& Pressure, const ThermoScalar& Temper
RaiseError(exception);
}

auto computeGibbsResidualEnergy(
alexandrebbruno marked this conversation as resolved.
Show resolved Hide resolved
const ThermoScalar& pressure,
const ThermoScalar& temperature,
const ChemicalScalar& amix,
const ChemicalScalar& bmix,
const ChemicalScalar& A,
const ChemicalScalar& B,
const ChemicalScalar& Z,
const double epsilon,
const double sigma) -> ChemicalScalar
{
auto const almost_zero = 1e-20;
auto constexpr R = universalGasConstant;
auto const& T = temperature;

// Computing the values of residual Gibbs energy for all Zs
ChemicalScalar Gs;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but it doesn't seem necessary to have this uninitialized variable here, line 138 could be ChemicalScalar Gs = R * temperature*(Z - 1 - log(Z - beta) - q * I); or line 140 could be return R * temperature*(Z - 1 - log(Z - beta) - q * I).

const double factor = -1.0 / (3 * Z.val*Z.val + 2 * A.val*Z.val + B.val);
const ChemicalScalar beta = pressure * bmix / (R * T);
const ChemicalScalar q = amix / (bmix * R * T);

// Calculate the integration factor I
ChemicalScalar I;
if (std::abs(epsilon - sigma) > almost_zero)
I = log((Z + sigma * beta) / (Z + epsilon * beta)) / (sigma - epsilon);
else
I = beta / (Z + epsilon * beta);

Gs = R * temperature*(Z - 1 - log(Z - beta) - q * I);

return Gs;
}

auto gibbsResidualEnergyComparison(
const ThermoScalar& pressure,
Expand All @@ -127,24 +159,24 @@ auto gibbsResidualEnergyComparison(
std::vector<ChemicalScalar> Gs;
for (const auto Z : {Z_max, Z_min})
{
const double factor = -1.0 / (3 * Z.val*Z.val + 2 * A.val*Z.val + B.val);
const ChemicalScalar beta = pressure * bmix / (R * T);
const ChemicalScalar q = amix / (bmix * R * T);

// Calculate the integration factor I and its temperature derivative IT
ChemicalScalar I;
if (epsilon != sigma)
I = log((Z + sigma * beta) / (Z + epsilon * beta)) / (sigma - epsilon);
else
I = beta / (Z + epsilon * beta);

Gs.push_back(R * temperature*(Z - 1 - log(Z - beta) - q * I));
auto current_G = computeGibbsResidualEnergy(
pressure,
temperature,
amix,
bmix,
A,
B,
Z,
epsilon,
sigma
);

Gs.push_back(current_G);
}

return (Gs[0].val < Gs[1].val) ? PhaseType::Gas : PhaseType::Liquid;
}


auto identifyPhaseUsingGibbsEnergyAndEos(
const ThermoScalar& pressure,
const ThermoScalar& temperature,
Expand Down
2 changes: 1 addition & 1 deletion Reaktoro/Thermodynamics/EOS/PhaseIdentification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ auto identifyPhaseUsingIsothermalCompressibility(
/// @param temperature Phase temperature
/// @param amix attractive parameter
/// @param Zs Z-roots, as calculated by the cubic EOS. Must have size 1 or 2 here.
/// If size(Z) == 2, the values od Gibbs residual energy are compared. It is a liquid phase if
/// If size(Z) == 2, the values of Gibbs residual energy are compared. It is a liquid phase if
/// Gibbs residual energy of Z_min is the smallest and gaseous if Gibbs residual energy of Z_max
/// is the smallest.
/// If size(Z) == 1, the pressue is compared with the local P_min and local P_max of the EoS.
Expand Down
1 change: 1 addition & 0 deletions python/PyReaktoro/Core/PyChemicalProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void exportChemicalProperties(py::module& m)
.def("phaseSpecificGibbsEnergies", &ChemicalProperties::phaseSpecificGibbsEnergies)
.def("phaseSpecificEnthalpies", &ChemicalProperties::phaseSpecificEnthalpies)
.def("phaseSpecificVolumes", &ChemicalProperties::phaseSpecificVolumes)
.def("phaseCompressibilityFactors", &ChemicalProperties::phaseCompressibilityFactors)
.def("phaseSpecificEntropies", &ChemicalProperties::phaseSpecificEntropies)
.def("phaseSpecificInternalEnergies", &ChemicalProperties::phaseSpecificInternalEnergies)
.def("phaseSpecificHelmholtzEnergies", &ChemicalProperties::phaseSpecificHelmholtzEnergies)
Expand Down
4 changes: 2 additions & 2 deletions python/reaktoro/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ add_custom_target(reaktoro ALL
COMMAND ${PYTHON_EXECUTABLE} -m pip install
reaktoro --prefix=${CMAKE_BINARY_DIR}
--find-links=${CMAKE_CURRENT_BINARY_DIR}/dist
--no-index --no-deps --no-cache-dir
--no-index --no-deps --no-cache-dir --force-reinstall
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

# Set dependencies of reaktoro target
Expand Down Expand Up @@ -66,7 +66,7 @@ install(CODE
COMMAND ${PYTHON_EXECUTABLE} -m pip
install reaktoro --prefix=\${REAKTORO_PYTHON_INSTALL_PREFIX_NATIVE}
--find-links=\${REAKTORO_PYTHON_DIST_DIR_NATIVE}
--no-index --no-deps --no-cache-dir
--no-index --no-deps --no-cache-dir --force-reinstall
WORKING_DIRECTORY ${REAKTORO_PYTHON_INSTALL_PREFIX})
"
)
Loading