| Conditions | 7 |
| Total Lines | 113 |
| Code Lines | 71 |
| 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:
| 1 | """ |
||
| 100 | def evaluate_df(self, df, ctx): |
||
| 101 | """ |
||
| 102 | Evaluate the comparison between storage and building data. |
||
| 103 | |||
| 104 | Parameters |
||
| 105 | ---------- |
||
| 106 | df : pd.DataFrame |
||
| 107 | DataFrame with storage and building data per bus |
||
| 108 | ctx : dict |
||
| 109 | Context information |
||
| 110 | |||
| 111 | Returns |
||
| 112 | ------- |
||
| 113 | RuleResult |
||
| 114 | Validation result with success/failure status |
||
| 115 | """ |
||
| 116 | if df.empty: |
||
| 117 | return RuleResult( |
||
| 118 | rule_id=self.rule_id, |
||
| 119 | task=self.task, |
||
| 120 | table=self.table, |
||
| 121 | kind=self.kind, |
||
| 122 | success=False, |
||
| 123 | message=f"No home battery data found for scenario {self.scenario}", |
||
| 124 | severity=Severity.WARNING, |
||
| 125 | schema=self.schema, |
||
| 126 | table_name=self.table_name, |
||
| 127 | rule_class=self.__class__.__name__ |
||
| 128 | ) |
||
| 129 | |||
| 130 | # Check for buses that exist in only one source |
||
| 131 | missing_in_storage = df[df["storage_p_nom"].isna()] |
||
| 132 | missing_in_buildings = df[df["building_p_nom"].isna()] |
||
| 133 | |||
| 134 | if not missing_in_storage.empty or not missing_in_buildings.empty: |
||
| 135 | violations = [] |
||
| 136 | if not missing_in_storage.empty: |
||
| 137 | violations.append( |
||
| 138 | f"{len(missing_in_storage)} bus(es) in buildings but not in storage: " |
||
| 139 | f"{missing_in_storage['bus_id'].tolist()[:5]}" |
||
| 140 | ) |
||
| 141 | if not missing_in_buildings.empty: |
||
| 142 | violations.append( |
||
| 143 | f"{len(missing_in_buildings)} bus(es) in storage but not in buildings: " |
||
| 144 | f"{missing_in_buildings['bus_id'].tolist()[:5]}" |
||
| 145 | ) |
||
| 146 | |||
| 147 | return RuleResult( |
||
| 148 | rule_id=self.rule_id, |
||
| 149 | task=self.task, |
||
| 150 | table=self.table, |
||
| 151 | kind=self.kind, |
||
| 152 | success=False, |
||
| 153 | observed=len(missing_in_storage) + len(missing_in_buildings), |
||
| 154 | expected=0, |
||
| 155 | message=f"Bus mismatch between tables: {'; '.join(violations)}", |
||
| 156 | severity=Severity.ERROR, |
||
| 157 | schema=self.schema, |
||
| 158 | table_name=self.table_name, |
||
| 159 | rule_class=self.__class__.__name__ |
||
| 160 | ) |
||
| 161 | |||
| 162 | # Check if p_nom values match |
||
| 163 | p_nom_mismatch = df[df["storage_p_nom"] != df["building_p_nom"]] |
||
| 164 | |||
| 165 | # Check if capacity values match |
||
| 166 | capacity_mismatch = df[df["storage_capacity"] != df["building_capacity"]] |
||
| 167 | |||
| 168 | # Combine mismatches |
||
| 169 | mismatches = pd.concat([p_nom_mismatch, capacity_mismatch]).drop_duplicates(subset=["bus_id"]) |
||
| 170 | |||
| 171 | if not mismatches.empty: |
||
| 172 | # Calculate maximum differences |
||
| 173 | max_p_nom_diff = (df["storage_p_nom"] - df["building_p_nom"]).abs().max() |
||
| 174 | max_capacity_diff = (df["storage_capacity"] - df["building_capacity"]).abs().max() |
||
| 175 | |||
| 176 | # Get all violations |
||
| 177 | all_violations = mismatches[ |
||
| 178 | ["bus_id", "storage_p_nom", "building_p_nom", "storage_capacity", "building_capacity"] |
||
| 179 | ].to_dict(orient="records") |
||
| 180 | |||
| 181 | return RuleResult( |
||
| 182 | rule_id=self.rule_id, |
||
| 183 | task=self.task, |
||
| 184 | table=self.table, |
||
| 185 | kind=self.kind, |
||
| 186 | success=False, |
||
| 187 | observed=float(max(max_p_nom_diff, max_capacity_diff)), |
||
| 188 | expected=0.0, |
||
| 189 | message=( |
||
| 190 | f"Home battery aggregation mismatch for {len(mismatches)} bus(es): " |
||
| 191 | f"max p_nom diff={max_p_nom_diff:.6f}, max capacity diff={max_capacity_diff:.6f}. " |
||
| 192 | f"violations: {all_violations}" |
||
| 193 | ), |
||
| 194 | severity=Severity.ERROR, |
||
| 195 | schema=self.schema, |
||
| 196 | table_name=self.table_name, |
||
| 197 | rule_class=self.__class__.__name__ |
||
| 198 | ) |
||
| 199 | |||
| 200 | # All checks passed |
||
| 201 | return RuleResult( |
||
| 202 | rule_id=self.rule_id, |
||
| 203 | task=self.task, |
||
| 204 | table=self.table, |
||
| 205 | kind=self.kind, |
||
| 206 | success=True, |
||
| 207 | observed=0.0, |
||
| 208 | expected=0.0, |
||
| 209 | message=f"Home battery capacities correctly aggregated for all {len(df)} buses in scenario {self.scenario}", |
||
| 210 | schema=self.schema, |
||
| 211 | table_name=self.table_name, |
||
| 212 | rule_class=self.__class__.__name__ |
||
| 213 | ) |