hestia-earth-models 0.66.0__py3-none-any.whl → 0.67.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +23 -54
- hestia_earth/models/cml2001Baseline/resourceUseEnergyDepletionDuringCycle.py +147 -0
- hestia_earth/models/cml2001Baseline/resourceUseEnergyDepletionInputsProduction.py +40 -0
- hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +80 -0
- hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsInputsProduction.py +40 -0
- hestia_earth/models/config/ImpactAssessment.json +1869 -1846
- hestia_earth/models/cycle/completeness/freshForage.py +7 -3
- hestia_earth/models/cycle/inorganicFertiliser.py +67 -17
- hestia_earth/models/cycle/input/hestiaAggregatedData.py +13 -10
- hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/__init__.py +4 -3
- hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/environmentalFootprintSingleOverallScore.py +42 -37
- hestia_earth/models/environmentalFootprintV3_1/marineEutrophicationPotential.py +36 -0
- hestia_earth/models/environmentalFootprintV3_1/scarcityWeightedWaterUse.py +40 -0
- hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/soilQualityIndexLandTransformation.py +22 -14
- hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/soilQualityIndexTotalLandUseEffects.py +17 -15
- hestia_earth/models/hestia/landTransformation100YearAverageDuringCycle.py +1 -1
- hestia_earth/models/hestia/landTransformation20YearAverageDuringCycle.py +1 -1
- hestia_earth/models/impact_assessment/product/value.py +1 -1
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +2 -2
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +2 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +6 -5
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +3 -2
- hestia_earth/models/mocking/search-results.json +1200 -1068
- hestia_earth/models/site/management.py +2 -2
- hestia_earth/models/utils/__init__.py +6 -0
- hestia_earth/models/utils/aggregated.py +13 -10
- hestia_earth/models/utils/array_builders.py +4 -3
- hestia_earth/models/utils/blank_node.py +78 -21
- hestia_earth/models/utils/ecoClimateZone.py +2 -2
- hestia_earth/models/utils/impact_assessment.py +5 -4
- hestia_earth/models/utils/lookup.py +5 -5
- hestia_earth/models/utils/property.py +5 -2
- hestia_earth/models/version.py +1 -1
- hestia_earth/orchestrator/log.py +11 -0
- hestia_earth/orchestrator/models/__init__.py +8 -3
- {hestia_earth_models-0.66.0.dist-info → hestia_earth_models-0.67.1.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.66.0.dist-info → hestia_earth_models-0.67.1.dist-info}/RECORD +64 -52
- tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +51 -87
- tests/models/cml2001Baseline/test_resourceUseEnergyDepletionDuringCycle.py +136 -0
- tests/models/cml2001Baseline/test_resourceUseEnergyDepletionInputsProduction.py +23 -0
- tests/models/cml2001Baseline/test_resourceUseMineralsAndMetalsDuringCycle.py +58 -0
- tests/models/cml2001Baseline/test_resourceUseMineralsAndMetalsInputsProduction.py +23 -0
- tests/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/test_environmentalFootprintSingleOverallScore.py +43 -12
- tests/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/test_freshwaterEcotoxicityPotentialCtue.py +6 -5
- tests/models/environmentalFootprintV3_1/test_marineEutrophicationPotential.py +27 -0
- tests/models/environmentalFootprintV3_1/test_scarcityWeightedWaterUse.py +32 -0
- tests/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/test_soilQualityIndexLandOccupation.py +4 -3
- tests/models/environmentalFootprintV3_1/test_soilQualityIndexLandTransformation.py +194 -0
- tests/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/test_soilQualityIndexTotalLandUseEffects.py +4 -4
- tests/models/impact_assessment/test_emissions.py +0 -1
- tests/models/site/test_management.py +1 -4
- tests/models/test_config.py +3 -3
- tests/models/test_ecoinventV3.py +0 -1
- tests/models/utils/test_array_builders.py +2 -2
- tests/models/utils/test_blank_node.py +13 -165
- tests/orchestrator/models/test_transformations.py +4 -1
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +0 -164
- /hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/freshwaterEcotoxicityPotentialCtue.py +0 -0
- /hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/soilQualityIndexLandOccupation.py +0 -0
- /hestia_earth/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/utils.py +0 -0
- {hestia_earth_models-0.66.0.dist-info → hestia_earth_models-0.67.1.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.66.0.dist-info → hestia_earth_models-0.67.1.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.66.0.dist-info → hestia_earth_models-0.67.1.dist-info}/top_level.txt +0 -0
- /tests/models/{environmentalFootprintV3 → environmentalFootprintV3_1}/__init__.py +0 -0
@@ -110,7 +110,7 @@ _PRACTICES_TERM_TYPES = [
|
|
110
110
|
TermTermType.LANDUSEMANAGEMENT,
|
111
111
|
TermTermType.SYSTEM
|
112
112
|
]
|
113
|
-
_PRACTICES_COMPLETENESS_MAPPING = COMPLETENESS_MAPPING.get(SchemaType.PRACTICE.value)
|
113
|
+
_PRACTICES_COMPLETENESS_MAPPING = COMPLETENESS_MAPPING.get(SchemaType.PRACTICE.value, {})
|
114
114
|
_ANIMAL_MANURE_USED_TERM_ID = "animalManureUsed"
|
115
115
|
_INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID = "inorganicNitrogenFertiliserUsed"
|
116
116
|
_ORGANIC_FERTILISER_USED_TERM_ID = "organicFertiliserUsed"
|
@@ -242,7 +242,7 @@ def _get_relevant_items(cycle: dict, item_name: str, term_types: List[TermTermTy
|
|
242
242
|
term_type for term_type in term_types
|
243
243
|
if any([
|
244
244
|
not completeness_mapping.get(term_type.value),
|
245
|
-
cycle.get('completeness').get(completeness_mapping.get(term_type.value), False)
|
245
|
+
cycle.get('completeness', {}).get(completeness_mapping.get(term_type.value), False)
|
246
246
|
])
|
247
247
|
]
|
248
248
|
blank_nodes = filter_list_term_type(cycle.get(item_name, []), complete_term_types)
|
@@ -165,6 +165,12 @@ def last_day_of_month(year: int, month: int):
|
|
165
165
|
)
|
166
166
|
|
167
167
|
|
168
|
+
def current_date(): return datetime.datetime.now().date().strftime('%Y-%m-%d')
|
169
|
+
|
170
|
+
|
171
|
+
def current_year(): return int(current_date()[:4])
|
172
|
+
|
173
|
+
|
168
174
|
def flatten_args(args) -> list:
|
169
175
|
"""
|
170
176
|
Flatten the input args into a single list.
|
@@ -6,7 +6,8 @@ from hestia_earth.utils.model import find_term_match, linked_node
|
|
6
6
|
from hestia_earth.utils.tools import safe_parse_date, non_empty_list
|
7
7
|
|
8
8
|
from hestia_earth.models.log import debugValues, logShouldRun
|
9
|
-
from
|
9
|
+
from . import current_year
|
10
|
+
from .cycle import is_organic
|
10
11
|
|
11
12
|
MODEL_KEY = 'impactAssessment'
|
12
13
|
MATCH_WORLD_QUERY = {'match': {'country.name.keyword': {'query': 'World', 'boost': 1}}}
|
@@ -14,7 +15,7 @@ MATCH_WORLD_QUERY = {'match': {'country.name.keyword': {'query': 'World', 'boost
|
|
14
15
|
|
15
16
|
def aggregated_end_date(end_date: str):
|
16
17
|
year = safe_parse_date(end_date).year
|
17
|
-
return round(math.floor(year / 10) * 10) + 9
|
18
|
+
return min([round(math.floor(year / 10) * 10) + 9, current_year()])
|
18
19
|
|
19
20
|
|
20
21
|
def _match_region_country(region: dict, country: dict):
|
@@ -36,8 +37,7 @@ def _match_region_country(region: dict, country: dict):
|
|
36
37
|
}
|
37
38
|
|
38
39
|
|
39
|
-
def find_closest_impact(cycle: dict, end_date: str,
|
40
|
-
term = input.get('term', {})
|
40
|
+
def find_closest_impact(cycle: dict, end_date: str, term: dict, region: dict, country: dict, must_queries=[]):
|
41
41
|
query = {
|
42
42
|
'bool': {
|
43
43
|
'must': non_empty_list([
|
@@ -74,21 +74,24 @@ def find_closest_impact(cycle: dict, end_date: str, input: dict, region: dict, c
|
|
74
74
|
|
75
75
|
def _link_input_to_impact(model: str, cycle: dict, date: int):
|
76
76
|
def run(input: dict):
|
77
|
-
|
77
|
+
term = input.get('term', {})
|
78
|
+
term_id = term.get('@id')
|
78
79
|
region = input.get('region')
|
79
80
|
country = input.get('country')
|
80
|
-
impact = find_closest_impact(cycle, date,
|
81
|
+
impact = find_closest_impact(cycle, date, term, region, country)
|
81
82
|
|
83
|
+
search_by_region_id = (region or country or {}).get('@id') or 'region-world'
|
82
84
|
debugValues(cycle, model=model, term=term_id, key=MODEL_KEY,
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
search_by_input_term_id=term_id,
|
86
|
+
search_by_region_id=search_by_region_id,
|
87
|
+
search_by_end_date=str(date),
|
88
|
+
impact_assessment_id_found=(impact or {}).get('@id'))
|
86
89
|
|
87
90
|
should_run = all([impact is not None])
|
88
91
|
logShouldRun(cycle, model, term_id, should_run)
|
89
92
|
logShouldRun(cycle, model, term_id, should_run, key=MODEL_KEY) # show specifically under Input
|
90
93
|
|
91
|
-
return
|
94
|
+
return input | {MODEL_KEY: linked_node(impact), 'impactAssessmentIsProxy': True} if impact else None
|
92
95
|
return run
|
93
96
|
|
94
97
|
|
@@ -527,12 +527,13 @@ def avg_run_in_rowwise(arr: NDArray, n: int):
|
|
527
527
|
return avg_run_in_columnwise(arr.transpose(), n).transpose()
|
528
528
|
|
529
529
|
|
530
|
-
def gen_seed(node: dict) -> int:
|
530
|
+
def gen_seed(node: dict, *args: tuple[str]) -> int:
|
531
531
|
"""
|
532
|
-
Generate a seed based on a node's `@id` so that rng is the same each time the model is re-run.
|
532
|
+
Generate a seed based on a node's `@id` and optional args so that rng is the same each time the model is re-run.
|
533
533
|
"""
|
534
534
|
node_id = node.get("@id", "")
|
535
|
-
|
535
|
+
seed_str = "".join([node_id] + [str(arg) for arg in args])
|
536
|
+
hashed = hashlib.shake_128(seed_str.encode(), usedforsecurity=False).hexdigest(4)
|
536
537
|
return abs(int(hashed, 16))
|
537
538
|
|
538
539
|
|
@@ -12,7 +12,6 @@ from typing import (
|
|
12
12
|
Optional,
|
13
13
|
Union
|
14
14
|
)
|
15
|
-
|
16
15
|
from dateutil import parser
|
17
16
|
from dateutil.relativedelta import relativedelta
|
18
17
|
from hestia_earth.schema import TermTermType
|
@@ -22,6 +21,7 @@ from hestia_earth.utils.model import filter_list_term_type
|
|
22
21
|
from hestia_earth.utils.tools import (
|
23
22
|
flatten,
|
24
23
|
list_sum,
|
24
|
+
list_average,
|
25
25
|
safe_parse_date,
|
26
26
|
safe_parse_float,
|
27
27
|
non_empty_list
|
@@ -35,7 +35,7 @@ from .lookup import (
|
|
35
35
|
is_product_id_allowed, is_product_termType_allowed,
|
36
36
|
is_input_id_allowed, is_input_termType_allowed, _node_value
|
37
37
|
)
|
38
|
-
from .property import get_node_property, get_node_property_value
|
38
|
+
from .property import get_node_property, get_node_property_value
|
39
39
|
from .term import get_lookup_value
|
40
40
|
from ..log import debugValues, log_as_table
|
41
41
|
|
@@ -44,6 +44,14 @@ MAX_DEPTH = 1000
|
|
44
44
|
OLDEST_DATE = '1800'
|
45
45
|
|
46
46
|
|
47
|
+
def group_by_term(values: list):
|
48
|
+
def group_by(groups: dict, value: dict):
|
49
|
+
key = value.get('term', {}).get('@id')
|
50
|
+
groups[key] = groups.get(key, []) + [value]
|
51
|
+
return groups
|
52
|
+
return reduce(group_by, values, {})
|
53
|
+
|
54
|
+
|
47
55
|
def merge_blank_nodes(source: list, new_values: list):
|
48
56
|
"""
|
49
57
|
Merge a list of blank nodes into an existing list of blank nodes.
|
@@ -1335,11 +1343,14 @@ def _node_from_group(nodes: list):
|
|
1335
1343
|
# `nodes` contain list with consecutive dates
|
1336
1344
|
return nodes[0] if len(nodes) == 1 else (
|
1337
1345
|
# if all nodes have the same dates, sum up the values
|
1338
|
-
nodes[0] |
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1346
|
+
nodes[0] | (
|
1347
|
+
{
|
1348
|
+
'value': _sum_nodes_value(nodes)
|
1349
|
+
} if _same_dates(nodes) else {
|
1350
|
+
'startDate': min(n.get('startDate') for n in nodes),
|
1351
|
+
'endDate': max(n.get('endDate') for n in nodes)
|
1352
|
+
}
|
1353
|
+
)
|
1343
1354
|
)
|
1344
1355
|
|
1345
1356
|
|
@@ -1349,7 +1360,7 @@ def _condense_nodes(nodes: list):
|
|
1349
1360
|
return flatten(map(_node_from_group, grouped_nodes))
|
1350
1361
|
|
1351
1362
|
|
1352
|
-
def
|
1363
|
+
def _group_nodes_by_value_and_properties(nodes: list) -> dict:
|
1353
1364
|
def _group_node(group: dict, node: dict):
|
1354
1365
|
value = node.get('value', [])
|
1355
1366
|
value = '-'.join(map(str, value if isinstance(value, list) else [value]))
|
@@ -1359,7 +1370,6 @@ def _group_nodes_to_condense(nodes: list) -> dict:
|
|
1359
1370
|
f"{p.get('value')}"
|
1360
1371
|
])) for p in node.get('properties', [])
|
1361
1372
|
]))
|
1362
|
-
# group by term, value, and properties
|
1363
1373
|
group_key = '-'.join(non_empty_list([
|
1364
1374
|
node.get('term', {}).get('@id', ''),
|
1365
1375
|
value,
|
@@ -1371,8 +1381,51 @@ def _group_nodes_to_condense(nodes: list) -> dict:
|
|
1371
1381
|
return reduce(_group_node, nodes, {})
|
1372
1382
|
|
1373
1383
|
|
1384
|
+
def _group_nodes_by_dates(nodes: list) -> dict:
|
1385
|
+
def _group_node(group: dict, node: dict):
|
1386
|
+
group_key = '-'.join(non_empty_list([
|
1387
|
+
node.get('term', {}).get('@id', ''),
|
1388
|
+
node.get('startDate'),
|
1389
|
+
node.get('endDate'),
|
1390
|
+
]))
|
1391
|
+
group[group_key] = group.get(group_key, []) + [node]
|
1392
|
+
return group
|
1393
|
+
|
1394
|
+
return reduce(_group_node, nodes, {})
|
1395
|
+
|
1396
|
+
|
1397
|
+
def _average_properties(properties: list):
|
1398
|
+
# group properties by term
|
1399
|
+
grouped_properties = group_by_term(properties)
|
1400
|
+
return [
|
1401
|
+
props[0] | {
|
1402
|
+
'value': list_average(non_empty_list([p.get('value') for p in props]), default=props[0].get('value'))
|
1403
|
+
}
|
1404
|
+
for props in grouped_properties.values()
|
1405
|
+
]
|
1406
|
+
|
1407
|
+
|
1408
|
+
def _merge_same_dates(nodes: list):
|
1409
|
+
# group by term, startDate and endDate
|
1410
|
+
grouped_nodes = _group_nodes_by_dates(nodes)
|
1411
|
+
|
1412
|
+
def merge_nodes(nodes: list):
|
1413
|
+
properties = flatten([n.get('properties', []) for n in nodes])
|
1414
|
+
return nodes[0] | (
|
1415
|
+
{
|
1416
|
+
'value': _sum_nodes_value(nodes)
|
1417
|
+
} | ({
|
1418
|
+
'properties': _average_properties(properties)
|
1419
|
+
} if properties else {})
|
1420
|
+
) if len(nodes) > 1 else nodes[0]
|
1421
|
+
|
1422
|
+
return list(map(merge_nodes, grouped_nodes.values()))
|
1423
|
+
|
1424
|
+
|
1374
1425
|
def condense_nodes(nodes: list) -> list:
|
1375
|
-
|
1426
|
+
# merge nodes with the same term and dates as they need to be unique
|
1427
|
+
values = _merge_same_dates(nodes)
|
1428
|
+
grouped_nodes = _group_nodes_by_value_and_properties(values)
|
1376
1429
|
return flatten(map(_condense_nodes, grouped_nodes.values()))
|
1377
1430
|
|
1378
1431
|
|
@@ -1446,13 +1499,13 @@ def most_relevant_blank_node_by_id(nodes: list, term_id: str, date: str):
|
|
1446
1499
|
PROPERTY_UNITS_CONVERSIONS = {
|
1447
1500
|
Units.KG.value: {
|
1448
1501
|
Units.MJ.value: [
|
1449
|
-
'
|
1502
|
+
'energyContentLowerHeatingValue', # "kg" to "mj"
|
1450
1503
|
]
|
1451
1504
|
},
|
1452
1505
|
Units.M3.value: {
|
1453
1506
|
Units.MJ.value: [
|
1454
1507
|
'density', # "m3" to "kg"
|
1455
|
-
'
|
1508
|
+
'energyContentLowerHeatingValue', # "kg" to "mj"
|
1456
1509
|
]
|
1457
1510
|
}
|
1458
1511
|
}
|
@@ -1468,16 +1521,20 @@ def _convert_via_property(node: dict, node_value: Union[int, float], property_fi
|
|
1468
1521
|
|
1469
1522
|
Parameters
|
1470
1523
|
----------
|
1471
|
-
node:
|
1472
|
-
|
1473
|
-
|
1524
|
+
node: dict
|
1525
|
+
Blank node containing a term
|
1526
|
+
node_value: int | float
|
1527
|
+
Value to be converted as float or int
|
1528
|
+
property_field: str
|
1529
|
+
E.g., "density"
|
1474
1530
|
|
1475
|
-
Returns
|
1531
|
+
Returns
|
1476
1532
|
-------
|
1533
|
+
Float or None
|
1477
1534
|
"""
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1535
|
+
node_property_value = get_node_property_value(
|
1536
|
+
model=None, node=node, prop_id=property_field, default=0, handle_percents=False
|
1537
|
+
)
|
1481
1538
|
return node_value * node_property_value if node_value is not None and bool(node_property_value) else None
|
1482
1539
|
|
1483
1540
|
|
@@ -1486,7 +1543,7 @@ def convert_unit(node, dest_unit: Units, node_value: Union[int, float] = None) -
|
|
1486
1543
|
Convert a number `value` inside a node or a optional `node_value` belonging to a term `node`, to unit `dest_unit`
|
1487
1544
|
using the ATOMIC_WEIGHT_CONVERSIONS map or failing that, the PROPERTY_UNITS_CONVERSIONS map and lookups
|
1488
1545
|
"""
|
1489
|
-
src_unit = node.get("units", "")
|
1546
|
+
src_unit = node.get("units") or node.get('term', {}).get('units', "")
|
1490
1547
|
|
1491
1548
|
node_value = _node_value(node) if node_value is None else node_value
|
1492
1549
|
|
@@ -1505,7 +1562,7 @@ def convert_unit_properties(node_value: Union[int, float], node: dict, dest_unit
|
|
1505
1562
|
Uses cached calls to download_hestia() internally for speedup
|
1506
1563
|
Returns None if no conversion possible.
|
1507
1564
|
"""
|
1508
|
-
src_unit = node.get(
|
1565
|
+
src_unit = node.get("units") or node.get('term', {}).get('units', "")
|
1509
1566
|
conversions = PROPERTY_UNITS_CONVERSIONS.get(src_unit, {}).get(dest_unit.value, [])
|
1510
1567
|
return reduce(
|
1511
1568
|
lambda value, conversion_property_field: _convert_via_property(node, value, conversion_property_field),
|
@@ -36,8 +36,8 @@ def get_eco_climate_zone_value(node: dict, as_enum: bool = False) -> Union[int,
|
|
36
36
|
Parameters
|
37
37
|
----------
|
38
38
|
node : dict
|
39
|
-
A HESTIA [Site](https://
|
40
|
-
[Cycle](https://
|
39
|
+
A HESTIA [Site](https://hestia.earth/schema/Site) or
|
40
|
+
[Cycle](https://hestia.earth/schema/Cycle).
|
41
41
|
|
42
42
|
Returns
|
43
43
|
-------
|
@@ -131,6 +131,7 @@ def impact_country_value(
|
|
131
131
|
lookup: str,
|
132
132
|
group_key: str = None,
|
133
133
|
country_fallback: bool = False,
|
134
|
+
default_no_values=None
|
134
135
|
) -> float:
|
135
136
|
"""
|
136
137
|
Calculate the value of the impact based on lookup factors and `site.country.@id`.
|
@@ -166,13 +167,13 @@ def impact_country_value(
|
|
166
167
|
debugValues(impact, model=model, term=term_id,
|
167
168
|
values_used=log_as_table(values))
|
168
169
|
|
169
|
-
|
170
|
+
has_values = len(values) > 0
|
171
|
+
missing_values = set([v.get('id') for v in values if v.get('value') and v.get('coefficient') is None])
|
172
|
+
all_with_factors = not missing_values
|
170
173
|
values = [float((v.get('value') or 0) * (v.get('coefficient') or 0)) for v in values]
|
171
174
|
|
172
175
|
# fail if some factors are missing
|
173
|
-
return None if not all_with_factors else (
|
174
|
-
list_sum(values) if len(values) > 0 else None
|
175
|
-
)
|
176
|
+
return None if not all_with_factors else (list_sum(values) if has_values else default_no_values)
|
176
177
|
|
177
178
|
|
178
179
|
def impact_aware_value(model: str, term_id: str, impact: dict, lookup: str, group_key: str = None) -> float:
|
@@ -49,8 +49,9 @@ def all_factor_value(
|
|
49
49
|
):
|
50
50
|
values = list(map(_factor_value(model, term_id, lookup_name, lookup_col, grouped_key), blank_nodes))
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
has_values = len(values) > 0
|
53
|
+
missing_values = set([v.get('id') for v in values if v.get('value') and v.get('coefficient') is None])
|
54
|
+
all_with_factors = not missing_values
|
54
55
|
|
55
56
|
for missing_value in missing_values:
|
56
57
|
debugMissingLookup(lookup_name, 'termid', missing_value, lookup_col, None, model=model, term=term_id)
|
@@ -58,14 +59,13 @@ def all_factor_value(
|
|
58
59
|
debugValues(node, model=model, term=term_id,
|
59
60
|
all_with_factors=all_with_factors,
|
60
61
|
missing_lookup_factor=';'.join(missing_values),
|
62
|
+
has_values=has_values,
|
61
63
|
values_used=log_as_table(values))
|
62
64
|
|
63
65
|
values = [float((v.get('value') or 0) * (v.get('coefficient') or 0)) for v in values]
|
64
66
|
|
65
67
|
# fail if some factors are missing
|
66
|
-
return None if not all_with_factors else (
|
67
|
-
list_sum(values) if len(values) > 0 else default_no_values
|
68
|
-
)
|
68
|
+
return None if not all_with_factors else (list_sum(values) if has_values else default_no_values)
|
69
69
|
|
70
70
|
|
71
71
|
def _term_factor_value(model: str, term_id: str, lookup_name: str, lookup_term_id: str, group_key: str = None):
|
@@ -57,7 +57,8 @@ def find_term_property(term, property: str, default=None, keep_in_memory=False)
|
|
57
57
|
return find_term_match(props, property, default)
|
58
58
|
|
59
59
|
|
60
|
-
def get_node_property(node: dict, property: str, find_default_property: bool = True
|
60
|
+
def get_node_property(node: dict, property: str, find_default_property: bool = True,
|
61
|
+
keep_in_memory: bool = False) -> dict:
|
61
62
|
"""
|
62
63
|
Get the property by `@id` linked to the Blank Node in the glossary.
|
63
64
|
|
@@ -73,6 +74,8 @@ def get_node_property(node: dict, property: str, find_default_property: bool = T
|
|
73
74
|
The `term.@id` of the property. Example: `nitrogenContent`.
|
74
75
|
find_default_property : bool
|
75
76
|
Default to fetching the property from the `defaultProperties` of the `Term`.
|
77
|
+
keep_in_memory:
|
78
|
+
If True and find_default_property is True, will cache this term_id call to api
|
76
79
|
|
77
80
|
Returns
|
78
81
|
-------
|
@@ -80,7 +83,7 @@ def get_node_property(node: dict, property: str, find_default_property: bool = T
|
|
80
83
|
The property if found, `None` otherwise.
|
81
84
|
"""
|
82
85
|
prop = find_term_match(node.get('properties', []), property, None)
|
83
|
-
return find_term_property(node.get('term', {}), property, {}) if all([
|
86
|
+
return find_term_property(node.get('term', {}), property, {}, keep_in_memory) if all([
|
84
87
|
find_default_property,
|
85
88
|
prop is None
|
86
89
|
]) else (prop or {})
|
hestia_earth/models/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION = '0.
|
1
|
+
VERSION = '0.67.1'
|
hestia_earth/orchestrator/log.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import sys
|
3
|
+
import platform
|
4
|
+
import resource
|
3
5
|
import logging
|
4
6
|
|
5
7
|
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
@@ -42,6 +44,15 @@ if LOG_FILENAME is not None:
|
|
42
44
|
def _join_args(**kwargs): return ', '.join([f"{key}={value}" for key, value in kwargs.items()])
|
43
45
|
|
44
46
|
|
47
|
+
def log_memory_usage(**kwargs):
|
48
|
+
factor = 1024 * (
|
49
|
+
1024 if platform.system() in ['Darwin', 'Windows'] else 1
|
50
|
+
)
|
51
|
+
value = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / factor
|
52
|
+
extra = (', ' + _join_args(**kwargs)) if len(kwargs.keys()) > 0 else ''
|
53
|
+
logger.info('memory used=%s, unit=MB' + extra, value)
|
54
|
+
|
55
|
+
|
45
56
|
def _log_node_suffix(node: dict = {}):
|
46
57
|
node_type = node.get('@type', node.get('type')) if node else None
|
47
58
|
node_id = node.get('@id', node.get('id', node.get('term', {}).get('@id'))) if node else None
|
@@ -7,7 +7,7 @@ from copy import deepcopy
|
|
7
7
|
from hestia_earth.utils.tools import non_empty_list
|
8
8
|
|
9
9
|
from hestia_earth.models.version import VERSION
|
10
|
-
from ..log import logger
|
10
|
+
from ..log import logger, log_memory_usage
|
11
11
|
from ..utils import get_required_model_param, _snakecase
|
12
12
|
from ..strategies.run import should_run
|
13
13
|
from ..strategies.merge import merge
|
@@ -76,10 +76,15 @@ def _run_post_checks(data: dict):
|
|
76
76
|
|
77
77
|
|
78
78
|
def _run_model(data: dict, model: dict, all_models: list):
|
79
|
-
|
80
|
-
# if no value is provided, use all the models but this one
|
79
|
+
model_id = get_required_model_param(model, 'model')
|
81
80
|
model_value = model.get('value') or _list_except_item(all_models, model)
|
81
|
+
log_memory_usage(model_model=model_id, model_value=model_value, step='before')
|
82
|
+
|
83
|
+
module = _import_model(model_id.replace('-', '_'))
|
84
|
+
# if no value is provided, use all the models but this one
|
82
85
|
result = module.get('run')(model_value, data)
|
86
|
+
|
87
|
+
log_memory_usage(model_model=model_id, model_value=model_value, step='after')
|
83
88
|
return {'data': data, 'model': model, 'version': module.get('version'), 'result': result}
|
84
89
|
|
85
90
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: hestia-earth-models
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.67.1
|
4
4
|
Summary: HESTIA's set of modules for filling gaps in the activity data using external datasets (e.g. populating soil properties with a geospatial dataset using provided coordinates) and internal lookups (e.g. populating machinery use from fuel use). Includes rules for when gaps should be filled versus not (e.g. never gap fill yield, gap fill crop residue if yield provided etc.).
|
5
5
|
Home-page: https://gitlab.com/hestia-earth/hestia-engine-models
|
6
6
|
Author: HESTIA Team
|