Conditions | 10 |
Total Lines | 105 |
Code Lines | 53 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like data.datasets.storages.home_batteries.allocate_home_batteries_to_buildings() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | from loguru import logger |
||
36 | def allocate_home_batteries_to_buildings(): |
||
37 | """ |
||
38 | Allocate home battery storage systems to buildings with pv rooftop systems |
||
39 | """ |
||
40 | # get constants |
||
41 | constants = config.datasets()["home_batteries"]["constants"] |
||
42 | scenarios = constants["scenarios"] |
||
43 | cbat_ppv_ratio = constants["cbat_ppv_ratio"] |
||
44 | rtol = constants["rtol"] |
||
45 | max_it = constants["max_it"] |
||
46 | cbat_pbat_ratio = get_cbat_pbat_ratio() |
||
47 | |||
48 | sources = config.datasets()["home_batteries"]["sources"] |
||
49 | |||
50 | df_list = [] |
||
51 | |||
52 | for scenario in scenarios: |
||
53 | # get home battery capacity per mv grid id |
||
54 | sql = f""" |
||
55 | SELECT el_capacity as p_nom_min, bus_id as bus FROM |
||
56 | {sources["storage"]["schema"]} |
||
57 | .{sources["storage"]["table"]} |
||
58 | WHERE carrier = 'home_battery' |
||
59 | AND scenario = '{scenario}'; |
||
60 | """ |
||
61 | |||
62 | home_batteries_df = db.select_dataframe(sql) |
||
63 | |||
64 | home_batteries_df = home_batteries_df.assign( |
||
65 | bat_cap=home_batteries_df.p_nom_min * cbat_pbat_ratio |
||
66 | ) |
||
67 | |||
68 | sql = """ |
||
69 | SELECT building_id, capacity |
||
70 | FROM supply.egon_power_plants_pv_roof_building |
||
71 | WHERE scenario = '{}' |
||
72 | AND bus_id = {} |
||
73 | """ |
||
74 | |||
75 | for bus_id, bat_cap in home_batteries_df[ |
||
76 | ["bus", "bat_cap"] |
||
77 | ].itertuples(index=False): |
||
78 | pv_df = db.select_dataframe(sql.format(scenario, bus_id)) |
||
79 | |||
80 | grid_ratio = bat_cap / pv_df.capacity.sum() |
||
81 | |||
82 | if grid_ratio > cbat_ppv_ratio: |
||
83 | logger.warning( |
||
84 | f"In Grid {bus_id} and scenario {scenario}, the ratio of " |
||
85 | f"home storage capacity to pv rooftop capacity is above 1" |
||
86 | f" ({grid_ratio: g}). The storage capacity of pv rooftop " |
||
87 | f"systems will be high." |
||
88 | ) |
||
89 | |||
90 | if grid_ratio < cbat_ppv_ratio: |
||
91 | random_state = RandomState(seed=bus_id) |
||
92 | |||
93 | n = max(int(len(pv_df) * grid_ratio), 1) |
||
94 | |||
95 | best_df = pv_df.sample(n=n, random_state=random_state) |
||
96 | |||
97 | i = 0 |
||
98 | |||
99 | while ( |
||
100 | not np.isclose(best_df.capacity.sum(), bat_cap, rtol=rtol) |
||
101 | and i < max_it |
||
102 | ): |
||
103 | sample_df = pv_df.sample(n=n, random_state=random_state) |
||
104 | |||
105 | if abs(best_df.capacity.sum() - bat_cap) > abs( |
||
106 | sample_df.capacity.sum() - bat_cap |
||
107 | ): |
||
108 | best_df = sample_df.copy() |
||
109 | |||
110 | i += 1 |
||
111 | |||
112 | if sample_df.capacity.sum() < bat_cap: |
||
113 | n = min(n + 1, len(pv_df)) |
||
114 | else: |
||
115 | n = max(n - 1, 1) |
||
116 | |||
117 | if not np.isclose(best_df.capacity.sum(), bat_cap, rtol=rtol): |
||
118 | logger.warning( |
||
119 | f"No suitable generators could be found in Grid " |
||
120 | f"{bus_id} and scenario {scenario} to achieve the " |
||
121 | f"desired ratio between battery capacity and pv " |
||
122 | f"rooftop capacity. The ratio will be " |
||
123 | f"{bat_cap / best_df.capacity.sum()}." |
||
124 | ) |
||
125 | |||
126 | pv_df = best_df.copy() |
||
127 | |||
128 | bat_df = pv_df.drop(columns=["capacity"]).assign( |
||
129 | capacity=pv_df.capacity / pv_df.capacity.sum() * bat_cap, |
||
130 | p_nom=pv_df.capacity |
||
131 | / pv_df.capacity.sum() |
||
132 | * bat_cap |
||
133 | / cbat_pbat_ratio, |
||
134 | scenario=scenario, |
||
135 | bus_id=bus_id, |
||
136 | ) |
||
137 | |||
138 | df_list.append(bat_df) |
||
139 | |||
140 | create_table(pd.concat(df_list, ignore_index=True)) |
||
141 | |||
171 |