Skip to content

Commit 375a885

Browse files
committed
add output generation
1 parent 25fd94c commit 375a885

File tree

6 files changed

+141
-6
lines changed

6 files changed

+141
-6
lines changed

ods_tools/combine/combine.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import logging
55

66
from ods_tools.combine.grouping import ResultGroup, create_combine_group
7-
from ods_tools.combine.io import get_default_output_dir, save_summary_info
7+
from ods_tools.combine.io import get_default_output_dir, save_output, save_summary_info
8+
from ods_tools.combine.output_generation import generate_alt, generate_ept
89
from ods_tools.combine.result import load_analysis_dirs
910
from ods_tools.combine.sampling import do_loss_sampling, generate_group_periods, generate_gpqt
1011
from ods_tools.combine.common import DEFAULT_CONFIG
@@ -43,6 +44,11 @@ def combine(analysis_dirs,
4344
group_format_priority=['M', 'Q', 'S'],
4445
group_correlation=None,
4546
occ_dtype=None,
47+
group_plt=False,
48+
group_alt=False,
49+
group_ept=False,
50+
group_ept_oep=True,
51+
group_ept_aep=True,
4652
output_dir=None,
4753
**kwargs
4854
):
@@ -88,6 +94,23 @@ def combine(analysis_dirs,
8894
# Output generation
8995
logger.info("Running: Output Generation")
9096

97+
outputs = []
98+
99+
if group_plt:
100+
outputs.append(('plt', gplt))
101+
102+
if group_alt:
103+
outputs.append(('alt', generate_alt(gplt, group_number_of_periods)))
104+
105+
if group_ept:
106+
outputs.append(('ept',
107+
generate_ept(gplt, group_number_of_periods,
108+
oep=group_ept_oep,
109+
aep=group_ept_aep)))
110+
111+
for output_name, output_df in outputs:
112+
save_output(output_df, output_dir, f'{output_name}.csv')
113+
91114
return gplt
92115

93116

ods_tools/combine/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44

55
oasis_int = np.dtype(os.environ.get('OASIS_INT', 'i4'))
6+
oasis_float = np.dtype(os.environ.get('OASIS_FLOAT', 'f4'))
67
nb_oasis_int = nb.from_dtype(oasis_int)
78

89
DEFAULT_RANDOM_SEED = 8762

ods_tools/combine/config.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
"group_number_of_periods": 100000,
44
"group_mean": true,
55
"group_secondary_uncertainty": true,
6-
"group_format_priority": ["M", "Q", "S"]
6+
"group_format_priority": ["M", "Q", "S"],
7+
"group_plt": true,
8+
"group_alt": true,
9+
"group_ept": true
710
}

