Skip to content

Commit

Permalink
testm
Browse files Browse the repository at this point in the history
  • Loading branch information
fedebenelli committed Jan 30, 2025
1 parent 3481b74 commit b48af72
Show file tree
Hide file tree
Showing 7 changed files with 625 additions and 13 deletions.
18 changes: 18 additions & 0 deletions python/docs/source/tutorial/data/CO2_C6.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
kind,T,P,x1,y1
bubble,303.15,20.24,0.2385,0.9721
bubble,303.15,30.36,0.3698,0.9768
bubble,303.15,39.55,0.5063,0.9815
bubble,303.15,50.95,0.7078,0.9842
bubble,303.15,57.83,0.843,0.9855
bubble,303.15,64.68,0.941,0.9884
bubble,303.15,67.46,0.9656,0.9909
bubble,315.15,20.84,0.2168,0.956
bubble,315.15,30.4,0.3322,0.966
bubble,315.15,40.52,0.4446,0.9748
bubble,315.15,50.66,0.5809,0.9753
bubble,315.15,60.29,0.718,0.9753
bubble,315.15,69.11,0.8457,0.9764
bubble,315.15,72.89,0.8928,0.9773
bubble,315.15,75.94,0.9252,0.9777
bubble,315.15,77.5,0.9424,0.9768
bubble,315.15,78.66,0.952,0.9756
472 changes: 472 additions & 0 deletions python/docs/source/tutorial/fitting.ipynb

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions python/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os

import pandas as pd

import pathlib

import pytest


PATH = pathlib.Path(os.path.abspath(os.path.dirname(__file__)))
DATA_PATH = PATH / "datasets"


@pytest.fixture
def data_path():
return DATA_PATH.joinpath


@pytest.fixture
def data_co2_c6_pxy(data_path):
tc = [304.1, 504.0]
pc = [73.75, 30.12]
w = [0.4, 0.299]
return pd.read_csv(data_path("co2_c6.csv")), tc, pc, w
18 changes: 18 additions & 0 deletions python/tests/datasets/co2_c6.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
kind,T,P,x1,y1
bubble,303.15,20.24,0.2385,0.9721
bubble,303.15,30.36,0.3698,0.9768
bubble,303.15,39.55,0.5063,0.9815
bubble,303.15,50.95,0.7078,0.9842
bubble,303.15,57.83,0.843,0.9855
bubble,303.15,64.68,0.941,0.9884
bubble,303.15,67.46,0.9656,0.9909
bubble,315.15,20.84,0.2168,0.956
bubble,315.15,30.4,0.3322,0.966
bubble,315.15,40.52,0.4446,0.9748
bubble,315.15,50.66,0.5809,0.9753
bubble,315.15,60.29,0.718,0.9753
bubble,315.15,69.11,0.8457,0.9764
bubble,315.15,72.89,0.8928,0.9773
bubble,315.15,75.94,0.9252,0.9777
bubble,315.15,77.5,0.9424,0.9768
bubble,315.15,78.66,0.952,0.9756
24 changes: 24 additions & 0 deletions python/tests/fitting/test_fitting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest
import yaeos
import yaeos.fitting
import yaeos.fitting.model_setters


def test_fit_co2_c6_pxy(data_co2_c6_pxy):
data, tc, pc, w = data_co2_c6_pxy

mr0 = yaeos.QMR(kij=[[0, 0], [0, 0]], lij=[[0, 0], [0, 0]])
model = yaeos.PengRobinson76(tc, pc, w, mixrule=mr0)

fit_kij = yaeos.fitting.model_setters.fit_kij_lij
args = (model, True, False)

problem = yaeos.fitting.BinaryFitter(
model_setter=fit_kij, model_setter_args=args, data=data
)

x0 = [0.0]

problem.fit(x0, bounds=None)

assert (abs(problem.solution.x[0] - 0.11) < 1e-1)
78 changes: 68 additions & 10 deletions python/yaeos/fitting/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,32 @@


class BinaryFitter:
"""Binary Fitter."""
"""BinaryFitter class.
This class is used to fit binary interaction parameters to experimental
data. The objective function is defined as the sum of the squared errors
between the experimental data and the model predictions.
Parameters
----------
model_setter : callable
A function that returns a model object. The function should take the
optimization parameters as the first argument and any other arguments
as the following arguments.
model_setter_args : tuple
A tuple with the arguments to pass to the model_setter function.
data : pandas.DataFrame
A DataFrame with the experimental data.
The DataFrame should have the following columns:
- kind: str, the kind of data point
(bubble, dew, liquid-liquid, PT, critical)
- x1: float, the mole fraction of component 1
- y1: float, the mole fraction of component 1
- T: float, the temperature in K
- P: float, the pressure in bar
verbose : bool, optional
If True, print the objective function value and the optimization
"""

def __init__(self, model_setter, model_setter_args, data, verbose=False):
self._get_model = model_setter
Expand All @@ -21,18 +46,19 @@ def __init__(self, model_setter, model_setter_args, data, verbose=False):
def objective_function(self, x_values):
"""
Objective function to minimize when fitting interaction parameters.
Parameters
----------
x_values : array-like
The interaction parameters to fit.
"""
model = self._get_model(x_values, *self._get_model_args)
data = self.data

# ==============================================================
# Calculate the critical line and remove the NaN values
# --------------------------------------------------------------
# =====================================================================
# Calculate the critical line starting from the heavy component
# ---------------------------------------------------------------------
cl = model.critical_line(z0=[0, 1], zi=[1, 0], a0=1e-2, s=1e-2)
msk = ~np.isnan(cl["T"])
cl["T"] = cl["T"][msk]
cl["P"] = cl["P"][msk]
cl["a"] = cl["a"][msk]

err = 0

Expand All @@ -41,7 +67,12 @@ def objective_function(self, x_values):
y = [row["y1"], 1 - row["y1"]]
t = row["T"]
p = row["P"]
w = row["weight"]

try:
w = row["weight"]
except KeyError:
w = 1

error_i = 0

# =================================================================
Expand Down Expand Up @@ -97,6 +128,10 @@ def objective_function(self, x_values):
error_i += distances[nearest]

err += error_i * w

# =====================================================================
# Normalize the error and save the valuation
# ---------------------------------------------------------------------
err = err / len(data)

self.evaluations["fobj"].append(err)
Expand All @@ -107,8 +142,31 @@ def objective_function(self, x_values):
return err

def fit(self, x0, bounds, method="Nelder-Mead"):
"""Fit the model to the data."""
"""Fit the model to the data.
Fit the model to the data using the objective function defined in
the objective_function method. The optimization is performed using
the scipy.optimize.minimize function.
The optimization result is stored in the `.solution` property. Which
Parameters
----------
x0 : array-like
Initial guess for the fitting parameters.
bounds : array-like
Bounds for the fitting parameters.
method : str, optional
The optimization method to use. Default is 'Nelder-Mead'.
Returns
-------
None
"""
sol = minimize(
self.objective_function, x0=x0, bounds=bounds, method=method
)
self._solution = sol

@property
def solution(self):
return self._solution
4 changes: 1 addition & 3 deletions python/yaeos/fitting/model_setters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
import numpy as np


def fit_kij_lij(x, args):
def fit_kij_lij(x, model, fit_kij, fit_lij):
"""Set the kij and/or lij parameter of the model."""
model = args[0]
fit_kij, fit_lij = args[1:]

mr = model.mixrule

Expand Down

0 comments on commit b48af72

Please sign in to comment.