Commit 1266a21b authored by Cecilia Nievas's avatar Cecilia Nievas
Browse files

Adapted _retrieve_building_classes for variable building properties

parent 2d82e39b
Pipeline #38793 passed with stage
in 3 minutes and 17 seconds
......@@ -777,7 +777,12 @@ class ExposureModelESRM20(AggregatedExposureModel):
# Retrieve proportions and properties of building classes
building_classes_proportions_and_properties = (
self._retrieve_building_classes_of_data_units(
data_table, id_column_name_data, data_units_ids, exposure_entity_name, False
data_table,
id_column_name_data,
data_units_ids,
exposure_entity_name,
occupancy_case,
False,
)
)
......@@ -1369,11 +1374,17 @@ class ExposureModelESRM20(AggregatedExposureModel):
+ total_cost[data_unit_id]["Contents"]
)
)
if total_cost_difference > 1e-5:
if total_cost_difference / total_cost[data_unit_id]["Total"] > 1e-3:
logger.warning(
"Data Unit with ID %s of Exposure Entity '%s': The sum of structural, "
"non-structural and components' costs does not match the total cost."
% (data_unit_id, exposure_entity_name)
"non-structural and components' costs does not match the total cost. "
"Absolute difference is %s (of %s total)."
% (
data_unit_id,
exposure_entity_name,
total_cost_difference,
total_cost[data_unit_id]["Total"],
)
)
return total_buildings, total_dwellings, total_people, total_cost
......@@ -1384,10 +1395,11 @@ class ExposureModelESRM20(AggregatedExposureModel):
ids_column_name,
data_units_ids,
exposure_entity_name,
occupancy_case,
weighted_average=False,
):
"""This function retrieves from data_table the proportions of building classes in each
data unit enumerated in data_units_ids, as well as their associated total replacement
data unit enumerated in 'data_units_ids', as well as their associated total replacement
costs and total census people per building.
A building class is defined by a combination of three columns in data_table. The names
......@@ -1396,6 +1408,10 @@ class ExposureModelESRM20(AggregatedExposureModel):
self.csv_column_names["settlement_type"]
self.csv_column_names["occupancy_subtype"]
If 'weighted_average' is False but building properties are found for which different
entries for the same building class exist within the same data unit, this is logged and
'weighted_average' is set to True (further details in self._retrieve_building_classes).
Args:
data_table (Pandas DataFrame):
DataFrame with all contents of the ESRM20 CSV file for a specific
......@@ -1407,14 +1423,18 @@ class ExposureModelESRM20(AggregatedExposureModel):
data_table.
exposure_entity_name (str):
Name of the ExposureEntity to which data_units_ids belong.
occupancy_case (str):
Name of the occupancy case (e.g. "residential", "commercial", "industrial") to
which data_table corresponds.
weighted_average (bool):
If True, the total replacement costs and total census people per building are
calculated as the average of all the entries of the building class in
'data_table', weighted by the number of buildings in each entry. If False, the
function will check that values of total replacement costs and total census
people per building are the same in all entries of the building class in
'data_table'; if they are not, the maximum values are assigned and an error
message is logged. Default: False.
the data unit before assigning them to the respective building classes; if they
are not, this is logged and 'weighted_average' is set to True for that
particular data unit. Default: False.
Returns:
proportions_and_properties (dict):
......@@ -1450,19 +1470,21 @@ class ExposureModelESRM20(AggregatedExposureModel):
# Retrieve the building classes and their properties
(
proportions_and_properties[data_unit_id],
error_in_properties,
warning_in_properties,
) = self._retrieve_building_classes(
data_filtered_data_unit, exposure_entity_name, weighted_average
)
# Log errors (if found; otherwise 'error_in_properties' is empty)
for col_name in error_in_properties:
error_message = (
"Problem found when grouping building classes for Data Unit %s of %s: "
"building property '%s' is inconsistent."
% (data_unit_id, exposure_entity_name, col_name)
# Log information (if found; otherwise 'warning_in_properties' is empty)
if len(warning_in_properties) > 0:
col_names = ", ".join(warning_in_properties)
info_message = (
"Data Unit %s of %s %s: different values of building property/ies %s found"
" for different entries of the same building class when running"
" '_retrieve_building_classes'. Weighted average properties were assigned."
% (data_unit_id, occupancy_case, exposure_entity_name, col_names)
)
logger.critical(error_message)
logger.info(info_message)
return proportions_and_properties
......@@ -1473,8 +1495,11 @@ class ExposureModelESRM20(AggregatedExposureModel):
average of the values of individual entries of each building class in 'data_table'. If
'weighted_average' is False, this function checks that values of total replacement costs
and total census people per building are the same in all entries of the building class
in 'data_table'; if they are not, the maximum values are assigned and an error message
is returned.
in 'data_table' before assigning them to the respective building classes; if they are
not, a list of the names of the columns of 'data_table' for which the check failed is
output ('warning_in_properties' list), 'weighted_average' is set to True and the total
replacement costs and total census people per building are calculated as the weighted
average.
A building class is defined by a combination of three columns in data_table. The names
of these columns are found under:
......@@ -1494,8 +1519,11 @@ class ExposureModelESRM20(AggregatedExposureModel):
'data_table', weighted by the number of buildings in each entry. If False, the
function will check that values of total replacement costs and total census
people per building are the same in all entries of the building class in
'data_table'; if they are not, the maximum values are assigned and an error
message is logged.
'data_table' before assigning them to the respective building classes; if they
are not, a list of the names of the columns of 'data_table' for which the check
failed is output (as 'warning_in_properties'), 'weighted_average' is set to True
and the total replacement costs and total census people per building are
calculated as the weighted average.
Returns:
proportions_and_properties (Pandas DataFrame):
......@@ -1518,11 +1546,11 @@ class ExposureModelESRM20(AggregatedExposureModel):
total_cost_per_building (float):
Total replacement cost per building, including costs of structural and
non-structural components as well as contents.
error_in_properties (list of str):
warning_in_properties (list of str):
It specifies the names of the columns of 'data_table' for which different values
of total replacement costs and total census people per building have been found
for different entries of the same building class. If empty, no problem has been
found. It can only contain elements if 'weighted_average' is set to False.
for different entries of the same building class. If empty, no such case has
been found. It can only contain elements if 'weighted_average' is set to False.
"""
building_class_fields = [
......@@ -1580,9 +1608,33 @@ class ExposureModelESRM20(AggregatedExposureModel):
# Retrieve from data_table columns_to_filter_properties
data_filtered = data_table.loc[:, columns_to_filter_properties].copy()
error_in_properties = []
warning_in_properties = []
# Identify unique combinations of the columns_to_group and minimum and maximum values of
# building properties
grouped_max = data_filtered.groupby(columns_to_group).max()
grouped_min = data_filtered.groupby(columns_to_group).min()
grouped_diff = grouped_max - grouped_min
# Check that 'grouped_max' and 'grouped_min' yield the same values of
# 'building_fundamental_properties_fields'; log the names of the fields that do not
# comply with this
for j, col in enumerate(building_fundamental_properties_fields):
if numpy.any(abs(grouped_diff[self.csv_column_names[col]].to_numpy()) > 1e-2):
warning_in_properties.append("'%s'" % (col))
if len(warning_in_properties) > 0: # Fields with warnings have been found
if not weighted_average:
# Switch to using the weighted average because warnings have been raised
weighted_average = True
else:
# If 'weighted_average' was already True, then warnings are discarded
warning_in_properties = []
if weighted_average:
if not weighted_average: # 'grouped_max' = 'grouped_min'
for j, col in enumerate(building_output_properties_fields):
unique_vals[col] = grouped_max[self.csv_column_names[col]].to_numpy()
else: # Weighted-average properties are calculated
number_unique = grouped.shape[0]
aux_output_properties = numpy.zeros(
[number_unique, len(building_output_properties_fields)]
......@@ -1612,23 +1664,10 @@ class ExposureModelESRM20(AggregatedExposureModel):
# Write output properties to 'unique_vals'
for j, col in enumerate(building_output_properties_fields):
unique_vals[col] = aux_output_properties[:, j]
else:
# Identify unique combinations of the columns_to_group and minimum and maximum
# values of building properties
grouped_max = data_filtered.groupby(columns_to_group).max()
grouped_min = data_filtered.groupby(columns_to_group).min()
grouped_diff = grouped_max - grouped_min
for j, col in enumerate(building_fundamental_properties_fields):
if numpy.any(abs(grouped_diff[self.csv_column_names[col]].to_numpy()) > 1e-2):
error_in_properties.append(col)
for j, col in enumerate(building_output_properties_fields):
unique_vals[col] = grouped_max[self.csv_column_names[col]].to_numpy()
proportions_and_properties = pandas.DataFrame(unique_vals)
return proportions_and_properties, error_in_properties
return proportions_and_properties, warning_in_properties
def _retrieve_costs_disaggregation(self, configuration):
"""This function retrieves the factors through which the total replacement cost of a
......
......@@ -2,7 +2,7 @@ LON,LAT,TAXONOMY,SETTLEMENT_TYPE,OCCUPANCY_TYPE,BUILDINGS,ID_1,AREA_PER_BUILDING
20.1,47.3,A,BIG_CITY,ALL,35.2,Unit_X,90,1400,316800000,126720000,63360000,126720000,1056,844.8,105.6,211.2,387.2
20.1,47.3,B,RURAL,ALL,12.7,Unit_X,120,1050,114300000,45720000,22860000,45720000,381,304.8,38.1,76.2,139.7
20.1,47.3,C,BIG_CITY,ALL,8.9,Unit_X,85,1300,80100000,32040000,16020000,32040000,267,213.6,26.7,53.4,97.9
20.1,47.3,C,BIG_CITY,ALL,5.7,Unit_X,85,1300,51300000,20520000,10260000,20520000,171,136.8,17.1,34.2,62.7
20.1,47.3,C,BIG_CITY,ALL,5.7,Unit_X,90,1400,51300000,20520000,10260000,20520000,171,136.8,17.1,34.2,62.7
19.8,47.4,A,RURAL,ALL,25.6,Unit_Y,110,980,230400000,92160000,46080000,92160000,768,614.4,76.8,153.6,281.6
19.8,47.4,A,URBAN,ALL,7.9,Unit_Y,95,1280,71100000,28440000,14220000,28440000,237,189.6,23.7,47.4,86.9
19.8,47.4,B,RURAL,ALL,23.5,Unit_Y,120,1050,211500000,84600000,42300000,84600000,705,564,70.5,141,258.5
......
......@@ -17,7 +17,7 @@ Entity_1,residential,residential_FILLER,C,BIG_CITY,Single,0.02722063,7.5,393300
Entity_1,residential,residential_FILLER,C,RURAL,Single,0.159503343,7.5,414000
Entity_1,commercial,Unit_X,A,BIG_CITY,ALL,0.5632,30,126000
Entity_1,commercial,Unit_X,B,RURAL,ALL,0.2032,30,126000
Entity_1,commercial,Unit_X,C,BIG_CITY,ALL,0.2336,30,110500
Entity_1,commercial,Unit_X,C,BIG_CITY,ALL,0.2336,30,116551.3699
Entity_1,commercial,Unit_Y,A,RURAL,ALL,0.449122807,30,107800
Entity_1,commercial,Unit_Y,A,URBAN,ALL,0.138596491,30,121600
Entity_1,commercial,Unit_Y,B,RURAL,ALL,0.412280702,30,126000
......@@ -29,7 +29,7 @@ Entity_1,commercial,commercial_FILLER,A,RURAL,ALL,0.122254059,30,107800
Entity_1,commercial,commercial_FILLER,A,URBAN,ALL,0.037726839,30,121600
Entity_1,commercial,commercial_FILLER,B,BIG_CITY,ALL,0.077841452,30,121000
Entity_1,commercial,commercial_FILLER,B,RURAL,ALL,0.172874881,30,126000
Entity_1,commercial,commercial_FILLER,C,BIG_CITY,ALL,0.069723018,30,110500
Entity_1,commercial,commercial_FILLER,C,BIG_CITY,ALL,0.069723018,30,116551.3699
Entity_1,commercial,commercial_FILLER,C,RURAL,ALL,0.159503343,30,138000
Entity_2,commercial,Unit_A,A,ALL,Offices,0.5632,30,210000
Entity_2,commercial,Unit_A,B,ALL,Offices,0.2032,30,260000
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment