Skip to content

Commit

Permalink
DemandModel: Improve save_model robustness.
Browse files Browse the repository at this point in the history
Use `convert_marginal_params` before saving instead of manually taking
care of lognormal parameters.
Extends `convert_marginal_params` to support inverse conversions (from
internal units to user-defined).
  • Loading branch information
ioannis-vm committed May 27, 2024
1 parent 3d96a4d commit 9c9c037
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 26 deletions.
29 changes: 8 additions & 21 deletions pelicun/model/demand_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,26 +691,17 @@ def save_model(self, file_prefix):
log=self._asmnt.log,
)

# the log standard deviations in the marginal parameters need to be
# scaled up before feeding to the saving method where they will be
# scaled back down and end up being saved unscaled to the target file

marginal_params = self.marginal_params.copy()

log_rows = marginal_params['Family'] == 'lognormal'
log_demands = marginal_params.loc[log_rows, :]

for label in log_demands.index:
if label in self.user_units.index:
unit_factor = self._asmnt.calc_unit_scale_factor(self.user_units[label])

marginal_params.loc[label, 'Theta_1'] *= unit_factor
# Converting the marginal parameters requires special
# treatment, so we can't rely on file_io's universal unit
# conversion functionality. We do it manually here instead.
marginal_params_user_units = self._convert_marginal_params(
self.marginal_params.copy(), self.user_units, inverse_conversion=True
)
marginal_params_user_units['Units'] = self.user_units

file_io.save_to_csv(
marginal_params,
marginal_params_user_units,
file_prefix + '_marginals.csv',
units=self.user_units,
unit_conversion_factors=self._asmnt.unit_conversion_factors,
orientation=1,
log=self._asmnt.log,
)
Expand Down Expand Up @@ -767,10 +758,6 @@ def load_model(self, data_source):
else:
self.correlation = None

# the log standard deviations in the marginal parameters need to be
# adjusted after getting the data from the loading method where they
# were scaled according to the units of the corresponding variable

# Note that a data source without marginal information is not valid
marginal_params, units = file_io.load_data(
marginal_data_source,
Expand Down
20 changes: 15 additions & 5 deletions pelicun/model/pelicun_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ def __init__(self, assessment: Assessment):
self.log = self._asmnt.log

def _convert_marginal_params(
self, marginal_params, units, arg_units=None, divide_units=True
self,
marginal_params,
units,
arg_units=None,
divide_units=True,
inverse_conversion=False,
):
"""
Converts the parameters of marginal distributions in a model to SI units.
Expand Down Expand Up @@ -110,6 +115,11 @@ def _convert_marginal_params(
should be True when the arg units represent the quantity
corresponding to the primary parameters, and False
otherwise.
inverse_conversion: bool
If True, converts from user-defined units to internal. If
False, converts from internal units to
user-defined. Defaults to False, since the method is
mostly applied on user-defined data.
Returns
-------
Expand Down Expand Up @@ -211,11 +221,13 @@ def _convert_marginal_params(
if isinstance(arg, np.ndarray):
args[a_i] = arg * arg_unit_factor

# convert the distribution parameters to SI
# convert units
if divide_units:
conversion_factor = unit_factor / arg_unit_factor
else:
conversion_factor = unit_factor
if inverse_conversion:
conversion_factor = 1.00 / conversion_factor
theta, tr_limits = uq.scale_distribution(
conversion_factor, family, theta, tr_limits
)
Expand Down Expand Up @@ -325,9 +337,7 @@ def _get_locations(self, loc_str):
if loc_str == "roof":
return np.array([stories + 1]).astype(str)

raise ValueError(
f"Cannot parse location string: " f"{loc_str}"
) from exc
raise ValueError(f"Cannot parse location string: " f"{loc_str}") from exc

def _get_directions(self, dir_str):
"""
Expand Down

0 comments on commit 9c9c037

Please sign in to comment.