fmdtools 2.1.2__tar.gz → 2.1.3__tar.gz
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.
- {fmdtools-2.1.2 → fmdtools-2.1.3}/LICENSE +1 -1
- {fmdtools-2.1.2 → fmdtools-2.1.3}/PKG-INFO +5 -5
- {fmdtools-2.1.2 → fmdtools-2.1.3}/README.md +3 -3
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/rover_model.py +8 -3
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/__init__.py +1 -1
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/history.py +14 -6
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/result.py +1 -1
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/base.py +4 -6
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/geom.py +33 -5
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/base.py +3 -2
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/environment.py +15 -8
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/object/base.py +4 -1
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/object/geom.py +147 -74
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools.egg-info/PKG-INFO +5 -5
- {fmdtools-2.1.2 → fmdtools-2.1.3}/pyproject.toml +1 -1
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/asg_demo/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/asg_demo/demo_model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/eps/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/eps/eps.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/eps/test_eps.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multiflow_demo/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multiflow_demo/multiflow_demo.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multiflow_demo/test_multiflow.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/drone_mdl_dynamic.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/drone_mdl_hierarchical.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/drone_mdl_rural.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/drone_mdl_static.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/drone_mdl_urban.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/opt_drone_rural.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/multirotor/test_multirotor.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/ex_pump.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/jointfaults_ex.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/parallelism_methods.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/pump_indiv.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/pump_stochastic.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/test_pump.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/test_pump_example.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/pump/test_pump_stochastic.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/optimization/ea_analysis.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/optimization/search_rover.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/rover_degradation.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/rover_mode_space.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/rover_model_human.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/rover/test_rover.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/tank/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/tank/tank_model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/tank/tank_optimization_model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/tank/test_tank.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/ATC.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/asset.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/common.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/test_asset.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/examples/taxiway/test_model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/common.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/graph/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/graph/base.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/graph/label.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/graph/model.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/graph/style.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/phases.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/analyze/tabulate.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/action.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/component.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/architecture/function.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/base.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/block/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/block/action.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/block/base.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/block/component.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/block/function.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/mode.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/parameter.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/rand.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/state.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/container/time.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/flow/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/flow/base.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/flow/commsflow.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/flow/multiflow.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/object/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/object/coords.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/define/object/timer.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/sim/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/sim/propagate.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/sim/sample.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/sim/scenario.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools/sim/search.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools.egg-info/SOURCES.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools.egg-info/dependency_links.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools.egg-info/requires.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/fmdtools.egg-info/top_level.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/setup.cfg +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/tests/test_graph.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/tests/test_hierarchical.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.1.3}/tests/test_packages.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmdtools
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: System resilience modelling, simulation, and assessment in Python
|
|
5
5
|
Author: fmdtools Developers
|
|
6
6
|
Maintainer-email: Daniel Hulse <daniel.e.hulse@nasa.gov>
|
|
7
|
-
License: fmdtools version 2.1.
|
|
7
|
+
License: fmdtools version 2.1.3
|
|
8
8
|
---------------------------
|
|
9
9
|
Apache License
|
|
10
10
|
Version 2.0, January 2004
|
|
@@ -367,7 +367,7 @@ This may then be installed using:
|
|
|
367
367
|
Note that this version reflects the latest version on the ``main`` git branch along with any local changes. To use a particular version of ``fmdtools`` you can checkout the tag corresponding to the version you want, e.g.:
|
|
368
368
|
|
|
369
369
|
```
|
|
370
|
-
git checkout v2.1.
|
|
370
|
+
git checkout v2.1.3
|
|
371
371
|
```
|
|
372
372
|
|
|
373
373
|
|
|
@@ -505,8 +505,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
505
505
|
author = {{NASA}},
|
|
506
506
|
title = {fmdtools},
|
|
507
507
|
url = {https://github.com/nasa/fmdtools},
|
|
508
|
-
version = {2.1.
|
|
509
|
-
date = {2025-
|
|
508
|
+
version = {2.1.3},
|
|
509
|
+
date = {2025-6-6},
|
|
510
510
|
}
|
|
511
511
|
```
|
|
512
512
|
|
|
@@ -106,7 +106,7 @@ This may then be installed using:
|
|
|
106
106
|
Note that this version reflects the latest version on the ``main`` git branch along with any local changes. To use a particular version of ``fmdtools`` you can checkout the tag corresponding to the version you want, e.g.:
|
|
107
107
|
|
|
108
108
|
```
|
|
109
|
-
git checkout v2.1.
|
|
109
|
+
git checkout v2.1.3
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
|
|
@@ -244,8 +244,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
244
244
|
author = {{NASA}},
|
|
245
245
|
title = {fmdtools},
|
|
246
246
|
url = {https://github.com/nasa/fmdtools},
|
|
247
|
-
version = {2.1.
|
|
248
|
-
date = {2025-
|
|
247
|
+
version = {2.1.3},
|
|
248
|
+
date = {2025-6-6},
|
|
249
249
|
}
|
|
250
250
|
```
|
|
251
251
|
|
|
@@ -227,6 +227,7 @@ class DestState(State):
|
|
|
227
227
|
class Dest(GeomPoint):
|
|
228
228
|
"""Start/end/point."""
|
|
229
229
|
|
|
230
|
+
__slots__ = ()
|
|
230
231
|
container_p = DestParam
|
|
231
232
|
container_s = DestState
|
|
232
233
|
|
|
@@ -252,9 +253,11 @@ class GroundGeomArch(GeomArchitecture):
|
|
|
252
253
|
|
|
253
254
|
|
|
254
255
|
class GroundState(State):
|
|
255
|
-
"""
|
|
256
|
+
"""State defining if rover is in bounds."""
|
|
257
|
+
|
|
256
258
|
in_bound: bool = True
|
|
257
259
|
|
|
260
|
+
|
|
258
261
|
class Ground(Environment):
|
|
259
262
|
"""Ground environment of the rover."""
|
|
260
263
|
|
|
@@ -272,7 +275,8 @@ class Ground(Environment):
|
|
|
272
275
|
|
|
273
276
|
def end_dist(self, pos_state):
|
|
274
277
|
"""Calculate minimum distance between the end point and the rover."""
|
|
275
|
-
|
|
278
|
+
on_shape = self.ga.points['end'].get_shape('on')
|
|
279
|
+
return on_shape.distance(Point(pos_state.get("x", "y")))
|
|
276
280
|
|
|
277
281
|
def max_line_dist(self, pos_hist):
|
|
278
282
|
"""Calculate the maximum distance the rover has deviated from its path."""
|
|
@@ -280,7 +284,7 @@ class Ground(Environment):
|
|
|
280
284
|
yhist = pos_hist.y
|
|
281
285
|
max_dist = 0.0
|
|
282
286
|
for i, x in enumerate(xhist):
|
|
283
|
-
dist = self.ga.lines['line'].
|
|
287
|
+
dist = self.ga.lines['line'].get_shape().distance(Point(x, yhist[i]))
|
|
284
288
|
if dist > max_dist:
|
|
285
289
|
max_dist = dist
|
|
286
290
|
return max_dist
|
|
@@ -289,6 +293,7 @@ class Ground(Environment):
|
|
|
289
293
|
class PathLine(GeomLine):
|
|
290
294
|
"""Rover Line."""
|
|
291
295
|
|
|
296
|
+
__slots__ = ()
|
|
292
297
|
container_p = PathParam
|
|
293
298
|
|
|
294
299
|
|
|
@@ -268,7 +268,7 @@ class History(Result):
|
|
|
268
268
|
raise Exception(obj_str + "Value too large to represent: "
|
|
269
269
|
+ att + "=" + str(val)) from e
|
|
270
270
|
|
|
271
|
-
def cut(self, end_ind=None, start_ind=None, newcopy=False):
|
|
271
|
+
def cut(self, end_ind=None, start_ind=None, newcopy=False, reshape_to=None):
|
|
272
272
|
"""
|
|
273
273
|
Cut the history to a given index.
|
|
274
274
|
|
|
@@ -283,6 +283,9 @@ class History(Result):
|
|
|
283
283
|
newcopy: bool, optional
|
|
284
284
|
Tells whether to creat a new history variable with the information what was
|
|
285
285
|
cut or cut the original history variable. Default is False.
|
|
286
|
+
reshape_to: int, optional
|
|
287
|
+
Size of array to cut from, if different from current size. Default is None,
|
|
288
|
+
which does not reshape the array.
|
|
286
289
|
|
|
287
290
|
Examples
|
|
288
291
|
--------
|
|
@@ -306,15 +309,20 @@ class History(Result):
|
|
|
306
309
|
hist = self
|
|
307
310
|
for name, att in hist.items():
|
|
308
311
|
if isinstance(att, History):
|
|
309
|
-
hist[name] = hist[name].cut(end_ind, start_ind,
|
|
312
|
+
hist[name] = hist[name].cut(end_ind, start_ind,
|
|
313
|
+
newcopy=False, reshape_to=reshape_to)
|
|
310
314
|
else:
|
|
311
315
|
try:
|
|
316
|
+
if reshape_to and reshape_to != att.shape[0]:
|
|
317
|
+
new_shape = tuple([reshape_to, *att.shape[1:]])
|
|
318
|
+
att = np.resize(att, new_shape)
|
|
312
319
|
if end_ind is None:
|
|
313
|
-
|
|
314
|
-
elif start_ind is None:
|
|
315
|
-
hist[name] = att[:end_ind+1]
|
|
320
|
+
ei = len(att)
|
|
316
321
|
else:
|
|
317
|
-
|
|
322
|
+
ei = end_ind+1
|
|
323
|
+
if start_ind is None:
|
|
324
|
+
start_ind = 0
|
|
325
|
+
hist[name] = att[start_ind:ei]
|
|
318
326
|
except TypeError as e:
|
|
319
327
|
raise Exception("Invalid history for name " + name +
|
|
320
328
|
" in history "+str(hist.data)) from e
|
|
@@ -40,7 +40,7 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
|
40
40
|
specific language governing permissions and limitations under the License.
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
from fmdtools.define.base import t_key, nest_dict, is_numeric, is_bool
|
|
43
|
+
from fmdtools.define.base import t_key, nest_dict, is_numeric, is_bool
|
|
44
44
|
from fmdtools.analyze.common import to_include_keys
|
|
45
45
|
from fmdtools.analyze.common import calc_metric, calc_metric_ci, join_key
|
|
46
46
|
from fmdtools.analyze.common import get_sub_include, unpack_plot_values
|
|
@@ -167,6 +167,8 @@ class Architecture(Simulable):
|
|
|
167
167
|
# sync rands, if present
|
|
168
168
|
if hasattr(self, 'r') and hasattr(objclass, "container_r"):
|
|
169
169
|
kwargs = {**{'r': {"seed": self.r.seed}}, **kwargs}
|
|
170
|
+
if hasattr(objclass, "container_sp"):
|
|
171
|
+
kwargs = {**{'sp': self.sp.asdict()}, **kwargs}
|
|
170
172
|
obj = init_obj(name=name, objclass=objclass, track=track,
|
|
171
173
|
as_copy=as_copy, root=self.get_full_name()+"."+flex_role,
|
|
172
174
|
**kwargs)
|
|
@@ -241,14 +243,10 @@ class Architecture(Simulable):
|
|
|
241
243
|
Flows, dicts for non-default values to p, s, etc.
|
|
242
244
|
"""
|
|
243
245
|
flows = self.get_flows(*flownames, all_if_empty=False)
|
|
244
|
-
fkwargs = {**{'sp': self.sp.asdict()}, **kwargs}
|
|
245
246
|
if not self.sp.use_local:
|
|
246
|
-
|
|
247
|
+
kwargs = {**{'t': {'dt': self.sp.dt}}, **kwargs}
|
|
247
248
|
|
|
248
|
-
self.add_flex_role_obj(flex_role, name, objclass=simclass, flows=flows, **
|
|
249
|
-
|
|
250
|
-
# add modes to overall mode dict
|
|
251
|
-
sim = self.get_flex_role_objs(flex_role)[name]
|
|
249
|
+
self.add_flex_role_obj(flex_role, name, objclass=simclass, flows=flows, **kwargs)
|
|
252
250
|
|
|
253
251
|
def init_architecture(self, *args, **kwargs):
|
|
254
252
|
"""Use to initialize architecture."""
|
|
@@ -51,13 +51,16 @@ class GeomArchitecture(Architecture):
|
|
|
51
51
|
|
|
52
52
|
>>> ega = ExGeomArch()
|
|
53
53
|
>>> ega.geoms()['ex_point'].s
|
|
54
|
-
ExGeomState(occupied=False)
|
|
54
|
+
ExGeomState(occupied=False, buffer_around=1.0)
|
|
55
55
|
>>> ega.h
|
|
56
56
|
points.ex_point.s.occupied: array(101)
|
|
57
|
+
points.ex_point.s.buffer_around: array(101)
|
|
57
58
|
lines.ex_line.s.occupied: array(101)
|
|
59
|
+
lines.ex_line.s.buffer_around: array(101)
|
|
58
60
|
polys.ex_poly.s.occupied: array(101)
|
|
61
|
+
polys.ex_poly.s.buffer_around: array(101)
|
|
59
62
|
>>> ega.return_mutables()
|
|
60
|
-
((False,), (False,), (False,), (-0.1, 0, 0.0, 1))
|
|
63
|
+
((False, 1.0), (False, 1.0), (False, 1.0), (-0.1, 0, 0.0, 1))
|
|
61
64
|
"""
|
|
62
65
|
|
|
63
66
|
container_p = Parameter
|
|
@@ -153,11 +156,11 @@ class GeomArchitecture(Architecture):
|
|
|
153
156
|
--------
|
|
154
157
|
>>> exga = ExGeomArch()
|
|
155
158
|
>>> exga.all_at(1.0, 1.0)
|
|
156
|
-
{'ex_point': ['shape', 'on'], 'ex_line': ['shape', 'on'], 'ex_poly': ['shape']}
|
|
159
|
+
{'ex_point': ['shape', 'on', 'around'], 'ex_line': ['shape', 'on', 'around'], 'ex_poly': ['shape', 'around']}
|
|
157
160
|
>>> exga.all_at(0.0, 0.0)
|
|
158
|
-
{'ex_line': ['shape', 'on'], 'ex_poly': ['shape']}
|
|
161
|
+
{'ex_line': ['shape', 'on', 'around'], 'ex_poly': ['shape', 'around']}
|
|
159
162
|
>>> exga.all_at(0.4, 0.3)
|
|
160
|
-
{'ex_point': ['on'], 'ex_line': ['on']}
|
|
163
|
+
{'ex_point': ['on', 'around'], 'ex_line': ['on', 'around'], 'ex_poly': ['around']}
|
|
161
164
|
"""
|
|
162
165
|
all_at = {}
|
|
163
166
|
for geomname, geom in self.geoms().items():
|
|
@@ -205,6 +208,31 @@ class GeomArchitecture(Architecture):
|
|
|
205
208
|
fig, ax = self.geoms()[geomname].show(ax=ax, fig=fig, z=z, **local_kwargs)
|
|
206
209
|
return fig, ax
|
|
207
210
|
|
|
211
|
+
def show_from(self, hist, t, **kwargs):
|
|
212
|
+
"""
|
|
213
|
+
Show the GeomArch at the given time in the provided history.
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
hist : History
|
|
218
|
+
History of states for the GeomArchitecture.
|
|
219
|
+
t : int
|
|
220
|
+
Time in the history to show the state of the GeomArchitecture at.
|
|
221
|
+
**kwargs : kwargs
|
|
222
|
+
Keyword arguments to GeomArchitecture.show().
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
fig : figure
|
|
227
|
+
Matplotlib figure object
|
|
228
|
+
ax : axis
|
|
229
|
+
Corresponding matplotlib axis
|
|
230
|
+
"""
|
|
231
|
+
for flex_role in self.flexible_roles:
|
|
232
|
+
for geomname, geom in self.get_flex_role_objs(flex_role).items():
|
|
233
|
+
geom.assign_from(hist.get(flex_role+"."+geomname), t)
|
|
234
|
+
return self.show(**kwargs)
|
|
235
|
+
|
|
208
236
|
|
|
209
237
|
class ExGeomArch(GeomArchitecture):
|
|
210
238
|
"""Example Geometric Architecture for testing etc."""
|
|
@@ -22,6 +22,7 @@ from fmdtools.analyze.common import get_sub_include
|
|
|
22
22
|
from fmdtools.analyze.history import History
|
|
23
23
|
|
|
24
24
|
from recordclass import dataobject, astuple, asdict
|
|
25
|
+
from collections import UserDict
|
|
25
26
|
import copy
|
|
26
27
|
import pickle
|
|
27
28
|
import numpy as np
|
|
@@ -218,13 +219,13 @@ class BaseContainer(dataobject, mapping=True, iterable=True, copy_default=True):
|
|
|
218
219
|
else:
|
|
219
220
|
# if kwarg states provided, assign keys to values
|
|
220
221
|
fielddict = {k: getattr(obj, v) for k, v in fielddict.items()}
|
|
221
|
-
elif isinstance(obj, dict):
|
|
222
|
+
elif isinstance(obj, dict) or isinstance(obj, UserDict):
|
|
222
223
|
if not fielddict:
|
|
223
224
|
fielddict = {s: obj[s] for s in fields if s in obj}
|
|
224
225
|
else:
|
|
225
226
|
fielddict = {k: obj[v] for k, v in fielddict.items() if v in obj}
|
|
226
227
|
else:
|
|
227
|
-
raise Exception("Invalid type to assign from: "+obj.__class__)
|
|
228
|
+
raise Exception("Invalid type to assign from: "+str(obj.__class__))
|
|
228
229
|
return fielddict
|
|
229
230
|
|
|
230
231
|
def assign(self, obj, *fields, as_copy=True, **fielddict):
|
|
@@ -19,6 +19,7 @@ specific language governing permissions and limitations under the License.
|
|
|
19
19
|
|
|
20
20
|
from fmdtools.define.container.rand import Rand
|
|
21
21
|
from fmdtools.define.flow.commsflow import CommsFlow
|
|
22
|
+
from fmdtools.define.block.base import SimParam
|
|
22
23
|
from fmdtools.define.object.coords import Coords, ExampleCoords
|
|
23
24
|
from fmdtools.define.architecture.geom import GeomArchitecture, ExGeomArch
|
|
24
25
|
|
|
@@ -51,32 +52,37 @@ class Environment(CommsFlow):
|
|
|
51
52
|
>>> env.create_hist([1.0])
|
|
52
53
|
c.r.probdens: array(1)
|
|
53
54
|
c.st: array(1)
|
|
54
|
-
ga.points.ex_point:
|
|
55
|
-
ga.
|
|
56
|
-
ga.
|
|
55
|
+
ga.points.ex_point.s.occupied: array(1)
|
|
56
|
+
ga.points.ex_point.s.buffer_around: array(1)
|
|
57
|
+
ga.lines.ex_line.s.occupied: array(1)
|
|
58
|
+
ga.lines.ex_line.s.buffer_around: array(1)
|
|
59
|
+
ga.polys.ex_poly.s.occupied: array(1)
|
|
60
|
+
ga.polys.ex_poly.s.buffer_around: array(1)
|
|
57
61
|
"""
|
|
58
62
|
|
|
59
63
|
slots = ["c", "r", "ga"]
|
|
60
64
|
container_r = Rand
|
|
65
|
+
container_sp = SimParam
|
|
66
|
+
default_sp = {}
|
|
61
67
|
coords_c = Coords
|
|
62
68
|
arch_ga = GeomArchitecture
|
|
63
69
|
roletypes = ['container', 'coords', 'arch']
|
|
64
70
|
default_track = ('s', 'i', 'c', 'ga')
|
|
65
71
|
all_possible = ('s', 'i', 'c', 'r', 'ga')
|
|
66
72
|
|
|
67
|
-
def __init__(self, name='', root='', glob=[], p={}, s={}, r={}, c={}, ga={},
|
|
73
|
+
def __init__(self, name='', root='', glob=[], p={}, s={}, r={}, sp={}, c={}, ga={},
|
|
68
74
|
track='default'):
|
|
69
|
-
super().__init__(name=name, root=root, glob=glob, p=p, s=s, track=track)
|
|
75
|
+
super().__init__(name=name, root=root, glob=glob, p=p, s=s, sp=sp, track=track)
|
|
70
76
|
# NOTE: p and s also init here because if not, they are overritten
|
|
71
77
|
# may need to change in the future
|
|
72
|
-
self.init_roletypes('container', "coords", "arch", r=r, p=p, s=s)
|
|
78
|
+
self.init_roletypes('container', "coords", "arch", r=r, p=p, s=s, sp=sp)
|
|
73
79
|
if 'p' not in c and getattr(self.coords_c, 'container_p', None) == getattr(self, 'container_p', None):
|
|
74
80
|
c = {**c, 'p': p}
|
|
75
81
|
if 'p' not in ga and getattr(self.arch_ga, 'container_p', None) == getattr(self, 'container_p', None):
|
|
76
82
|
ga = {**ga, 'p': p}
|
|
77
83
|
r_kwargs = {'run_stochastic': self.r.run_stochastic, 'seed': self.r.seed}
|
|
78
84
|
c = {**{'r': r_kwargs}, **c}
|
|
79
|
-
ga = {**{'r': r_kwargs}, **ga}
|
|
85
|
+
ga = {**{'r': r_kwargs, 'sp': self.sp}, **ga}
|
|
80
86
|
self.init_roletypes('coords', 'arch', c=c, ga=ga)
|
|
81
87
|
|
|
82
88
|
def base_type(self):
|
|
@@ -115,7 +121,8 @@ class Environment(CommsFlow):
|
|
|
115
121
|
cop = super().copy(glob=glob, p=p, s=s)
|
|
116
122
|
cop.r.assign(self.r)
|
|
117
123
|
cop.c = self.c.copy()
|
|
118
|
-
cop.
|
|
124
|
+
cop.sp = self.sp
|
|
125
|
+
cop.ga = self.ga.copy(sp=self.sp)
|
|
119
126
|
if hasattr(self, 'h'):
|
|
120
127
|
cop.h = self.h.copy()
|
|
121
128
|
return cop
|
|
@@ -644,7 +644,10 @@ class BaseObject(object):
|
|
|
644
644
|
hist : History
|
|
645
645
|
A history of each recorded block property over the given timerange.
|
|
646
646
|
"""
|
|
647
|
-
if hasattr(self, 'h') and self.h
|
|
647
|
+
if hasattr(self, 'h') and self.h:
|
|
648
|
+
len_timerange = len(timerange)
|
|
649
|
+
if len_timerange != len([*self.h.values()][0]):
|
|
650
|
+
self.h = self.h.cut(reshape_to=len_timerange)
|
|
648
651
|
return self.h
|
|
649
652
|
else:
|
|
650
653
|
track = self.track
|
|
@@ -48,19 +48,18 @@ class Geom(BaseObject):
|
|
|
48
48
|
"""
|
|
49
49
|
Base class for defining geometries.
|
|
50
50
|
|
|
51
|
-
Geometry objects are essentially
|
|
51
|
+
Geometry objects are essentially interfaces for various shapely classes used to
|
|
52
52
|
convey the spacial properties of a model.
|
|
53
53
|
|
|
54
|
-
...
|
|
55
|
-
|
|
56
54
|
Roles
|
|
57
55
|
-----
|
|
58
56
|
s : State
|
|
59
|
-
State defining mutable
|
|
57
|
+
State defining mutable properties (e.g., allocations, shapely class inputs)
|
|
60
58
|
p : Param
|
|
61
|
-
Parameter defining immutable
|
|
59
|
+
Parameter defining immutable properties (e.g., shapely inputs, buffer)
|
|
62
60
|
"""
|
|
63
61
|
|
|
62
|
+
__slots__ = ('p', 's', 'shapenames', )
|
|
64
63
|
container_s = State
|
|
65
64
|
container_p = Parameter
|
|
66
65
|
default_track = ['s']
|
|
@@ -70,22 +69,53 @@ class Geom(BaseObject):
|
|
|
70
69
|
|
|
71
70
|
def __init__(self, *args, s={}, p={}, track='default', **kwargs):
|
|
72
71
|
super().__init__(s=s, p=p, track=[], **kwargs)
|
|
73
|
-
self.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for buffer, rad in self.buffers.items():
|
|
77
|
-
setattr(self, buffer, self.shape.buffer(rad))
|
|
72
|
+
self.shapenames = ['shape',
|
|
73
|
+
*self.p.get_pref_attrs('buffer'),
|
|
74
|
+
*self.s.get_pref_attrs('buffer')]
|
|
78
75
|
self.init_track(track=track)
|
|
79
76
|
|
|
80
|
-
def
|
|
77
|
+
def get_shape(self, shapename='shape'):
|
|
81
78
|
"""
|
|
82
|
-
|
|
79
|
+
Get the shapely object defining the class and buffers.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
shapename : str, optional
|
|
84
|
+
Name of the shape. The default is 'shape', which produces the base shape,
|
|
85
|
+
other names return the buffer shapes for that shape.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
shapely.geometry
|
|
90
|
+
Shapely object for the shape.
|
|
91
|
+
"""
|
|
92
|
+
shape = self.shapely_class(*self.get_args())
|
|
93
|
+
if shapename == 'shape':
|
|
94
|
+
return shape
|
|
95
|
+
else:
|
|
96
|
+
argname = 'buffer_'+shapename
|
|
97
|
+
if hasattr(self.p, argname):
|
|
98
|
+
arg = self.p[argname]
|
|
99
|
+
elif hasattr(self.s, argname):
|
|
100
|
+
arg = self.s[argname]
|
|
101
|
+
else:
|
|
102
|
+
raise Exception(argname+" not in "+"Geom's "+str(self.s.__class__)
|
|
103
|
+
+ " or "+str(self.p.__class__))
|
|
104
|
+
return shape.buffer(arg)
|
|
105
|
+
|
|
106
|
+
def get_paramstates(self):
|
|
107
|
+
"""Create dict of parameters and states."""
|
|
108
|
+
return {**self.p.asdict(), **self.s.asdict()}
|
|
109
|
+
|
|
110
|
+
def at(self, pt, shapename='shape'):
|
|
111
|
+
"""
|
|
112
|
+
Determine whether the point x, y is within the buffer 'shapename'.
|
|
83
113
|
|
|
84
114
|
Parameters
|
|
85
115
|
----------
|
|
86
116
|
*pt : tuple
|
|
87
117
|
Locations of x, y, z coordinates.
|
|
88
|
-
|
|
118
|
+
shapename : str
|
|
89
119
|
Name of buffer property
|
|
90
120
|
|
|
91
121
|
Returns
|
|
@@ -93,8 +123,8 @@ class Geom(BaseObject):
|
|
|
93
123
|
at : bool
|
|
94
124
|
Whether x,y is within the buffer.
|
|
95
125
|
"""
|
|
96
|
-
|
|
97
|
-
return
|
|
126
|
+
shape = self.get_shape(shapename)
|
|
127
|
+
return shape.covers(Point(*pt))
|
|
98
128
|
|
|
99
129
|
def all_at(self, *pt):
|
|
100
130
|
"""
|
|
@@ -114,15 +144,14 @@ class Geom(BaseObject):
|
|
|
114
144
|
--------
|
|
115
145
|
>>> exp = ExPoint()
|
|
116
146
|
>>> exp.all_at(1.0, 1.0)
|
|
117
|
-
['shape', 'on']
|
|
147
|
+
['shape', 'on', 'around']
|
|
118
148
|
>>> exp.all_at(1.0, 0.1)
|
|
119
|
-
['on']
|
|
149
|
+
['on', 'around']
|
|
120
150
|
>>> exp.all_at(0.0, 0.0)
|
|
121
151
|
[]
|
|
122
152
|
"""
|
|
123
|
-
buffernames = ['shape', *self.buffers]
|
|
124
153
|
all_at = []
|
|
125
|
-
for bname in
|
|
154
|
+
for bname in self.shapenames:
|
|
126
155
|
if self.at(pt, bname):
|
|
127
156
|
all_at.append(bname)
|
|
128
157
|
return all_at
|
|
@@ -140,7 +169,7 @@ class Geom(BaseObject):
|
|
|
140
169
|
def return_mutables(self):
|
|
141
170
|
return astuple(self.s)
|
|
142
171
|
|
|
143
|
-
def vect_to_shape(self, pt,
|
|
172
|
+
def vect_to_shape(self, pt, shapename='shape'):
|
|
144
173
|
"""
|
|
145
174
|
Gets the vector (x, y) to a given shape.
|
|
146
175
|
|
|
@@ -148,7 +177,7 @@ class Geom(BaseObject):
|
|
|
148
177
|
----------
|
|
149
178
|
pt : tuple/list
|
|
150
179
|
Point to get vector from
|
|
151
|
-
|
|
180
|
+
shapename : str
|
|
152
181
|
Name of shape/buffer. Default is 'shape'.
|
|
153
182
|
|
|
154
183
|
Examples
|
|
@@ -164,13 +193,13 @@ class Geom(BaseObject):
|
|
|
164
193
|
array([[0.],
|
|
165
194
|
[0.]])
|
|
166
195
|
"""
|
|
167
|
-
|
|
196
|
+
shape = self.get_shape(shapename)
|
|
168
197
|
geom_pt = Point(pt)
|
|
169
|
-
geom_c, close_pt = nearest_points(geom_pt,
|
|
198
|
+
geom_c, close_pt = nearest_points(geom_pt, shape)
|
|
170
199
|
vect_to_shape = np.array(close_pt.xy) - np.array(geom_pt.xy)
|
|
171
200
|
return vect_to_shape
|
|
172
201
|
|
|
173
|
-
def vect_at_shape(self, pt,
|
|
202
|
+
def vect_at_shape(self, pt, shapename='shape', dist_forward=0.1):
|
|
174
203
|
"""
|
|
175
204
|
Get the vector (x, y) at a given shape (e.g., direction of a line at pt).
|
|
176
205
|
|
|
@@ -178,7 +207,7 @@ class Geom(BaseObject):
|
|
|
178
207
|
----------
|
|
179
208
|
pt : tuple/lost
|
|
180
209
|
Point closest to shape
|
|
181
|
-
|
|
210
|
+
shapename : str
|
|
182
211
|
Name of shape/buffer. Default is 'shape'.
|
|
183
212
|
dist_forward : float
|
|
184
213
|
Distance forward along line segment to project. Give a negative number to
|
|
@@ -194,11 +223,11 @@ class Geom(BaseObject):
|
|
|
194
223
|
array([[ 0. ],
|
|
195
224
|
[-0.1]])
|
|
196
225
|
"""
|
|
197
|
-
|
|
226
|
+
shape = self.get_shape(shapename)
|
|
198
227
|
geom_pt = Point(pt)
|
|
199
|
-
geom_c, close_pt = nearest_points(geom_pt,
|
|
200
|
-
line_dist =
|
|
201
|
-
next_pt =
|
|
228
|
+
geom_c, close_pt = nearest_points(geom_pt, shape)
|
|
229
|
+
line_dist = shape.line_locate_point(geom_pt)
|
|
230
|
+
next_pt = shape.line_interpolate_point(line_dist + dist_forward)
|
|
202
231
|
vect_at_shape = np.array(next_pt.xy) - np.array(close_pt.xy)
|
|
203
232
|
return vect_at_shape
|
|
204
233
|
|
|
@@ -236,33 +265,37 @@ class Geom(BaseObject):
|
|
|
236
265
|
if not ax:
|
|
237
266
|
fig, ax = setup_plot(z=z, figsize=figsize)
|
|
238
267
|
if 'all' in shapes:
|
|
239
|
-
shapes = {
|
|
268
|
+
shapes = {s: {} for s in self.shapenames}
|
|
240
269
|
if type(z) in (int, float):
|
|
241
270
|
plot_kwargs = {'zs': z, 'zdir': 'z', **kwargs}
|
|
242
271
|
else:
|
|
243
272
|
plot_kwargs = kwargs
|
|
244
|
-
for
|
|
273
|
+
for shapename, shape_kwargs in shapes.items():
|
|
245
274
|
if geomlabel:
|
|
246
|
-
shape_label = geomlabel + "." +
|
|
275
|
+
shape_label = geomlabel + "." + shapename
|
|
247
276
|
else:
|
|
248
|
-
shape_label =
|
|
277
|
+
shape_label = shapename
|
|
249
278
|
local_kwargs = {**plot_kwargs, 'label': shape_label, **shape_kwargs}
|
|
250
|
-
|
|
251
|
-
if isinstance(
|
|
252
|
-
ax.scatter(
|
|
253
|
-
elif isinstance(
|
|
254
|
-
linecoords = np.array([*
|
|
279
|
+
shape = self.get_shape(shapename)
|
|
280
|
+
if isinstance(shape, Point):
|
|
281
|
+
ax.scatter(shape.x, shape.y, **local_kwargs)
|
|
282
|
+
elif isinstance(shape, LineString):
|
|
283
|
+
linecoords = np.array([*shape.coords])
|
|
255
284
|
ax.plot(linecoords[:, 0], linecoords[:, 1], **local_kwargs)
|
|
256
|
-
elif isinstance(
|
|
257
|
-
ax.plot(*
|
|
285
|
+
elif isinstance(shape, Polygon):
|
|
286
|
+
ax.plot(*shape.exterior.xy, **local_kwargs)
|
|
258
287
|
ax.axis('equal')
|
|
259
288
|
consolidate_legend(ax, **kwargs)
|
|
260
289
|
return fig, ax
|
|
261
290
|
|
|
291
|
+
def assign_from(self, hist, t, *states):
|
|
292
|
+
"""Update Geom state from a given history and time."""
|
|
293
|
+
self.s.assign(hist.s.get_slice(t), *states)
|
|
294
|
+
|
|
262
295
|
|
|
263
296
|
class PointParam(Parameter):
|
|
264
297
|
"""
|
|
265
|
-
Parameter defining points.
|
|
298
|
+
Parameter defining points. Extend with 'buffer_att' to create buffer shapes.
|
|
266
299
|
|
|
267
300
|
Fields
|
|
268
301
|
------
|
|
@@ -271,6 +304,7 @@ class PointParam(Parameter):
|
|
|
271
304
|
y : float
|
|
272
305
|
y-location of point.
|
|
273
306
|
|
|
307
|
+
|
|
274
308
|
Examples
|
|
275
309
|
--------
|
|
276
310
|
a point with center at 1.0, 1.0 and radius of 1.0 defining whether something
|
|
@@ -281,18 +315,13 @@ class PointParam(Parameter):
|
|
|
281
315
|
... y: float = 1.0
|
|
282
316
|
... buffer_on: float = 1.0
|
|
283
317
|
|
|
284
|
-
>>>
|
|
285
|
-
|
|
286
|
-
([1.0, 1.0],)
|
|
318
|
+
>>> ExPointParam()
|
|
319
|
+
ExPointParam(x=1.0, y=1.0, buffer_on=1.0)
|
|
287
320
|
"""
|
|
288
321
|
|
|
289
322
|
x: ClassVar[float] = 0.0
|
|
290
323
|
y: ClassVar[float] = 0.0
|
|
291
324
|
|
|
292
|
-
def as_args(self):
|
|
293
|
-
"""Create arguments for shapely Point class based on fields."""
|
|
294
|
-
return ([self[i] for i in ['x', 'y', 'z'] if i in dir(self)], )
|
|
295
|
-
|
|
296
325
|
|
|
297
326
|
class GeomPoint(Geom):
|
|
298
327
|
"""
|
|
@@ -304,6 +333,7 @@ class GeomPoint(Geom):
|
|
|
304
333
|
Examples
|
|
305
334
|
--------
|
|
306
335
|
>>> class ExPoint(GeomPoint):
|
|
336
|
+
... __slots__ = ()
|
|
307
337
|
... container_p = ExPointParam
|
|
308
338
|
... container_s = ExGeomState
|
|
309
339
|
>>> exp = ExPoint()
|
|
@@ -314,20 +344,42 @@ class GeomPoint(Geom):
|
|
|
314
344
|
>>> exp.at((1.0, 0.1), "on")
|
|
315
345
|
True
|
|
316
346
|
|
|
317
|
-
Additionally, note the underlying shapely
|
|
347
|
+
Additionally, note the underlying shapely attributes returned by get_shape:
|
|
318
348
|
|
|
319
|
-
>>> type(exp.
|
|
349
|
+
>>> type(exp.get_shape())
|
|
320
350
|
<class 'shapely.geometry.point.Point'>
|
|
321
351
|
|
|
322
352
|
as well as the buffer (on):
|
|
323
353
|
|
|
324
|
-
>>> type(exp.on)
|
|
354
|
+
>>> type(exp.get_shape('on'))
|
|
325
355
|
<class 'shapely.geometry.polygon.Polygon'>
|
|
356
|
+
|
|
357
|
+
Finally, note how geom characteristics defined as states can change:
|
|
358
|
+
|
|
359
|
+
>>> exp.at((3.0, 1.0), 'around') # outside the default area of `around` buffer
|
|
360
|
+
False
|
|
361
|
+
>>> exp.s.buffer_around = 2.0 # set to a larger radius to capture the point
|
|
362
|
+
>>> exp.at((3.0, 1.0), 'around')
|
|
363
|
+
True
|
|
326
364
|
"""
|
|
327
365
|
|
|
366
|
+
__slots__ = ()
|
|
328
367
|
container_p = PointParam
|
|
329
368
|
shapely_class = Point
|
|
330
369
|
|
|
370
|
+
def get_args(self):
|
|
371
|
+
"""
|
|
372
|
+
Get shape arguments from Point parameter/state.
|
|
373
|
+
|
|
374
|
+
Examples
|
|
375
|
+
--------
|
|
376
|
+
>>> exp = ExPoint()
|
|
377
|
+
>>> exp.get_args()
|
|
378
|
+
(1.0, 1.0)
|
|
379
|
+
"""
|
|
380
|
+
combodict = self.get_paramstates()
|
|
381
|
+
return tuple([combodict[i] for i in ['x', 'y', 'z'] if i in combodict])
|
|
382
|
+
|
|
331
383
|
|
|
332
384
|
class ExGeomState(State):
|
|
333
385
|
"""
|
|
@@ -337,6 +389,7 @@ class ExGeomState(State):
|
|
|
337
389
|
"""
|
|
338
390
|
|
|
339
391
|
occupied: bool = False
|
|
392
|
+
buffer_around: float = 1.0
|
|
340
393
|
|
|
341
394
|
|
|
342
395
|
class ExPointParam(PointParam):
|
|
@@ -354,6 +407,7 @@ class ExPointParam(PointParam):
|
|
|
354
407
|
class ExPoint(GeomPoint):
|
|
355
408
|
"""Example point for testing."""
|
|
356
409
|
|
|
410
|
+
__slots__ = ()
|
|
357
411
|
container_p = ExPointParam
|
|
358
412
|
container_s = ExGeomState
|
|
359
413
|
|
|
@@ -377,17 +431,12 @@ class LineParam(Parameter):
|
|
|
377
431
|
>>> class ExLineParam(LineParam):
|
|
378
432
|
... xys: tuple = ((0.0, 0.0), (1.0, 1.0))
|
|
379
433
|
... buffer_on: float = 1.0
|
|
380
|
-
>>>
|
|
381
|
-
|
|
382
|
-
(((0.0, 0.0), (1.0, 1.0)),)
|
|
434
|
+
>>> ExLineParam()
|
|
435
|
+
ExLineParam(xys=((0.0, 0.0), (1.0, 1.0)), buffer_on=1.0)
|
|
383
436
|
"""
|
|
384
437
|
|
|
385
438
|
xys: ClassVar[tuple] = ()
|
|
386
439
|
|
|
387
|
-
def as_args(self):
|
|
388
|
-
"""Create arguments for shapely LineString class based on fields."""
|
|
389
|
-
return (self.xys, )
|
|
390
|
-
|
|
391
440
|
|
|
392
441
|
class ExLineParam(LineParam):
|
|
393
442
|
"""Example parameter defining a line with a given buffer 'on'."""
|
|
@@ -405,6 +454,7 @@ class GeomLine(Geom):
|
|
|
405
454
|
Examples
|
|
406
455
|
--------
|
|
407
456
|
>>> class ExLine(GeomLine):
|
|
457
|
+
... __slots__ = ()
|
|
408
458
|
... container_p = ExLineParam
|
|
409
459
|
... container_s = ExGeomState
|
|
410
460
|
>>> exp = ExLine()
|
|
@@ -415,24 +465,39 @@ class GeomLine(Geom):
|
|
|
415
465
|
>>> exp.at((2.0, 2.0), "on")
|
|
416
466
|
False
|
|
417
467
|
|
|
418
|
-
Additionally, note the underlying shapely
|
|
468
|
+
Additionally, note the underlying shapely objects returned by get_shape():
|
|
419
469
|
|
|
420
|
-
>>> type(exp.
|
|
470
|
+
>>> type(exp.get_shape())
|
|
421
471
|
<class 'shapely.geometry.linestring.LineString'>
|
|
422
472
|
|
|
423
473
|
As well as the buffer (on):
|
|
424
474
|
|
|
425
|
-
>>> type(exp.on)
|
|
475
|
+
>>> type(exp.get_shape('on'))
|
|
426
476
|
<class 'shapely.geometry.polygon.Polygon'>
|
|
427
477
|
"""
|
|
428
478
|
|
|
479
|
+
__slots__ = ()
|
|
429
480
|
container_p = LineParam
|
|
430
481
|
shapely_class = LineString
|
|
431
482
|
|
|
483
|
+
def get_args(self):
|
|
484
|
+
"""
|
|
485
|
+
Create arguments for shapely LineString class based on fields.
|
|
486
|
+
|
|
487
|
+
Examples
|
|
488
|
+
--------
|
|
489
|
+
>>> exl = ExLine()
|
|
490
|
+
>>> exl.get_args()
|
|
491
|
+
(((0.0, 0.0), (1.0, 1.0)),)
|
|
492
|
+
"""
|
|
493
|
+
combodict = self.get_paramstates()
|
|
494
|
+
return (combodict['xys'], )
|
|
495
|
+
|
|
432
496
|
|
|
433
497
|
class ExLine(GeomLine):
|
|
434
498
|
"""Example GeomLine to use in testing."""
|
|
435
499
|
|
|
500
|
+
__slots__ = ()
|
|
436
501
|
container_p = ExLineParam
|
|
437
502
|
container_s = ExGeomState
|
|
438
503
|
|
|
@@ -441,8 +506,6 @@ class PolyParam(Parameter):
|
|
|
441
506
|
"""
|
|
442
507
|
Parameter defining polygons. May be extended with buffers.
|
|
443
508
|
|
|
444
|
-
...
|
|
445
|
-
|
|
446
509
|
Fields
|
|
447
510
|
------
|
|
448
511
|
shell : tuple
|
|
@@ -455,20 +518,16 @@ class PolyParam(Parameter):
|
|
|
455
518
|
The following PolyParam defines a hollow right triangle:
|
|
456
519
|
|
|
457
520
|
>>> class ExPolyParam(PolyParam):
|
|
458
|
-
...
|
|
459
|
-
...
|
|
460
|
-
|
|
461
|
-
>>>
|
|
462
|
-
(((0.0, 0.0), (1.0, 0.0), (1.0, 1.0)), (((0.3, 0.2), (0.6, 0.2), (0.6, 0.5)),))
|
|
521
|
+
... __slots__ = ()
|
|
522
|
+
... shell: tuple = ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0))
|
|
523
|
+
... holes: tuple = (((0.3, 0.2), (0.6, 0.2), (0.6, 0.5)), )
|
|
524
|
+
>>> ExPolyParam()
|
|
525
|
+
ExPolyParam(shell=((0.0, 0.0), (1.0, 0.0), (1.0, 1.0)), holes=(((0.3, 0.2), (0.6, 0.2), (0.6, 0.5)),))
|
|
463
526
|
"""
|
|
464
527
|
|
|
465
528
|
shell: ClassVar[tuple] = ()
|
|
466
529
|
holes: ClassVar[tuple] = ()
|
|
467
530
|
|
|
468
|
-
def as_args(self):
|
|
469
|
-
"""Create arguments for shapely Polygon class based on fields."""
|
|
470
|
-
return self.shell, self.holes
|
|
471
|
-
|
|
472
531
|
|
|
473
532
|
class ExPolyParam(PolyParam):
|
|
474
533
|
"""Example polygon parameter defining a basic triangle for use in testing."""
|
|
@@ -487,6 +546,7 @@ class GeomPoly(Geom):
|
|
|
487
546
|
Examples
|
|
488
547
|
--------
|
|
489
548
|
>>> class ExPoly(GeomPoly):
|
|
549
|
+
... __slots__ = ()
|
|
490
550
|
... container_p = ExPolyParam
|
|
491
551
|
... container_s = ExGeomState
|
|
492
552
|
>>> egp = ExPoly()
|
|
@@ -495,19 +555,32 @@ class GeomPoly(Geom):
|
|
|
495
555
|
>>> egp.at((0.4, 0.3))
|
|
496
556
|
False
|
|
497
557
|
|
|
498
|
-
Additionally, note the underlying shapely
|
|
558
|
+
Additionally, note the underlying shapely objects returned by get_shape():
|
|
499
559
|
|
|
500
|
-
>>> type(egp.
|
|
560
|
+
>>> type(egp.get_shape())
|
|
501
561
|
<class 'shapely.geometry.polygon.Polygon'>
|
|
502
562
|
"""
|
|
503
563
|
|
|
564
|
+
__slots__ = ()
|
|
504
565
|
container_p = PolyParam
|
|
505
566
|
shapely_class = Polygon
|
|
506
567
|
|
|
568
|
+
def get_args(self):
|
|
569
|
+
"""Create arguments for shapely Polygon class based on fields.
|
|
570
|
+
|
|
571
|
+
Examples
|
|
572
|
+
--------
|
|
573
|
+
>>> ExPoly().get_args()
|
|
574
|
+
(((0.0, 0.0), (1.0, 0.0), (1.0, 1.0)), (((0.3, 0.2), (0.6, 0.2), (0.6, 0.5)),))
|
|
575
|
+
"""
|
|
576
|
+
combodict = self.get_paramstates()
|
|
577
|
+
return combodict['shell'], combodict['holes']
|
|
578
|
+
|
|
507
579
|
|
|
508
580
|
class ExPoly(GeomPoly):
|
|
509
581
|
"""Example Polygon for use in testing."""
|
|
510
582
|
|
|
583
|
+
__slots__ = ()
|
|
511
584
|
container_p = ExPolyParam
|
|
512
585
|
container_s = ExGeomState
|
|
513
586
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmdtools
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: System resilience modelling, simulation, and assessment in Python
|
|
5
5
|
Author: fmdtools Developers
|
|
6
6
|
Maintainer-email: Daniel Hulse <daniel.e.hulse@nasa.gov>
|
|
7
|
-
License: fmdtools version 2.1.
|
|
7
|
+
License: fmdtools version 2.1.3
|
|
8
8
|
---------------------------
|
|
9
9
|
Apache License
|
|
10
10
|
Version 2.0, January 2004
|
|
@@ -367,7 +367,7 @@ This may then be installed using:
|
|
|
367
367
|
Note that this version reflects the latest version on the ``main`` git branch along with any local changes. To use a particular version of ``fmdtools`` you can checkout the tag corresponding to the version you want, e.g.:
|
|
368
368
|
|
|
369
369
|
```
|
|
370
|
-
git checkout v2.1.
|
|
370
|
+
git checkout v2.1.3
|
|
371
371
|
```
|
|
372
372
|
|
|
373
373
|
|
|
@@ -505,8 +505,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
505
505
|
author = {{NASA}},
|
|
506
506
|
title = {fmdtools},
|
|
507
507
|
url = {https://github.com/nasa/fmdtools},
|
|
508
|
-
version = {2.1.
|
|
509
|
-
date = {2025-
|
|
508
|
+
version = {2.1.3},
|
|
509
|
+
date = {2025-6-6},
|
|
510
510
|
}
|
|
511
511
|
```
|
|
512
512
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|