ods_tools/combine/config_schema.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@
114114
"type": "boolean",
115115
"default": false
116116
},
117+
"group_ept_oep": {
118+
"title": "group_ept_oep",
119+
"description": "Output grouped EPT with OEP if group_ept",
120+
"type": "boolean",
121+
"default": true
122+
},
123+
"group_ept_aep": {
124+
"title": "group_ept_aep",
125+
"description": "Output grouped EPT with AEP if group_ept",
126+
"type": "boolean",
127+
"default": true
128+
},
117129
"group_plt": {
118130
"title": "group_plt",
119131
"description": "Output grouped PLT report",

ods_tools/combine/io.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
import logging
88
from datetime import datetime
99
import pandas as pd
10-
import os
1110

12-
from ods_tools.combine.common import nb_oasis_int
11+
from ods_tools.combine.common import nb_oasis_int, oasis_float
1312

1413
logger = logging.getLogger(__name__)
1514

16-
oasis_float = np.dtype(os.environ.get('OASIS_FLOAT', 'f4'))
1715

1816
DEFAULT_OCC_DTYPE = [('event_id', 'i4'),
1917
('period_no', 'i4'),
@@ -37,11 +35,21 @@ def save_summary_info(groupset_summaryinfo, groupset_info, output_dir):
3735

3836
for gs, g_summary_info_df in groupset_summaryinfo.items():
3937
summary_info_fname = f'{groupset_info[gs]['perspective_code']}_GS{gs}_summary-info.csv'
40-
g_summary_info_df.to_csv(Path(output_dir) / summary_info_fname, index=False)
38+
save_path = Path(output_dir) / summary_info_fname
39+
g_summary_info_df.to_csv(save_path, index=False)
40+
logger.info(f'Saved {summary_info_fname}: ', save_path)
4141

4242

43+
def save_output(full_df, output_dir, output_name, factor_col='groupset_id', float_format='%.6f'):
44+
for i in full_df[factor_col].unique():
45+
save_path = output_dir / f'{i}_{output_name}'
46+
full_df.query(f"{factor_col} == {i}").to_csv(save_path, index=False,
47+
float_format=float_format)
48+
logger.info(f'Saved {output_name}: ', save_path)
49+
4350
# occurrence reading functions from oasislmf -> copied to avoid circular imports
4451

52+
4553
@nb.jit(nopython=True, cache=True)
4654
def mv_read(byte_mv, cursor, _dtype, itemsize):
4755
"""
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import pandas as pd
2+
import numpy as np
3+
4+
from ods_tools.combine.common import oasis_float
5+
6+
dtypes_al = {
7+
'groupset_id': 'i4',
8+
'SummaryId': 'i4',
9+
'LossType': 'i4',
10+
'Mean': oasis_float,
11+
'Std': oasis_float
12+
13+
}
14+
15+
dtypes_ep = {
16+
'groupset_id': 'i4',
17+
'SummaryId': 'i4',
18+
'EPCalc': 'i4',
19+
'EPType': 'i4',
20+
'RP': oasis_float,
21+
'Loss': oasis_float
22+
}
23+
24+
25+
def generate_alt(gplt, max_period):
26+
# TODO: mean loss sampling results in inf + NaN values
27+
aal_group = gplt.groupby(by=["groupset_id", "SummaryId", "LossType"], as_index=False)
28+
29+
records = []
30+
for name, group in aal_group:
31+
mean_loss = group["Loss"].sum() / max_period
32+
std_loss = np.sqrt(((mean_loss - group["Loss"])**2).sum() / (max_period - 1))
33+
34+
record = {
35+
"groupset_id": name[0],
36+
"SummaryId": name[1],
37+
"LossType": name[2],
38+
"Mean": mean_loss,
39+
"Std": std_loss
40+
}
41+
42+
records.append(record)
43+
44+
return pd.DataFrame(records).astype(dtypes_al)
45+
46+
47+
def assign_exceedance_probability(df, max_period):
48+
original_cols = list(df.columns)
49+
df["rank"] = (df.groupby(by=["groupset_id", "SummaryId", "EPCalc"], as_index=False)["Loss"]
50+
.rank(method="first", ascending=False))
51+
df["RP"] = max_period / df["rank"]
52+
return df[original_cols + ["RP"]]
53+
54+
55+
def generate_ept(gplt, max_group_period, oep=True, aep=True):
56+
ep_groups = (
57+
gplt.rename(columns={"LossType": "EPCalc"}) # check if this is the correct type
58+
.groupby(by=["groupset_id", "groupeventset_id",
59+
"EventId", "GroupPeriod", "SummaryId",
60+
"EPCalc"], as_index=False)
61+
)
62+
grouped_df = ep_groups["Loss"].agg("sum")
63+
grouped_df = grouped_df.groupby(by=["groupset_id", "SummaryId", "GroupPeriod", "EPCalc"], as_index=False)
64+
65+
ep_frags = []
66+
if oep:
67+
oep_df = (
68+
grouped_df.pipe(lambda gp: gp["Loss"].max())
69+
.pipe(assign_exceedance_probability, max_period=max_group_period)
70+
.pipe(lambda x: x.assign(EPType=1)) # todo check OEP TVAR EPCalc 2
71+
)
72+
73+
ep_frags.append(oep_df)
74+
75+
if aep:
76+
aep_df = (
77+
grouped_df.pipe(lambda gp: gp["Loss"].sum())
78+
.pipe(assign_exceedance_probability, max_period=max_group_period)
79+
.pipe(lambda x: x.assign(EPType=3)) # todo check AEP TVAR EPCalc 4
80+
)
81+
ep_frags.append(aep_df)
82+
83+
return (
84+
pd.concat(ep_frags)[["groupset_id", "SummaryId", "EPCalc", "EPType", "RP", "Loss"]]
85+
.astype(dtypes_ep)
86+
.sort_values(by=["groupset_id", "SummaryId", "EPType", "EPCalc", "Loss"],
87+
ascending=[True, True, True, True, False])
88+
)

0 commit comments

Comments
 (0)