""" Interface needed to create further objects to represent experimental data.
"""
# All folders in this directory refer back to this interface
import numpy as np
import logging
from abc import ABC, abstractmethod
logger = logging.getLogger(__name__)
[docs]
class ExpDataTemplate(ABC):
r"""
Interface needed to create further objects to represent experimental data.
Parameters
----------
data_dict : dict
Dictionary of exp data
* calculation_type (str) - Optional, default=*to be set*
* MultiprocessingObject (obj) - Optional, Initiated
:class:`~despasito.utils.parallelization.MultiprocessingJob`
* eos_obj (obj) - Equation of state object
* weights (dict) - A dictionary where each key is the header used in the exp.
data file. The value associated with a header can be a list as long as the
number of data points to multiply by the objective value associated with each
point, or a float to multiply the objective value of this data set.
* density_opts (dict) - Optional, default={}, Dictionary of options used in
calculating pressure vs. mole fraction curves.
* Allowed property keys and associated values
* kwargs for
:func:`~despasito.parameter_fitting.fit_functions.obj_function_form`
Attributes
----------
name : str
Data type, name of module, "To be set"
Eos : obj
Equation of state object
weights : dict, Optional, default: {"some_property": 1.0 ...}
Dictionary corresponding to thermo_dict, with weighting factor or vector for
each system property used in fitting
obj_opts : dict
Keywords to compute the objective function with
:func:`~despasito.parameter_fitting.fit_functions.obj_function_form`.
npoints : int
Number of sets of system conditions this object computes
thermodict : dict
Dictionary of inputs needed for thermodynamic calculations
- calculation_type (str) default=*to be set*
- density_opts (dict) default={}
"""
def __init__(self, data_dict):
# Self interaction parameters
self.name = "To be set"
if "eos_obj" in data_dict:
self.Eos = data_dict["eos_obj"]
del data_dict["eos_obj"]
else:
raise ValueError("An Eos object should have been included")
if "weights" in data_dict:
self.weights = data_dict["weights"]
del data_dict["weights"]
else:
self.weights = {}
self.obj_opts = {}
if "objective_method" in data_dict:
self.obj_opts["method"] = data_dict["objective_method"]
del data_dict["objective_method"]
fitting_opts = ["nan_number", "nan_ratio"]
for key in fitting_opts:
if key in data_dict:
self.obj_opts[key] = data_dict[key]
del data_dict[key]
logger.info("Objective function options: {}".format(self.obj_opts))
self.npoints = np.nan
# Add to thermo_dict
self.thermodict = {"calculation_type": None}
thermo_dict_keys = ["MultiprocessingObject", "density_opts", "calculation_type"]
for key in thermo_dict_keys:
if key in data_dict:
self.thermodict[key] = data_dict[key]
del data_dict[key]
[docs]
def update_parameters(self, fit_bead, param_names, param_values):
r"""
Update a single parameter value during parameter fitting process.
To refresh those parameters that are dependent on to bead_library or
cross_library, use method "parameter refresh".
Parameters
----------
fit_bead : str
Name of bead being fit
param_names : list
Parameters to be fit. See EOS documentation for supported parameter names.
Cross interaction parameter names should be composed of parameter name and
the other bead type, separated by an underscore (e.g. epsilon_CO2).
param_values : list
Value of parameter
"""
for i, param in enumerate(param_names):
bead_names = [fit_bead]
fit_parameter_names_list = param.split("_")
param = fit_parameter_names_list[0]
if len(fit_parameter_names_list) > 1:
bead_names.append(fit_parameter_names_list[1])
if len(fit_parameter_names_list) == 1:
self.Eos.update_parameter(fit_parameter_names_list[0], [fit_bead], param_values[i])
elif len(fit_parameter_names_list) == 2:
self.Eos.update_parameter(
fit_parameter_names_list[0],
[fit_bead, fit_parameter_names_list[1]],
param_values[i],
)
else:
raise ValueError(
"Parameters for only one bead are allowed to be fit. Multiple "
"underscores in a parameter name suggest more than one bead type "
"in your fit parameter name, {}".format(param)
)
if hasattr(self.Eos, "parameter_refresh"):
self.Eos.parameter_refresh()
[docs]
@abstractmethod
def objective(self):
"""Float representing objective function of from comparing predictions to
experimental data."""
pass
def __str__(self):
string = "Data Set Object\nName: {}\nCalculation_type: {}\nNumber of " "Points: {}".format(
self.name, self.thermodict["calculation_type"], self.npoints
)
return string