Skip to content

Commit dee4dfa

Browse files
authored
Merge pull request #174 from spjuhel/develop
v0.6.3 release (VA tracking and Arbitrary events)
2 parents ee3a3a0 + dc84e62 commit dee4dfa

File tree

10 files changed

+1010
-336
lines changed

10 files changed

+1010
-336
lines changed

.github/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
changelog:
2+
exclude:
3+
authors:
4+
- dependabot
5+
- pre-commit-ci

AUTHORS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# BoARIO authors
2+
3+
* Samuel Juhel

boario/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@
4343

4444
try:
4545
__git_branch__ = pygit2.Repository(__file__).head.name
46-
logger.info("You are using boario from branch %s", __git_branch__)
46+
logger.debug("You are using boario from branch %s", __git_branch__)
4747
except pygit2.GitError:
48-
logger.info(
48+
logger.debug(
4949
"Could not find git branch, this is normal if you installed boario from pip/conda."
5050
)
5151
except ModuleNotFoundError:
52-
logger.info("Unable to tell git branch as pygit2 was not found.")
52+
logger.debug("Unable to tell git branch as pygit2 was not found.")

boario/event.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,16 @@ def from_scalar_industries(
287287
recovery_function=recovery_function,
288288
)
289289
elif event_type == "arbitrary":
290-
raise NotImplementedError("This method does not yet accept this type of event.")
290+
return EventArbitraryProd._from_scalar_industries(
291+
impact=impact,
292+
affected_industries=affected_industries,
293+
impact_distrib=impact_distrib,
294+
occurrence=occurrence,
295+
duration=duration,
296+
name=name,
297+
recovery_tau=recovery_tau,
298+
recovery_function=recovery_function,
299+
)
291300
else:
292301
raise ValueError(f"Wrong event type: {event_type}")
293302

@@ -389,7 +398,18 @@ def from_scalar_regions_sectors(
389398
recovery_function=recovery_function,
390399
)
391400
elif event_type == "arbitrary":
392-
raise NotImplementedError("This type of event is not implemented yet.")
401+
return EventArbitraryProd._from_scalar_regions_sectors(
402+
impact=impact,
403+
affected_regions=affected_regions,
404+
affected_sectors=affected_sectors,
405+
impact_regional_distrib=impact_regional_distrib,
406+
impact_sectoral_distrib=impact_sectoral_distrib,
407+
occurrence=occurrence,
408+
duration=duration,
409+
name=name,
410+
recovery_tau=recovery_tau,
411+
recovery_function=recovery_function,
412+
)
393413
else:
394414
raise ValueError(f"Wrong event type: {event_type}")
395415

@@ -609,7 +629,6 @@ def from_scalar_regions_sectors(
609629
impact_sectoral_distrib : Optional[Union[str, npt.ArrayLike]], optional
610630
Either:
611631
612-
* ``\"gdp\"``, the impact is then distributed using the gross value added of each sector as a weight.
613632
* A vector of equal size to the list of sectors affected, stating the share of the impact each industry should receive. Defaults to None.
614633
615634
occurrence : int, optional

boario/model_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,8 @@ def distribute_production(
10661066
raise RuntimeError(
10671067
"matrix_stock contains negative values, this should not happen"
10681068
)
1069+
if (np.isnan(self.inputs_stock)).any():
1070+
raise RuntimeError("matrix_stock contains NaNs, this should not happen")
10691071

10701072
# 6. Compute final demand not met due to rationing
10711073
final_demand_not_met = (

boario/simulation.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class Simulation:
7676
"inputs_stocks",
7777
"limiting_inputs",
7878
"productive_capital_to_recover",
79+
"value_added",
7980
]
8081

8182
__file_save_array_specs = {
@@ -91,6 +92,12 @@ class Simulation:
9192
"industries",
9293
np.nan,
9394
),
95+
"value_added": (
96+
"float64",
97+
"_value_added_evolution",
98+
"industries",
99+
np.nan,
100+
),
94101
"final_demand": ("float64", "_final_demand_evolution", "industries", np.nan),
95102
"intermediate_demand": (
96103
"float64",
@@ -209,6 +216,7 @@ def __init__(
209216
self._io_demand_evolution = np.array([])
210217
self._rebuild_demand_evolution = np.array([])
211218
self._overproduction_evolution = np.array([])
219+
self._value_added_evolution = np.array([])
212220
self._final_demand_unmet_evolution = np.array([])
213221
self._rebuild_production_evolution = np.array([])
214222
self._inputs_evolution = np.array([])
@@ -508,6 +516,10 @@ def next_step(
508516
"_io_demand_evolution" in self._vars_to_record
509517
):
510518
self._write_io_demand()
519+
if ("_value_added_evolution" in self._files_to_record) or (
520+
"_value_added_evolution" in self._vars_to_record
521+
):
522+
self._write_value_added()
511523

512524
# 1)
513525
constraints = self.model.calc_production(self.current_temporal_unit)
@@ -912,6 +924,8 @@ def update_rebuild_demand(self):
912924
* (evnt_trck._rebuild_id + 1),
913925
] = evnt_trck.distributed_reb_dem_house_tau
914926

927+
if np.isnan(_rebuilding_demand).any():
928+
raise ValueError("NaNs found when creating the rebuilding demand.")
915929
self.model.rebuild_demand = _rebuilding_demand
916930

917931
def update_productive_capital_lost(self):
@@ -1007,6 +1021,22 @@ def production_capacity(self) -> pd.DataFrame:
10071021
copy=True,
10081022
).rename_axis("step")
10091023

1024+
@property
1025+
def value_added(self) -> pd.DataFrame:
1026+
"""Returns the evolution of the production capacity of each industry (region,sector) as a DataFrame.
1027+
1028+
Returns
1029+
-------
1030+
pd.DataFrame: A pandas DataFrame where the value is the production capacity, the columns are the industries
1031+
and the index is the step considered.
1032+
1033+
"""
1034+
return pd.DataFrame(
1035+
self._value_added_evolution,
1036+
columns=self.model.industries,
1037+
copy=True,
1038+
).rename_axis("step")
1039+
10101040
@property
10111041
def final_demand(self) -> pd.DataFrame:
10121042
"""Return the evolution of final demand asked of each industry as a DataFrame.
@@ -1237,6 +1267,12 @@ def _write_production_max(self) -> None:
12371267
self.model.production_cap
12381268
)
12391269

1270+
def _write_value_added(self) -> None:
1271+
"""Saves the current production capacity vector to the memmap."""
1272+
self._value_added_evolution[self.current_temporal_unit] = (
1273+
self.model.production - self.model.intermediate_demand_tot
1274+
)
1275+
12401276
def _write_io_demand(self) -> None:
12411277
"""Saves the current (total per industry) intermediate demand vector to the memmap."""
12421278
self._io_demand_evolution[self.current_temporal_unit] = (
@@ -1508,16 +1544,20 @@ def _normalize_distribution(
15081544
ret.loc[addressed_to, :] = (
15091545
dist_sq.loc[addressed_to]
15101546
.groupby(level=1)
1511-
.transform(lambda x: x / sum(x))
1547+
.transform(lambda x: x / sum(x) if sum(x) != 0 else 0)
15121548
.values[:, None]
15131549
)
1550+
if np.isnan(ret).any(axis=None):
1551+
raise ValueError("The distribution contains NaNs")
15141552
return ret
15151553
elif isinstance(dist_sq, pd.DataFrame):
15161554
ret.loc[addressed_to, affected] = (
15171555
dist_sq.loc[addressed_to, affected]
15181556
.groupby(level=1)
1519-
.transform(lambda x: x / sum(x))
1557+
.transform(lambda x: x / sum(x) if sum(x) != 0 else 0)
15201558
)
1559+
if np.isnan(ret).any(axis=None):
1560+
raise ValueError("The distribution contains NaNs")
15211561
return ret
15221562
else:
15231563
raise ValueError("given distribution should be a Series or a DataFrame.")

docs/source/tutorials/boario-events.rst

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ Otherwise, production capacity is restored instantaneously after the duration of
204204
Defining events from a scalar
205205
================================
206206

207-
You can also define an event from a scalar impact
208-
(except for :class:`~boario.event.EventArbitraryProd`).
207+
You can also define an event from a scalar impact.
209208
This requires to define which industries are affected and
210209
how the impact is distributed among the industries.
211210

@@ -236,25 +235,16 @@ Otherwise, there are multiple ways to setup a custom distribution:
236235
of per affected industry share of the impact (although in this case you should
237236
probably directly give the impact vector).
238237
2. Give a vector of the share per region, and the share per sector.
239-
3. Give a vector of the share per region, and specify ``"gdp"`` for the per sector
240-
distribution. This will distribute each regional impact toward each affected sector
241-
proportionally to their share of the regional GDP among the affected sectors.
242-
For example: Suppose we look at the impact in region ``"reg2"``, and suppose
243-
``"manufactoring"`` and ``"mining"`` are both affected. Now suppose
244-
``"manufactoring"`` account for 40% of ``"reg2"``'s GDP and ``"mining"``
245-
for 10%. The ``"manufactoring"`` sector will receive :math:`(40 * 100) / (40 + 10) = 80\%`
246-
of the impact and ``"mining"`` the remaining :math:`(10 * 100) / (40 + 10) = 20\%`.
247238

248239
.. note::
249240

250-
The GDP shares are estimated from the MRIO table used, based on the Value Added,
251-
which itself is computed as the gross output minus the intermediate demand:
241+
Users often use the GVA shares to distribute the impact, which can be computed as the gross output minus the intermediate demand:
252242

253243
:math:`\textrm{GVA} = \iox - \ioz`
254244

255245
.. warning::
256246

257-
You should not assume the default impact distribution setting is a good representation
247+
You should not assume the default impact distribution (impact equaly distributed) setting is a good representation
258248
of the general case, as different regions and sectors are most probably differently
259249
impacted by an event. It is strongly advised to setup your own distribution in accordance
260250
with your study.

0 commit comments

Comments
 (0)