emerge 0.4.7__py3-none-any.whl → 0.4.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of emerge might be problematic. Click here for more details.
- emerge/__init__.py +14 -14
- emerge/_emerge/__init__.py +42 -0
- emerge/_emerge/bc.py +197 -0
- emerge/_emerge/coord.py +119 -0
- emerge/_emerge/cs.py +523 -0
- emerge/_emerge/dataset.py +36 -0
- emerge/_emerge/elements/__init__.py +19 -0
- emerge/_emerge/elements/femdata.py +212 -0
- emerge/_emerge/elements/index_interp.py +64 -0
- emerge/_emerge/elements/legrange2.py +172 -0
- emerge/_emerge/elements/ned2_interp.py +645 -0
- emerge/_emerge/elements/nedelec2.py +140 -0
- emerge/_emerge/elements/nedleg2.py +217 -0
- emerge/_emerge/geo/__init__.py +24 -0
- emerge/_emerge/geo/horn.py +107 -0
- emerge/_emerge/geo/modeler.py +449 -0
- emerge/_emerge/geo/operations.py +254 -0
- emerge/_emerge/geo/pcb.py +1244 -0
- emerge/_emerge/geo/pcb_tools/calculator.py +28 -0
- emerge/_emerge/geo/pcb_tools/macro.py +79 -0
- emerge/_emerge/geo/pmlbox.py +204 -0
- emerge/_emerge/geo/polybased.py +529 -0
- emerge/_emerge/geo/shapes.py +427 -0
- emerge/_emerge/geo/step.py +77 -0
- emerge/_emerge/geo2d.py +86 -0
- emerge/_emerge/geometry.py +510 -0
- emerge/_emerge/howto.py +214 -0
- emerge/_emerge/logsettings.py +5 -0
- emerge/_emerge/material.py +118 -0
- emerge/_emerge/mesh3d.py +730 -0
- emerge/_emerge/mesher.py +339 -0
- emerge/_emerge/mth/common_functions.py +33 -0
- emerge/_emerge/mth/integrals.py +71 -0
- emerge/_emerge/mth/optimized.py +357 -0
- emerge/_emerge/periodic.py +263 -0
- emerge/_emerge/physics/__init__.py +0 -0
- emerge/_emerge/physics/microwave/__init__.py +1 -0
- emerge/_emerge/physics/microwave/adaptive_freq.py +279 -0
- emerge/_emerge/physics/microwave/assembly/assembler.py +569 -0
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +448 -0
- emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +426 -0
- emerge/_emerge/physics/microwave/assembly/robinbc.py +433 -0
- emerge/_emerge/physics/microwave/microwave_3d.py +1150 -0
- emerge/_emerge/physics/microwave/microwave_bc.py +915 -0
- emerge/_emerge/physics/microwave/microwave_data.py +1148 -0
- emerge/_emerge/physics/microwave/periodic.py +82 -0
- emerge/_emerge/physics/microwave/port_functions.py +53 -0
- emerge/_emerge/physics/microwave/sc.py +175 -0
- emerge/_emerge/physics/microwave/simjob.py +147 -0
- emerge/_emerge/physics/microwave/sparam.py +138 -0
- emerge/_emerge/physics/microwave/touchstone.py +140 -0
- emerge/_emerge/plot/__init__.py +0 -0
- emerge/_emerge/plot/display.py +394 -0
- emerge/_emerge/plot/grapher.py +93 -0
- emerge/_emerge/plot/matplotlib/mpldisplay.py +264 -0
- emerge/_emerge/plot/pyvista/__init__.py +1 -0
- emerge/_emerge/plot/pyvista/display.py +931 -0
- emerge/_emerge/plot/pyvista/display_settings.py +24 -0
- emerge/_emerge/plot/simple_plots.py +551 -0
- emerge/_emerge/plot.py +225 -0
- emerge/_emerge/projects/__init__.py +0 -0
- emerge/_emerge/projects/_gen_base.txt +32 -0
- emerge/_emerge/projects/_load_base.txt +24 -0
- emerge/_emerge/projects/generate_project.py +40 -0
- emerge/_emerge/selection.py +596 -0
- emerge/_emerge/simmodel.py +444 -0
- emerge/_emerge/simulation_data.py +411 -0
- emerge/_emerge/solver.py +993 -0
- emerge/_emerge/system.py +54 -0
- emerge/cli.py +19 -0
- emerge/lib.py +1 -1
- emerge/plot.py +1 -1
- {emerge-0.4.7.dist-info → emerge-0.4.8.dist-info}/METADATA +1 -1
- emerge-0.4.8.dist-info/RECORD +78 -0
- emerge-0.4.8.dist-info/entry_points.txt +2 -0
- emerge-0.4.7.dist-info/RECORD +0 -9
- emerge-0.4.7.dist-info/entry_points.txt +0 -2
- {emerge-0.4.7.dist-info → emerge-0.4.8.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# EMerge is an open source Python based FEM EM simulation module.
|
|
2
|
+
# Copyright (C) 2025 Robert Fennis.
|
|
3
|
+
|
|
4
|
+
# This program is free software; you can redistribute it and/or
|
|
5
|
+
# modify it under the terms of the GNU General Public License
|
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
|
7
|
+
# of the License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see
|
|
16
|
+
# <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
import numpy as np
|
|
20
|
+
from loguru import logger
|
|
21
|
+
from typing import TypeVar, Generic, Any, List, Union, Dict
|
|
22
|
+
from collections import defaultdict
|
|
23
|
+
|
|
24
|
+
T = TypeVar("T")
|
|
25
|
+
M = TypeVar("M")
|
|
26
|
+
|
|
27
|
+
def assemble_nd_data(
|
|
28
|
+
data_in: List[Union[float, np.ndarray]],
|
|
29
|
+
vars_in: List[Dict[str, float]],
|
|
30
|
+
axes: Dict[str, List[float]],
|
|
31
|
+
) -> np.ndarray:
|
|
32
|
+
"""
|
|
33
|
+
Assemble a flat list of data entries into an N-dimensional array
|
|
34
|
+
based on provided axis definitions.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
data_in : List[float or np.ndarray]
|
|
39
|
+
Flat list of data entries. Scalars are treated as shape ().
|
|
40
|
+
vars_in : List[Dict[str, float]]
|
|
41
|
+
List of dictionaries mapping variable names to their value for each data entry.
|
|
42
|
+
Length must match data_in.
|
|
43
|
+
axes : Dict[str, List[float]]
|
|
44
|
+
Mapping from variable name to list of allowed values along that axis.
|
|
45
|
+
If 'freq' is a key, its axis will be placed last.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
np.ndarray
|
|
50
|
+
An array of shape (*axis_lengths, *shp_out), where axis_lengths correspond
|
|
51
|
+
to lengths of each axis in `axes` (with 'freq' last if present) and
|
|
52
|
+
shp_out is the shape of the first ndarray in data_in or () if all scalars.
|
|
53
|
+
"""
|
|
54
|
+
# Determine axis ordering
|
|
55
|
+
axis_names = sorted(list(axes.keys()))
|
|
56
|
+
if 'freq' in axis_names:
|
|
57
|
+
axis_names.append(axis_names.pop(axis_names.index('freq')))
|
|
58
|
+
axis_lengths = [len(axes[name]) for name in axis_names]
|
|
59
|
+
|
|
60
|
+
# Determine output shape suffix
|
|
61
|
+
# Assume all array entries share the same shape
|
|
62
|
+
first = next((d for d in data_in if isinstance(d, np.ndarray)), None)
|
|
63
|
+
shp_out = first.shape if isinstance(first, np.ndarray) else ()
|
|
64
|
+
|
|
65
|
+
# Initialize output array
|
|
66
|
+
out_shape = tuple(axis_lengths) + shp_out
|
|
67
|
+
out = np.empty(out_shape, dtype=first.dtype if isinstance(first, np.ndarray) else float)
|
|
68
|
+
|
|
69
|
+
# Fill in data
|
|
70
|
+
for entry, var_map in zip(data_in, vars_in):
|
|
71
|
+
# build index for each axis
|
|
72
|
+
idx = tuple(
|
|
73
|
+
axes[name].index(var_map[name])
|
|
74
|
+
for name in axis_names
|
|
75
|
+
)
|
|
76
|
+
if isinstance(entry, np.ndarray):
|
|
77
|
+
out[idx + tuple(slice(None) for _ in shp_out)] = entry
|
|
78
|
+
else:
|
|
79
|
+
out[idx] = entry
|
|
80
|
+
|
|
81
|
+
return out
|
|
82
|
+
|
|
83
|
+
def generate_ndim(
|
|
84
|
+
outer_data: dict[str, list[float]],
|
|
85
|
+
inner_data: list[float],
|
|
86
|
+
outer_labels: tuple[str, ...]
|
|
87
|
+
) -> np.ndarray:
|
|
88
|
+
"""
|
|
89
|
+
Generates an N-dimensional grid of values from flattened data, and returns each axis array plus the grid.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
outer_data : dict of {label: flat list of coordinates}
|
|
94
|
+
Each key corresponds to one axis label, and the list contains coordinate values for each point.
|
|
95
|
+
inner_data : list of float
|
|
96
|
+
Flattened list of data values corresponding to each set of coordinates.
|
|
97
|
+
outer_labels : tuple of str
|
|
98
|
+
Order of axes (keys of outer_data) which defines the dimension order in the output array.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
*axes : np.ndarray
|
|
103
|
+
One 1D array for each axis, containing the sorted unique coordinates for that dimension,
|
|
104
|
+
in the order specified by outer_labels.
|
|
105
|
+
grid : np.ndarray
|
|
106
|
+
N-dimensional array of shape (n1, n2, ..., nN), where ni is the number of unique
|
|
107
|
+
values along the i-th axis. Missing points are filled with np.nan.
|
|
108
|
+
"""
|
|
109
|
+
# Convert inner data to numpy array
|
|
110
|
+
values = np.asarray(inner_data)
|
|
111
|
+
|
|
112
|
+
# Determine unique sorted coordinates for each axis
|
|
113
|
+
axes = [np.unique(np.asarray(outer_data[label])) for label in outer_labels]
|
|
114
|
+
grid_shape = tuple(axis.size for axis in axes)
|
|
115
|
+
|
|
116
|
+
# Initialize grid with NaNs
|
|
117
|
+
grid = np.full(grid_shape, np.nan, dtype=values.dtype)
|
|
118
|
+
|
|
119
|
+
# Build coordinate arrays for each axis
|
|
120
|
+
coords = [np.asarray(outer_data[label]) for label in outer_labels]
|
|
121
|
+
|
|
122
|
+
# Map coordinates to indices in the grid for each axis
|
|
123
|
+
idxs = [np.searchsorted(axes[i], coords[i]) for i in range(len(axes))]
|
|
124
|
+
|
|
125
|
+
# Assign values into the grid
|
|
126
|
+
grid[tuple(idxs)] = values
|
|
127
|
+
|
|
128
|
+
# Return each axis array followed by the grid
|
|
129
|
+
return (*axes, grid)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class DataEntry:
|
|
133
|
+
|
|
134
|
+
def __init__(self, vars: dict[str, float]):
|
|
135
|
+
self.vars: dict[str, float] = vars
|
|
136
|
+
self.data: dict[str, Any] = dict()
|
|
137
|
+
|
|
138
|
+
def print(self) -> None:
|
|
139
|
+
"""Print the content of the DataEntry object"""
|
|
140
|
+
for key, value in self.data.items():
|
|
141
|
+
print(f' {key} = {value}')
|
|
142
|
+
|
|
143
|
+
def values(self) -> list[Any]:
|
|
144
|
+
""" Return all values stored in the DataEntry"""
|
|
145
|
+
return self.data.values()
|
|
146
|
+
|
|
147
|
+
def keys(self) -> list[str]:
|
|
148
|
+
""" Return all names of data stored in the DataEntry"""
|
|
149
|
+
return list(self.data.keys())
|
|
150
|
+
|
|
151
|
+
def items(self) -> list[tuple[str, Any]]:
|
|
152
|
+
""" Returns a list of all key: value pairs of the DataEntry."""
|
|
153
|
+
|
|
154
|
+
def __eq__(self, other: dict[str, float]) -> bool:
|
|
155
|
+
allkeys = set(list(self.vars.keys()) + list(other.keys()))
|
|
156
|
+
return all(self.vars[key]==other[key] for key in allkeys)
|
|
157
|
+
|
|
158
|
+
def _dist(self, other: dict[str, float]) -> bool:
|
|
159
|
+
return sum([(abs(self.vars.get(key,1e20)-other[key])/other[key]) for key in other.keys()])
|
|
160
|
+
|
|
161
|
+
def __getitem__(self, key) -> Any:
|
|
162
|
+
return self.data[key]
|
|
163
|
+
|
|
164
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
165
|
+
self.data[key] = value
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class DataContainer:
|
|
169
|
+
"""The DataContainer class is a generalized class to store data for a set of parameter sweeps"""
|
|
170
|
+
def __init__(self):
|
|
171
|
+
self.entries: list[DataEntry] = []
|
|
172
|
+
self.stock: DataEntry = DataEntry({})
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def print(self) -> None:
|
|
176
|
+
""" Print an overview of all data in the DataContainer"""
|
|
177
|
+
self.stock.print()
|
|
178
|
+
for entry in self.entries:
|
|
179
|
+
entry.print()
|
|
180
|
+
|
|
181
|
+
def new(self, **vars: float) -> DataEntry:
|
|
182
|
+
"""Create a new entry in the DataContainer for the given value setting"""
|
|
183
|
+
entry = DataEntry(vars)
|
|
184
|
+
self.entries.append(entry)
|
|
185
|
+
return entry
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def last(self) -> DataEntry:
|
|
189
|
+
"""Returns the last added entry"""
|
|
190
|
+
return self.entries[-1]
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def default(self) -> DataEntry:
|
|
194
|
+
"""Returns the default DataEntry which is either the last from the parameter sweep or the general one in case of no parameter sweep."""
|
|
195
|
+
if not self.entries:
|
|
196
|
+
return self.stock
|
|
197
|
+
else:
|
|
198
|
+
return self.last
|
|
199
|
+
|
|
200
|
+
def select(self, **vars: float) -> DataEntry | None:
|
|
201
|
+
"""Returns the data entry corresponding to the provided parametric sweep set"""
|
|
202
|
+
for entry in self.entries:
|
|
203
|
+
if entry==vars:
|
|
204
|
+
return entry
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
def find(self, **vars: float) -> DataEntry:
|
|
208
|
+
"""Returns the DataEntry closest to the provided parametric sweep setting."""
|
|
209
|
+
return sorted([(entry, entry._dist(vars)) for entry in self.entries], key=lambda x: x[1])[0][0]
|
|
210
|
+
|
|
211
|
+
def __getitem__(self, key: str) -> DataEntry:
|
|
212
|
+
"""Returns the requested item from the default DataEntry"""
|
|
213
|
+
return self.default[key]
|
|
214
|
+
|
|
215
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
216
|
+
"""Writes a value to the requested default DataEntry"""
|
|
217
|
+
self.default[key] = value
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class BaseDataset(Generic[T,M]):
|
|
221
|
+
def __init__(self, datatype: T, matrixtype: M, scalar: bool):
|
|
222
|
+
self._datatype: type[T] = datatype
|
|
223
|
+
self._matrixtype: type[M] = matrixtype
|
|
224
|
+
self._variables: list[dict[str, float]] = []
|
|
225
|
+
self._data_entries: list[T] = []
|
|
226
|
+
self._scalar: bool = scalar
|
|
227
|
+
|
|
228
|
+
self._gritted: bool = None
|
|
229
|
+
self._axes: dict[str, np.ndarray] = None
|
|
230
|
+
self._ax_ids: dict[str, int] = None
|
|
231
|
+
self._ids: np.ndarray = None
|
|
232
|
+
self._gridobj: M = None
|
|
233
|
+
|
|
234
|
+
self._data: dict[str, Any] = dict()
|
|
235
|
+
|
|
236
|
+
def __getitem__(self, index: int) -> T:
|
|
237
|
+
return self._data_entries[index]
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def _fields(self) -> list[str]:
|
|
241
|
+
return self._datatype._fields
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def _copy(self) -> list[str]:
|
|
245
|
+
return self._datatype._copy
|
|
246
|
+
|
|
247
|
+
def store(self, key: str, value: Any) -> None:
|
|
248
|
+
"""Stores a variable with some value in the provided key.
|
|
249
|
+
Make sure that all values passed are picklable.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
key (str): The name for the data entry
|
|
253
|
+
value (Any): The value of the data entry
|
|
254
|
+
"""
|
|
255
|
+
self._data[key] = value
|
|
256
|
+
|
|
257
|
+
def load(self, key: str) -> Any | None:
|
|
258
|
+
"""Returns the data entry for a given key
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
key (str): The name of the data entry
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Any: The value of the data entry
|
|
265
|
+
"""
|
|
266
|
+
return self._data.get(key, None)
|
|
267
|
+
|
|
268
|
+
def get_entry(self, index: int) -> T:
|
|
269
|
+
"""Returns the physics dataset for the given index
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
index (int): The index of the solution
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
T: The Physics dataset
|
|
276
|
+
"""
|
|
277
|
+
return self._data_entries[index]
|
|
278
|
+
|
|
279
|
+
def select(self, **variables: float) -> T:
|
|
280
|
+
"""Returns the first physics dataset that satisfies the variable assignemnt.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
T: The physics dataset
|
|
284
|
+
"""
|
|
285
|
+
index = next(
|
|
286
|
+
i
|
|
287
|
+
for i, var_map in enumerate(self._variables)
|
|
288
|
+
if all(var_map.get(k) == v for k, v in variables.items())
|
|
289
|
+
)
|
|
290
|
+
return self.get_entry(index)
|
|
291
|
+
|
|
292
|
+
def filter(self, **variables: float) -> list[T]:
|
|
293
|
+
"""Returns a list of all physics datasets that are valid for the given variable assignment
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
list[T]: A list of all matching datasets
|
|
297
|
+
"""
|
|
298
|
+
output = []
|
|
299
|
+
for i, var_map in enumerate(self._variables):
|
|
300
|
+
if all(var_map.get(k) == v for k, v in variables.items()):
|
|
301
|
+
output.append(self.get_entry(i))
|
|
302
|
+
return output
|
|
303
|
+
|
|
304
|
+
def find(self, **variables: float) -> T:
|
|
305
|
+
"""Returns the physics dataset that is closest to the constraint given by the variables.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
T: The physics dataset.
|
|
309
|
+
"""
|
|
310
|
+
output = []
|
|
311
|
+
for i, var_map in enumerate(self._variables):
|
|
312
|
+
error = sum([abs(var_map.get(k, 1e30) - v) for k, v in variables.items()])
|
|
313
|
+
output.append((i,error))
|
|
314
|
+
return self.get_entry(sorted(output, key=lambda x:x[1])[0][0])
|
|
315
|
+
|
|
316
|
+
def axis(self, name: str) -> np.ndarray:
|
|
317
|
+
"""Returns a sorted list of all variables for the given name
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
name (str): The name of the variable axis
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
np.ndarray: A sorted list of all unique values.
|
|
324
|
+
"""
|
|
325
|
+
return np.sort(np.unique(np.array([var[name] for var in self._variables])))
|
|
326
|
+
|
|
327
|
+
def new(self, **vars: float) -> T:
|
|
328
|
+
"""Creates a new dataset
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
T: The physics dataset object
|
|
332
|
+
"""
|
|
333
|
+
self._variables.append(vars)
|
|
334
|
+
new_entry = self._datatype()
|
|
335
|
+
self._data_entries.append(new_entry)
|
|
336
|
+
return new_entry
|
|
337
|
+
|
|
338
|
+
def _grid_axes(self) -> None:
|
|
339
|
+
"""This method attepmts to create a gritted version of the scalar dataset
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
None
|
|
343
|
+
"""
|
|
344
|
+
logger.debug('Attempting to grid simulation data')
|
|
345
|
+
variables = defaultdict(set)
|
|
346
|
+
for var in self._variables:
|
|
347
|
+
for key, value in var.items():
|
|
348
|
+
variables[key].add(value)
|
|
349
|
+
N_entries = len(self._variables)
|
|
350
|
+
N_prod = 1
|
|
351
|
+
N_dim = len(variables)
|
|
352
|
+
for key, val_list in variables.items():
|
|
353
|
+
N_prod *= len(val_list)
|
|
354
|
+
|
|
355
|
+
if N_entries == N_prod:
|
|
356
|
+
logger.debug('Multi-dimensional grid found!')
|
|
357
|
+
self._gritted = True
|
|
358
|
+
else:
|
|
359
|
+
logger.debug('Multi-dimensional grid not found')
|
|
360
|
+
self._gritted = False
|
|
361
|
+
return False
|
|
362
|
+
|
|
363
|
+
self._axes = dict()
|
|
364
|
+
self._ax_ids = dict()
|
|
365
|
+
revax = dict()
|
|
366
|
+
i = 0
|
|
367
|
+
for key, val_set in variables.items():
|
|
368
|
+
self._axes[key] = np.sort(np.array(list(val_set)))
|
|
369
|
+
self._ax_ids[key] = i
|
|
370
|
+
revax[i] = key
|
|
371
|
+
i += 1
|
|
372
|
+
|
|
373
|
+
axlist = []
|
|
374
|
+
|
|
375
|
+
for idim in range(N_dim):
|
|
376
|
+
axlist.append(self._axes[revax[idim]])
|
|
377
|
+
|
|
378
|
+
indices = np.arange(N_entries)
|
|
379
|
+
Ndimlist = [len(dim) for dim in axlist]
|
|
380
|
+
self._ids = indices.reshape(Ndimlist)
|
|
381
|
+
|
|
382
|
+
obj = self._matrixtype()
|
|
383
|
+
|
|
384
|
+
axes_list = {key: list(self._axes[key]) for key in self._axes.keys()}
|
|
385
|
+
for field in self._fields:
|
|
386
|
+
data_field = [self._data_entries[i].__dict__[field] for i in range(N_entries)]
|
|
387
|
+
data_set = assemble_nd_data(data_field, self._variables, axes_list)
|
|
388
|
+
obj.__setattr__(field, data_set)
|
|
389
|
+
for copyfield in self._copy:
|
|
390
|
+
|
|
391
|
+
obj.__setattr__(copyfield, self._data_entries[0].__dict__[copyfield])
|
|
392
|
+
self._gridobj = obj
|
|
393
|
+
|
|
394
|
+
return True
|
|
395
|
+
|
|
396
|
+
@property
|
|
397
|
+
def grid(self) -> M:
|
|
398
|
+
"""Returns the gridded version of the scalar dataset.
|
|
399
|
+
|
|
400
|
+
Raises:
|
|
401
|
+
ValueError: _description_
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
M: The gritted physics dataset
|
|
405
|
+
"""
|
|
406
|
+
if self._gritted is None:
|
|
407
|
+
self._grid_axes()
|
|
408
|
+
if self._gritted is False:
|
|
409
|
+
logger.error('The dataset cannot be cast to a structured grid.')
|
|
410
|
+
raise ValueError('Data not in regular grid')
|
|
411
|
+
return self._gridobj
|