-
Notifications
You must be signed in to change notification settings - Fork 9
Feature/test math+more #600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0d79826
3aaa5c7
4fdc445
26ababd
8524d32
19ce60f
35bb383
c5f64fa
4a57b73
4bd9143
c14dc00
6e5082c
0bdc30f
92f14b9
314b0fa
6f8788e
6ae5d03
7e4347f
b7a30e6
2eb528f
5caffd1
16eae3d
31a5964
4a57282
57c6fc9
ce318e9
ae6afb6
efad9c9
78ed286
b4942dd
4b91731
e89150b
ba0f94f
24fcd58
f80885b
68850eb
e5be97e
fa3de4e
96124b2
d71f85e
3710435
79c4288
0eeb8ab
6387a29
f73c346
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,69 @@ | |
| _CASE_SLOTS = frozenset(slot for slots in SLOT_ORDERS.values() for slot in slots) | ||
|
|
||
|
|
||
| def _extract_nonindex_coords(datasets: list[xr.Dataset]) -> tuple[list[xr.Dataset], dict[str, tuple[str, dict]]]: | ||
| """Extract and merge non-index coords, returning cleaned datasets and merged mappings. | ||
|
|
||
| Non-index coords (like `component` on `contributor` dim) cause concat conflicts. | ||
| This extracts them, merges the mappings, and returns datasets without them. | ||
| """ | ||
| if not datasets: | ||
| return datasets, {} | ||
|
|
||
| # Find non-index coords and collect mappings | ||
| merged: dict[str, tuple[str, dict]] = {} | ||
| coords_to_drop: set[str] = set() | ||
|
|
||
| for ds in datasets: | ||
| for name, coord in ds.coords.items(): | ||
| if len(coord.dims) != 1: | ||
| continue | ||
| dim = coord.dims[0] | ||
| if dim == name or dim not in ds.coords: | ||
| continue | ||
|
|
||
| coords_to_drop.add(name) | ||
| if name not in merged: | ||
| merged[name] = (dim, {}) | ||
| elif merged[name][0] != dim: | ||
| warnings.warn( | ||
| f"Coordinate '{name}' appears on different dims: " | ||
| f"'{merged[name][0]}' vs '{dim}'. Dropping this coordinate.", | ||
| stacklevel=4, | ||
| ) | ||
| continue | ||
|
|
||
| for dv, cv in zip(ds.coords[dim].values, coord.values, strict=False): | ||
| if dv not in merged[name][1]: | ||
| merged[name][1][dv] = cv | ||
| elif merged[name][1][dv] != cv: | ||
| warnings.warn( | ||
| f"Coordinate '{name}' has conflicting values for dim value '{dv}': " | ||
| f"'{merged[name][1][dv]}' vs '{cv}'. Keeping first value.", | ||
| stacklevel=4, | ||
| ) | ||
|
|
||
| # Drop these coords from datasets | ||
| if coords_to_drop: | ||
| datasets = [ds.drop_vars(coords_to_drop, errors='ignore') for ds in datasets] | ||
|
|
||
| return datasets, merged | ||
|
Comment on lines
32
to
78
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Warn when the same non‑index coord name binds to different dims. If a later dataset has the same coord name on a different dimension, the merge silently keeps the first dim and the coord can be dropped or misapplied. Consider detecting this and warning/short‑circuiting to avoid silent data loss.
|
||
|
|
||
|
|
||
| def _apply_merged_coords(ds: xr.Dataset, merged: dict[str, tuple[str, dict]]) -> xr.Dataset: | ||
| """Apply merged coord mappings to concatenated dataset.""" | ||
| if not merged: | ||
| return ds | ||
|
|
||
| new_coords = {} | ||
| for name, (dim, mapping) in merged.items(): | ||
| if dim not in ds.dims: | ||
| continue | ||
| new_coords[name] = (dim, [mapping.get(dv, dv) for dv in ds.coords[dim].values]) | ||
|
|
||
| return ds.assign_coords(new_coords) | ||
|
|
||
|
|
||
| def _apply_slot_defaults(plotly_kwargs: dict, defaults: dict[str, str | None]) -> None: | ||
| """Apply default slot assignments to plotly kwargs. | ||
|
|
||
|
|
@@ -256,12 +319,10 @@ def solution(self) -> xr.Dataset: | |
| self._require_solutions() | ||
| datasets = [fs.solution for fs in self._systems] | ||
| self._warn_mismatched_dimensions(datasets) | ||
| self._solution = xr.concat( | ||
| [ds.expand_dims(case=[name]) for ds, name in zip(datasets, self._names, strict=True)], | ||
| dim='case', | ||
| join='outer', | ||
| fill_value=float('nan'), | ||
| ) | ||
| expanded = [ds.expand_dims(case=[name]) for ds, name in zip(datasets, self._names, strict=True)] | ||
| expanded, merged_coords = _extract_nonindex_coords(expanded) | ||
| result = xr.concat(expanded, dim='case', join='outer', coords='minimal', fill_value=float('nan')) | ||
| self._solution = _apply_merged_coords(result, merged_coords) | ||
| return self._solution | ||
|
|
||
| @property | ||
|
|
@@ -324,12 +385,10 @@ def inputs(self) -> xr.Dataset: | |
| if self._inputs is None: | ||
| datasets = [fs.to_dataset(include_solution=False) for fs in self._systems] | ||
| self._warn_mismatched_dimensions(datasets) | ||
| self._inputs = xr.concat( | ||
| [ds.expand_dims(case=[name]) for ds, name in zip(datasets, self._names, strict=True)], | ||
| dim='case', | ||
| join='outer', | ||
| fill_value=float('nan'), | ||
| ) | ||
| expanded = [ds.expand_dims(case=[name]) for ds, name in zip(datasets, self._names, strict=True)] | ||
| expanded, merged_coords = _extract_nonindex_coords(expanded) | ||
| result = xr.concat(expanded, dim='case', join='outer', coords='minimal', fill_value=float('nan')) | ||
| self._inputs = _apply_merged_coords(result, merged_coords) | ||
| return self._inputs | ||
|
|
||
|
|
||
|
|
@@ -374,7 +433,9 @@ def _concat_property(self, prop_name: str) -> xr.Dataset: | |
| continue | ||
| if not datasets: | ||
| return xr.Dataset() | ||
| return xr.concat(datasets, dim='case', join='outer', fill_value=float('nan')) | ||
| datasets, merged_coords = _extract_nonindex_coords(datasets) | ||
| result = xr.concat(datasets, dim='case', join='outer', coords='minimal', fill_value=float('nan')) | ||
| return _apply_merged_coords(result, merged_coords) | ||
|
|
||
| def _merge_dict_property(self, prop_name: str) -> dict[str, str]: | ||
| """Merge a dict property from all cases (later cases override).""" | ||
|
|
@@ -528,7 +589,9 @@ def _combine_data(self, method_name: str, *args, **kwargs) -> tuple[xr.Dataset, | |
| if not datasets: | ||
| return xr.Dataset(), '' | ||
|
|
||
| return xr.concat(datasets, dim='case', join='outer', fill_value=float('nan')), title | ||
| datasets, merged_coords = _extract_nonindex_coords(datasets) | ||
| combined = xr.concat(datasets, dim='case', join='outer', coords='minimal', fill_value=float('nan')) | ||
| return _apply_merged_coords(combined, merged_coords), title | ||
|
|
||
| def _finalize(self, ds: xr.Dataset, fig, show: bool | None) -> PlotResult: | ||
| """Handle show and return PlotResult.""" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix MD046: use indented code blocks instead of fenced blocks.
markdownlint expects indented blocks in these sections (before_solve, cluster_mode, from_old_dataset). Please convert the fenced blocks accordingly.
🛠️ Sample fix (apply similarly to the other blocks)
Also applies to: 352-358, 376-378
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 332-332: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
🤖 Prompt for AI Agents