fmdtools 2.1.2__tar.gz → 2.2.0__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.2.0}/LICENSE +1 -1
- {fmdtools-2.1.2/fmdtools.egg-info → fmdtools-2.2.0}/PKG-INFO +20 -20
- {fmdtools-2.1.2 → fmdtools-2.2.0}/README.md +14 -14
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/asg_demo/demo_model.py +10 -19
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/eps/eps.py +15 -29
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/eps/test_eps.py +15 -6
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multiflow_demo/multiflow_demo.py +13 -13
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multiflow_demo/test_multiflow.py +8 -8
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/drone_mdl_dynamic.py +28 -36
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/drone_mdl_hierarchical.py +4 -6
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/drone_mdl_rural.py +12 -22
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/drone_mdl_static.py +49 -59
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/drone_mdl_urban.py +18 -21
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/opt_drone_rural.py +2 -2
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/test_multirotor.py +6 -6
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/ex_pump.py +35 -39
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/parallelism_methods.py +4 -9
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/pump_indiv.py +4 -5
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/pump_stochastic.py +40 -40
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/test_pump.py +15 -12
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/test_pump_example.py +36 -34
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/test_pump_stochastic.py +41 -50
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/optimization/search_rover.py +15 -12
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/rover_degradation.py +26 -9
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/rover_mode_space.py +1 -1
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/rover_model.py +30 -41
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/rover_model_human.py +26 -38
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/test_rover.py +1 -2
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/tank/tank_model.py +35 -34
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/tank/tank_optimization_model.py +14 -15
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/tank/test_tank.py +26 -23
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/ATC.py +2 -2
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/asset.py +2 -5
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/common.py +6 -6
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/model.py +12 -14
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/test_asset.py +9 -9
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/taxiway/test_model.py +4 -4
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/__init__.py +1 -1
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/common.py +25 -28
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/graph/__init__.py +3 -2
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/graph/base.py +266 -9
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/graph/model.py +3 -3
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/graph/style.py +244 -92
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/history.py +27 -21
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/phases.py +16 -14
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/result.py +48 -14
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/tabulate.py +31 -31
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/architecture/action.py +111 -64
- fmdtools-2.2.0/fmdtools/define/architecture/base.py +673 -0
- fmdtools-2.2.0/fmdtools/define/architecture/component.py +116 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/architecture/function.py +47 -304
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/architecture/geom.py +82 -6
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/base.py +88 -2
- fmdtools-2.2.0/fmdtools/define/block/action.py +126 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/block/base.py +416 -173
- fmdtools-2.2.0/fmdtools/define/block/component.py +97 -0
- fmdtools-2.2.0/fmdtools/define/block/function.py +148 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/base.py +29 -15
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/mode.py +10 -16
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/rand.py +60 -51
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/state.py +32 -26
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/time.py +65 -28
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/environment.py +30 -11
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/flow/base.py +5 -13
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/flow/commsflow.py +39 -44
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/flow/multiflow.py +39 -20
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/object/base.py +335 -154
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/object/coords.py +121 -94
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/object/geom.py +159 -85
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/object/timer.py +4 -2
- fmdtools-2.2.0/fmdtools/sim/propagate.py +1200 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/sim/sample.py +32 -28
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/sim/scenario.py +13 -1
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/sim/search.py +84 -102
- {fmdtools-2.1.2 → fmdtools-2.2.0/fmdtools.egg-info}/PKG-INFO +20 -20
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools.egg-info/requires.txt +2 -2
- {fmdtools-2.1.2 → fmdtools-2.2.0}/pyproject.toml +5 -5
- {fmdtools-2.1.2 → fmdtools-2.2.0}/tests/test_graph.py +11 -10
- {fmdtools-2.1.2 → fmdtools-2.2.0}/tests/test_hierarchical.py +15 -6
- fmdtools-2.1.2/fmdtools/define/architecture/base.py +0 -403
- fmdtools-2.1.2/fmdtools/define/architecture/component.py +0 -52
- fmdtools-2.1.2/fmdtools/define/block/action.py +0 -102
- fmdtools-2.1.2/fmdtools/define/block/component.py +0 -29
- fmdtools-2.1.2/fmdtools/define/block/function.py +0 -231
- fmdtools-2.1.2/fmdtools/sim/propagate.py +0 -1238
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/asg_demo/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/eps/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multiflow_demo/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/multirotor/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/pump/jointfaults_ex.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/rover/optimization/ea_analysis.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/examples/tank/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/analyze/graph/label.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/architecture/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/block/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/container/parameter.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/flow/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/define/object/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools/sim/__init__.py +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools.egg-info/SOURCES.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools.egg-info/dependency_links.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/fmdtools.egg-info/top_level.txt +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/setup.cfg +0 -0
- {fmdtools-2.1.2 → fmdtools-2.2.0}/tests/test_packages.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmdtools
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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.
|
|
7
|
+
License: fmdtools version 2.2.0
|
|
8
8
|
---------------------------
|
|
9
9
|
Apache License
|
|
10
10
|
Version 2.0, January 2004
|
|
@@ -236,24 +236,24 @@ Project-URL: Documentation, https://nasa.github.io/fmdtools/
|
|
|
236
236
|
Project-URL: source-code, https://github.com/nasa/fmdtools
|
|
237
237
|
Classifier: Development Status :: 5 - Production/Stable
|
|
238
238
|
Classifier: Intended Audience :: Science/Research
|
|
239
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
240
239
|
Classifier: Programming Language :: Python :: 3.11
|
|
241
240
|
Classifier: Programming Language :: Python :: 3.12
|
|
241
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
242
242
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
243
243
|
Classifier: Operating System :: OS Independent
|
|
244
244
|
Classifier: Topic :: Scientific/Engineering
|
|
245
|
-
Requires-Python: >=3.
|
|
245
|
+
Requires-Python: >=3.11
|
|
246
246
|
Description-Content-Type: text/markdown
|
|
247
247
|
License-File: LICENSE
|
|
248
248
|
Requires-Dist: scipy
|
|
249
249
|
Requires-Dist: tqdm
|
|
250
250
|
Requires-Dist: networkx
|
|
251
|
-
Requires-Dist: numpy
|
|
251
|
+
Requires-Dist: numpy>=2.0
|
|
252
252
|
Requires-Dist: matplotlib>=3.7.0
|
|
253
253
|
Requires-Dist: pandas
|
|
254
254
|
Requires-Dist: ordered-set
|
|
255
255
|
Requires-Dist: dill
|
|
256
|
-
Requires-Dist: recordclass==0.
|
|
256
|
+
Requires-Dist: recordclass==0.23.1
|
|
257
257
|
Requires-Dist: pytest
|
|
258
258
|
Requires-Dist: graphviz
|
|
259
259
|
Requires-Dist: shapely>=2.0
|
|
@@ -263,15 +263,15 @@ Dynamic: license-file
|
|
|
263
263
|
|
|
264
264
|
# Overview
|
|
265
265
|
|
|
266
|
-

|
|
267
267
|
[](https://pypi.org/project/fmdtools/)
|
|
268
268
|
[](https://pepy.tech/project/fmdtools)
|
|
269
269
|
[](https://pepy.tech/project/fmdtools)
|
|
270
270
|
[](https://github.com/nasa/fmdtools/releases)
|
|
271
271
|
[](https://github.com/nasa/fmdtools/tags)
|
|
272
272
|
[](https://www.codefactor.io/repository/github/nasa/fmdtools)
|
|
273
|
-
[](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py313/junit/report.html)
|
|
274
|
+
[](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py313/coverage_html/index.html)
|
|
275
275
|
[](https://github.com/nasa/fmdtools/blob/main/LICENSE)
|
|
276
276
|
[](https://nodis3.gsfc.nasa.gov/displayDir.cfm?Internal_ID=N_PR_7150_002D_&page_name=AppendixD)
|
|
277
277
|
|
|
@@ -306,23 +306,23 @@ The fmdtools documentation repository is also home to the Functional Reasoning D
|
|
|
306
306
|
|
|
307
307
|
### Python version compatibility
|
|
308
308
|
|
|
309
|
-
The fmdtools library is developed in Python 3.
|
|
309
|
+
The fmdtools library is developed in Python 3.13 but is tested to maintain compatibility over three versions of Python. See current doctest reports below:
|
|
310
310
|
|
|
311
311
|
| Python Version | Doctests |
|
|
312
312
|
| -------- | ------- |
|
|
313
|
-
| 3.
|
|
314
|
-
| 3.
|
|
315
|
-
| 3.
|
|
313
|
+
| 3.11 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py311/junit/report.html) |
|
|
314
|
+
| 3.12 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py312/junit/report.html) |
|
|
315
|
+
| 3.13 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py313/junit/report.html) |
|
|
316
316
|
|
|
317
|
-
Further (functional and integration) tests are performed in the Python 3.
|
|
317
|
+
Further (functional and integration) tests are performed in the Python 3.13 to ensure that examples run as desired. Thus, it is generally reccommended to use Python 3.13 with this version to keep pace with development, especially when running examples.
|
|
318
318
|
|
|
319
319
|
### Set up python tooling environment
|
|
320
320
|
|
|
321
321
|
The fmdtools library was developed to run in a python development environments.
|
|
322
322
|
|
|
323
|
-
If you do not have an existing python environment, first [download and install anaconda](https://docs.anaconda.com/free/anaconda/install/index.html) or [uv]().
|
|
323
|
+
If you do not have an existing python environment, first [download and install anaconda](https://docs.anaconda.com/free/anaconda/install/index.html) or [uv](https://docs.astral.sh/uv/).
|
|
324
324
|
|
|
325
|
-
After the base installation, set up a new `Python 3.
|
|
325
|
+
After the base installation, set up a new `Python 3.13` environment for fmdtools and install these external external packages in it:
|
|
326
326
|
|
|
327
327
|
```
|
|
328
328
|
spyder-kernels
|
|
@@ -367,13 +367,13 @@ 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.
|
|
370
|
+
git checkout v2.2.0
|
|
371
371
|
```
|
|
372
372
|
|
|
373
373
|
|
|
374
374
|
#### Dependencies
|
|
375
375
|
|
|
376
|
-
fmdtools requires `Python 3.
|
|
376
|
+
fmdtools requires `Python 3.13` and depends directly on the packages below (see requirements.txt). Note that the use of these depencencies is governed by their respective licences, which may be obtained at the provided links.
|
|
377
377
|
|
|
378
378
|
```
|
|
379
379
|
scipy
|
|
@@ -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.
|
|
509
|
-
date = {2025-
|
|
508
|
+
version = {2.2.0},
|
|
509
|
+
date = {2025-6-6},
|
|
510
510
|
}
|
|
511
511
|
```
|
|
512
512
|
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# Overview
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
[](https://pypi.org/project/fmdtools/)
|
|
7
7
|
[](https://pepy.tech/project/fmdtools)
|
|
8
8
|
[](https://pepy.tech/project/fmdtools)
|
|
9
9
|
[](https://github.com/nasa/fmdtools/releases)
|
|
10
10
|
[](https://github.com/nasa/fmdtools/tags)
|
|
11
11
|
[](https://www.codefactor.io/repository/github/nasa/fmdtools)
|
|
12
|
-
[](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py313/junit/report.html)
|
|
13
|
+
[](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py313/coverage_html/index.html)
|
|
14
14
|
[](https://github.com/nasa/fmdtools/blob/main/LICENSE)
|
|
15
15
|
[](https://nodis3.gsfc.nasa.gov/displayDir.cfm?Internal_ID=N_PR_7150_002D_&page_name=AppendixD)
|
|
16
16
|
|
|
@@ -45,23 +45,23 @@ The fmdtools documentation repository is also home to the Functional Reasoning D
|
|
|
45
45
|
|
|
46
46
|
### Python version compatibility
|
|
47
47
|
|
|
48
|
-
The fmdtools library is developed in Python 3.
|
|
48
|
+
The fmdtools library is developed in Python 3.13 but is tested to maintain compatibility over three versions of Python. See current doctest reports below:
|
|
49
49
|
|
|
50
50
|
| Python Version | Doctests |
|
|
51
51
|
| -------- | ------- |
|
|
52
|
-
| 3.
|
|
53
|
-
| 3.
|
|
54
|
-
| 3.
|
|
52
|
+
| 3.11 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py311/junit/report.html) |
|
|
53
|
+
| 3.12 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py312/junit/report.html) |
|
|
54
|
+
| 3.13 | [](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py313/junit/report.html) |
|
|
55
55
|
|
|
56
|
-
Further (functional and integration) tests are performed in the Python 3.
|
|
56
|
+
Further (functional and integration) tests are performed in the Python 3.13 to ensure that examples run as desired. Thus, it is generally reccommended to use Python 3.13 with this version to keep pace with development, especially when running examples.
|
|
57
57
|
|
|
58
58
|
### Set up python tooling environment
|
|
59
59
|
|
|
60
60
|
The fmdtools library was developed to run in a python development environments.
|
|
61
61
|
|
|
62
|
-
If you do not have an existing python environment, first [download and install anaconda](https://docs.anaconda.com/free/anaconda/install/index.html) or [uv]().
|
|
62
|
+
If you do not have an existing python environment, first [download and install anaconda](https://docs.anaconda.com/free/anaconda/install/index.html) or [uv](https://docs.astral.sh/uv/).
|
|
63
63
|
|
|
64
|
-
After the base installation, set up a new `Python 3.
|
|
64
|
+
After the base installation, set up a new `Python 3.13` environment for fmdtools and install these external external packages in it:
|
|
65
65
|
|
|
66
66
|
```
|
|
67
67
|
spyder-kernels
|
|
@@ -106,13 +106,13 @@ 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.
|
|
109
|
+
git checkout v2.2.0
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
#### Dependencies
|
|
114
114
|
|
|
115
|
-
fmdtools requires `Python 3.
|
|
115
|
+
fmdtools requires `Python 3.13` and depends directly on the packages below (see requirements.txt). Note that the use of these depencencies is governed by their respective licences, which may be obtained at the provided links.
|
|
116
116
|
|
|
117
117
|
```
|
|
118
118
|
scipy
|
|
@@ -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.
|
|
248
|
-
date = {2025-
|
|
247
|
+
version = {2.2.0},
|
|
248
|
+
date = {2025-6-6},
|
|
249
249
|
}
|
|
250
250
|
```
|
|
251
251
|
|
|
@@ -33,7 +33,6 @@ class OutcomeStates(State):
|
|
|
33
33
|
|
|
34
34
|
class Outcome(Flow):
|
|
35
35
|
|
|
36
|
-
__slots__ = ()
|
|
37
36
|
container_s = OutcomeStates
|
|
38
37
|
|
|
39
38
|
|
|
@@ -47,7 +46,6 @@ class HazardState(State):
|
|
|
47
46
|
|
|
48
47
|
class Hazard(Flow):
|
|
49
48
|
|
|
50
|
-
__slots__ = ()
|
|
51
49
|
container_s = HazardState
|
|
52
50
|
|
|
53
51
|
|
|
@@ -61,12 +59,11 @@ class ActionMode(Mode):
|
|
|
61
59
|
class Perceive(Action):
|
|
62
60
|
"""A user's perception abilities/behaviors for percieving the hazard."""
|
|
63
61
|
|
|
64
|
-
__slots__ = ('hazard', 'outcome')
|
|
65
62
|
container_m = ActionMode
|
|
66
63
|
flow_hazard = Hazard
|
|
67
64
|
flow_outcome = Outcome
|
|
68
65
|
|
|
69
|
-
def
|
|
66
|
+
def dynamic_behavior(self):
|
|
70
67
|
if not self.m.in_mode('failed', 'unable'):
|
|
71
68
|
self.hazard.s.percieved = self.hazard.s.present
|
|
72
69
|
self.outcome.s.num_perceptions += self.hazard.s.percieved
|
|
@@ -81,12 +78,11 @@ class Perceive(Action):
|
|
|
81
78
|
class Act(Action):
|
|
82
79
|
"""User actions to mitigate the hazard."""
|
|
83
80
|
|
|
84
|
-
__slots__ = ('hazard', 'outcome')
|
|
85
81
|
container_m = ActionMode
|
|
86
82
|
flow_hazard = Hazard
|
|
87
83
|
flow_outcome = Outcome
|
|
88
84
|
|
|
89
|
-
def
|
|
85
|
+
def dynamic_behavior(self):
|
|
90
86
|
if not self.m.in_mode('failed', 'unable'):
|
|
91
87
|
self.outcome.s.num_actions += 1
|
|
92
88
|
self.hazard.s.mitigated = True
|
|
@@ -103,10 +99,9 @@ class Act(Action):
|
|
|
103
99
|
class Done(Action):
|
|
104
100
|
"""User state after performing the action."""
|
|
105
101
|
|
|
106
|
-
__slots__ = ('hazard')
|
|
107
102
|
flow_hazard = Hazard
|
|
108
103
|
|
|
109
|
-
def
|
|
104
|
+
def dynamic_behavior(self):
|
|
110
105
|
if not self.hazard.s.present:
|
|
111
106
|
self.hazard.s.mitigated = False
|
|
112
107
|
|
|
@@ -136,7 +131,6 @@ class Human(ActionArchitecture):
|
|
|
136
131
|
class DetectHazard(Function):
|
|
137
132
|
"""Function containing the human."""
|
|
138
133
|
|
|
139
|
-
__slots__ = ('hazard')
|
|
140
134
|
container_m = Mode
|
|
141
135
|
arch_aa = Human
|
|
142
136
|
flow_hazard = Hazard
|
|
@@ -145,11 +139,10 @@ class DetectHazard(Function):
|
|
|
145
139
|
class ProduceHazard(Function):
|
|
146
140
|
"""Function producing Hazards."""
|
|
147
141
|
|
|
148
|
-
__slots__ = ('hazard',)
|
|
149
142
|
flow_hazard = Hazard
|
|
150
143
|
|
|
151
|
-
def dynamic_behavior(self
|
|
152
|
-
if not time % 4:
|
|
144
|
+
def dynamic_behavior(self):
|
|
145
|
+
if not self.t.time % 4:
|
|
153
146
|
self.hazard.s.present = True
|
|
154
147
|
else:
|
|
155
148
|
self.hazard.s.present = False
|
|
@@ -165,11 +158,10 @@ class PassStates(State):
|
|
|
165
158
|
class PassHazard(Function):
|
|
166
159
|
"""Accumulates total hazards/mitigations."""
|
|
167
160
|
|
|
168
|
-
__slots__ = ('hazard',)
|
|
169
161
|
container_s = PassStates
|
|
170
162
|
flow_hazard = Hazard
|
|
171
163
|
|
|
172
|
-
def dynamic_behavior(self
|
|
164
|
+
def dynamic_behavior(self):
|
|
173
165
|
if self.hazard.s.present and self.hazard.s.mitigated:
|
|
174
166
|
self.s.hazards_mitigated += 1
|
|
175
167
|
elif self.hazard.s.present and not self.hazard.s.mitigated:
|
|
@@ -179,7 +171,6 @@ class PassHazard(Function):
|
|
|
179
171
|
class HazardModel(FunctionArchitecture):
|
|
180
172
|
"""Overall model of the human in context."""
|
|
181
173
|
|
|
182
|
-
__slots__ = ()
|
|
183
174
|
default_sp = dict(end_time=60, dt=1.0)
|
|
184
175
|
|
|
185
176
|
def init_architecture(self, **kwargs):
|
|
@@ -194,9 +185,9 @@ if __name__ == '__main__':
|
|
|
194
185
|
mdl = HazardModel()
|
|
195
186
|
result_fault, mdlhist_fault = prop.one_fault(mdl, 'detect_hazard.aa.acts.act',
|
|
196
187
|
'unable', time=4,
|
|
197
|
-
|
|
188
|
+
to_return='graph')
|
|
198
189
|
|
|
199
|
-
result_fault.graph.draw()
|
|
190
|
+
result_fault.get_faulty().tend.graph.draw()
|
|
200
191
|
ex_fxn = DetectHazard('detect_hazard')
|
|
201
192
|
result_indiv, hist_indiv = prop.nominal(ex_fxn,
|
|
202
193
|
disturbances={5:{'aa.flows.hazard.s.present':True}})
|
|
@@ -206,5 +197,5 @@ if __name__ == '__main__':
|
|
|
206
197
|
|
|
207
198
|
result_fault, mdlhist_fault = prop.one_fault(mdl, 'detect_hazard.aa.acts.perceive',
|
|
208
199
|
'failed', time=4,
|
|
209
|
-
|
|
210
|
-
result_fault.graph.fxns.detect_hazard.aa.draw_graphviz(layout='dot')
|
|
200
|
+
to_return='graph.fxns.detect_hazard.aa')
|
|
201
|
+
result_fault.get_faulty().tend.graph.fxns.detect_hazard.aa.draw_graphviz(layout='dot')
|
|
@@ -44,7 +44,6 @@ class GenericState(State):
|
|
|
44
44
|
|
|
45
45
|
class GenericFlow(Flow):
|
|
46
46
|
|
|
47
|
-
__slots__ = ()
|
|
48
47
|
container_s = GenericState
|
|
49
48
|
|
|
50
49
|
|
|
@@ -53,7 +52,6 @@ class SigState(State):
|
|
|
53
52
|
|
|
54
53
|
|
|
55
54
|
class Signal(Flow):
|
|
56
|
-
__slots__ = ()
|
|
57
55
|
container_s = SigState
|
|
58
56
|
|
|
59
57
|
|
|
@@ -65,7 +63,6 @@ class ImportEEModes(Mode):
|
|
|
65
63
|
|
|
66
64
|
class ImportEE(Function):
|
|
67
65
|
|
|
68
|
-
__slots__ = ("ee_out",)
|
|
69
66
|
container_m = ImportEEModes
|
|
70
67
|
flow_ee_out = GenericFlow
|
|
71
68
|
flownames = {"ee_1": "ee_out"}
|
|
@@ -84,7 +81,7 @@ class ImportEE(Function):
|
|
|
84
81
|
Both representations can be used--this just shows this representation.
|
|
85
82
|
"""
|
|
86
83
|
|
|
87
|
-
def static_behavior(self
|
|
84
|
+
def static_behavior(self):
|
|
88
85
|
if self.m.has_fault("no_v"):
|
|
89
86
|
self.ee_out.s.effort = 0.0
|
|
90
87
|
elif self.m.has_fault("high_v"):
|
|
@@ -102,12 +99,11 @@ class ImportSigModes(Mode):
|
|
|
102
99
|
|
|
103
100
|
class ImportSig(Function):
|
|
104
101
|
|
|
105
|
-
__slots__ = ("sig_out",)
|
|
106
102
|
container_m = ImportSigModes
|
|
107
103
|
flow_sig_out = Signal
|
|
108
104
|
flownames = {"sig_in": "sig_out"}
|
|
109
105
|
|
|
110
|
-
def static_behavior(self
|
|
106
|
+
def static_behavior(self):
|
|
111
107
|
if self.m.has_fault("partial_signal"):
|
|
112
108
|
self.sig_out.s.value = 0.5
|
|
113
109
|
elif self.m.has_fault("no_signal"):
|
|
@@ -123,7 +119,6 @@ class StoreEEModes(Mode):
|
|
|
123
119
|
|
|
124
120
|
class StoreEE(Function):
|
|
125
121
|
|
|
126
|
-
__slots__ = ("ee_in", "ee_out")
|
|
127
122
|
container_m = StoreEEModes
|
|
128
123
|
flow_ee_in = GenericFlow
|
|
129
124
|
flow_ee_out = GenericFlow
|
|
@@ -135,7 +130,7 @@ class StoreEE(Function):
|
|
|
135
130
|
elif self.ee_out.s.effort * self.ee_out.s.rate >= 2.0:
|
|
136
131
|
self.m.add_fault("low_storage")
|
|
137
132
|
|
|
138
|
-
def static_behavior(self
|
|
133
|
+
def static_behavior(self):
|
|
139
134
|
self.set_faults()
|
|
140
135
|
if self.m.has_fault("no_storage"):
|
|
141
136
|
self.ee_out.s.effort = 0.0
|
|
@@ -158,7 +153,6 @@ class SupplyEEModes(Mode):
|
|
|
158
153
|
|
|
159
154
|
class SupplyEE(Function):
|
|
160
155
|
|
|
161
|
-
__slots__ = ("ee_in", "ee_out", "heat_out")
|
|
162
156
|
container_m = SupplyEEModes
|
|
163
157
|
flow_ee_in = GenericFlow
|
|
164
158
|
flow_ee_out = GenericFlow
|
|
@@ -171,7 +165,7 @@ class SupplyEE(Function):
|
|
|
171
165
|
elif self.ee_out.s.rate > 1.0:
|
|
172
166
|
self.m.add_fault("open_circuit")
|
|
173
167
|
|
|
174
|
-
def static_behavior(self
|
|
168
|
+
def static_behavior(self):
|
|
175
169
|
self.set_faults()
|
|
176
170
|
if self.m.has_fault("open_circuit"):
|
|
177
171
|
self.ee_out.s.effort = 0.0
|
|
@@ -201,7 +195,6 @@ class DistEEModes(Mode):
|
|
|
201
195
|
|
|
202
196
|
class DistEE(Function):
|
|
203
197
|
|
|
204
|
-
__slots__ = ("sig_in", "ee_in", "ee_m", "ee_h", "ee_o")
|
|
205
198
|
container_m = DistEEModes
|
|
206
199
|
flow_sig_in = Signal
|
|
207
200
|
flow_ee_in = GenericFlow
|
|
@@ -214,7 +207,7 @@ class DistEE(Function):
|
|
|
214
207
|
if max(self.ee_m.s.rate, self.ee_h.s.rate, self.ee_o.s.rate) > 2.0:
|
|
215
208
|
self.m.add_fault("short")
|
|
216
209
|
|
|
217
|
-
def static_behavior(self
|
|
210
|
+
def static_behavior(self):
|
|
218
211
|
self.set_faults()
|
|
219
212
|
if self.m.has_fault("short"):
|
|
220
213
|
self.ee_in.s.rate = self.ee_in.s.effort * 4.0
|
|
@@ -253,12 +246,11 @@ class ExportHEModes(Mode):
|
|
|
253
246
|
|
|
254
247
|
class ExportHE(Function):
|
|
255
248
|
|
|
256
|
-
__slots__ = ("he",)
|
|
257
249
|
container_m = ExportHEModes
|
|
258
250
|
flow_he = GenericFlow
|
|
259
251
|
flownames = {"waste_he_1": "he", "waste_he_o": "he", "waste_he_m": "he"}
|
|
260
252
|
|
|
261
|
-
def static_behavior(self
|
|
253
|
+
def static_behavior(self):
|
|
262
254
|
if self.m.has_fault("ineffective_sink"):
|
|
263
255
|
self.he.s.rate = 4.0
|
|
264
256
|
elif self.m.has_fault("hot_sink"):
|
|
@@ -269,19 +261,17 @@ class ExportHE(Function):
|
|
|
269
261
|
|
|
270
262
|
class ExportME(Function):
|
|
271
263
|
|
|
272
|
-
__slots__ = ("me",)
|
|
273
264
|
flow_me = GenericFlow
|
|
274
265
|
|
|
275
|
-
def static_behavior(self
|
|
266
|
+
def static_behavior(self):
|
|
276
267
|
self.me.s.rate = self.me.s.effort
|
|
277
268
|
|
|
278
269
|
|
|
279
270
|
class ExportOE(Function):
|
|
280
271
|
|
|
281
|
-
__slots__ = ("oe",)
|
|
282
272
|
flow_oe = GenericFlow
|
|
283
273
|
|
|
284
|
-
def static_behavior(self
|
|
274
|
+
def static_behavior(self):
|
|
285
275
|
self.oe.s.rate = self.oe.s.effort
|
|
286
276
|
|
|
287
277
|
|
|
@@ -295,14 +285,13 @@ class EEtoMEModes(Mode):
|
|
|
295
285
|
|
|
296
286
|
class EEtoME(Function):
|
|
297
287
|
|
|
298
|
-
__slots__ = ("ee_in", "me", "he_out")
|
|
299
288
|
container_m = EEtoMEModes
|
|
300
289
|
flow_ee_in = GenericFlow
|
|
301
290
|
flow_me = GenericFlow
|
|
302
291
|
flow_he_out = GenericFlow
|
|
303
292
|
flownames = {"ee_m": "ee_in", "waste_he_m": "he_out"}
|
|
304
293
|
|
|
305
|
-
def static_behavior(self
|
|
294
|
+
def static_behavior(self):
|
|
306
295
|
if self.m.has_fault("high_torque"):
|
|
307
296
|
self.he_out.s.effort = self.ee_in.s.effort + 1.0
|
|
308
297
|
self.me.s.effort = self.ee_in.s.effort + 1.0
|
|
@@ -341,7 +330,6 @@ class EEtoHEModes(Mode):
|
|
|
341
330
|
|
|
342
331
|
class EEtoHE(Function):
|
|
343
332
|
|
|
344
|
-
__slots__ = ("ee_in", "he")
|
|
345
333
|
container_m = EEtoHEModes
|
|
346
334
|
flow_ee_in = GenericFlow
|
|
347
335
|
flow_he = GenericFlow
|
|
@@ -353,7 +341,7 @@ class EEtoHE(Function):
|
|
|
353
341
|
elif self.ee_in.s.effort > 1.0:
|
|
354
342
|
self.m.add_fault("low_heat")
|
|
355
343
|
|
|
356
|
-
def static_behavior(self
|
|
344
|
+
def static_behavior(self):
|
|
357
345
|
if self.m.has_fault("open_circuit"):
|
|
358
346
|
self.he.s.effort = 0.0
|
|
359
347
|
self.ee_in.s.rate = 0.0
|
|
@@ -378,7 +366,6 @@ class EEtoOEModes(Mode):
|
|
|
378
366
|
|
|
379
367
|
class EEtoOE(Function):
|
|
380
368
|
|
|
381
|
-
__slots__ = ("ee_in", "oe", "he_out")
|
|
382
369
|
container_m = EEtoOEModes
|
|
383
370
|
flow_ee_in = GenericFlow
|
|
384
371
|
flow_oe = GenericFlow
|
|
@@ -389,7 +376,7 @@ class EEtoOE(Function):
|
|
|
389
376
|
if self.ee_in.s.effort >= 2.0:
|
|
390
377
|
self.m.add_fault("burnt_out")
|
|
391
378
|
|
|
392
|
-
def static_behavior(self
|
|
379
|
+
def static_behavior(self):
|
|
393
380
|
if self.m.has_fault("burnt_out"):
|
|
394
381
|
self.ee_in.s.rate = 0.0
|
|
395
382
|
self.he_out.s.effort = 0.0
|
|
@@ -406,7 +393,6 @@ class EEtoOE(Function):
|
|
|
406
393
|
|
|
407
394
|
class EPS(FunctionArchitecture):
|
|
408
395
|
|
|
409
|
-
__slots__ = ()
|
|
410
396
|
default_track = {"flows": ["he", "me", "oe"]}
|
|
411
397
|
default_sp = {'end_time': 0}
|
|
412
398
|
|
|
@@ -444,7 +430,7 @@ class EPS(FunctionArchitecture):
|
|
|
444
430
|
self.add_fxn("export_waste_ho", ExportHE, "waste_he_o")
|
|
445
431
|
self.add_fxn("export_waste_hm", ExportHE, "waste_he_m")
|
|
446
432
|
|
|
447
|
-
def
|
|
433
|
+
def classify(self, scen={}, mdlhists={}, **kwargs):
|
|
448
434
|
outflows = ["he", "me", "oe"]
|
|
449
435
|
|
|
450
436
|
qualfunc = [
|
|
@@ -493,12 +479,12 @@ if __name__ == "__main__":
|
|
|
493
479
|
result, mdlhists = propagate.one_fault(mdl, "distribute_ee", "short")
|
|
494
480
|
|
|
495
481
|
result, mdlhists = propagate.one_fault(mdl, "distribute_ee", "short",
|
|
496
|
-
|
|
482
|
+
to_return="graph")
|
|
497
483
|
|
|
498
|
-
result.graph.draw()
|
|
484
|
+
result.get_faulty().tend.graph.draw()
|
|
499
485
|
# endclasses, mdlhists = propagate.single_faults(mdl)
|
|
500
486
|
|
|
501
|
-
# resgraph, mdlhists = propagate.one_fault(mdl, 'ee_to_me', 'toohigh_torque',
|
|
487
|
+
# resgraph, mdlhists = propagate.one_fault(mdl, 'ee_to_me', 'toohigh_torque', to_return="fxnflowgraph")
|
|
502
488
|
# result.graph.draw()
|
|
503
489
|
ks = [*mdl.get_roles_as_dict("fxn", "flow", flex_prefixes=True)]
|
|
504
490
|
|
|
@@ -39,16 +39,18 @@ class epsTests(unittest.TestCase, CommonTests):
|
|
|
39
39
|
backwards through the graph as expected - distributor short leads to empty battery
|
|
40
40
|
"""
|
|
41
41
|
res, hist = prop.one_fault(self.mdl, "distribute_ee", "short",
|
|
42
|
-
|
|
43
|
-
self.assertEqual(res
|
|
42
|
+
to_return="faults")
|
|
43
|
+
self.assertEqual(res.get_faulty().tend.faults,
|
|
44
|
+
['store_ee.no_storage', 'distribute_ee.short'])
|
|
44
45
|
|
|
45
46
|
def test_backward_fault_prop_2(self):
|
|
46
47
|
"""Tests that defined fault cases that require reverse propagation propagate
|
|
47
48
|
backwards through the graph as expected - motor short leads to distributor short
|
|
48
49
|
"""
|
|
49
50
|
res, hist = prop.one_fault(self.mdl, "ee_to_me", "short",
|
|
50
|
-
|
|
51
|
-
self.assertEqual(res
|
|
51
|
+
to_return="faults")
|
|
52
|
+
self.assertEqual(res.get_faulty().tend.faults,
|
|
53
|
+
['store_ee.no_storage', 'distribute_ee.short', 'ee_to_me.short'])
|
|
52
54
|
|
|
53
55
|
def test_all_faults(self):
|
|
54
56
|
"""Some basic tests for propagating lists of faults in the model--
|
|
@@ -82,7 +84,6 @@ class epsTests(unittest.TestCase, CommonTests):
|
|
|
82
84
|
fs.add_fault_phases(n_joint=n_joint)
|
|
83
85
|
# tests the length
|
|
84
86
|
self.assertEqual(len(fs.scenarios()), math.comb(actual_num_faults, n_joint))
|
|
85
|
-
ec, hists = prop.fault_sample(self.mdl, fs, showprogress=False)
|
|
86
87
|
|
|
87
88
|
def test_pickleability(self):
|
|
88
89
|
unpickleable = check_pickleability(self.mdl, verbose=False)
|
|
@@ -117,9 +118,17 @@ class epsTests(unittest.TestCase, CommonTests):
|
|
|
117
118
|
|
|
118
119
|
|
|
119
120
|
if __name__ == "__main__":
|
|
121
|
+
import sys
|
|
122
|
+
sys.path.append("../..")
|
|
123
|
+
|
|
124
|
+
# suite = unittest.TestSuite()
|
|
125
|
+
# suite.addTest(epsTests("test_fault_app"))
|
|
126
|
+
# runner = unittest.TextTestRunner()
|
|
127
|
+
# runner.run(suite)
|
|
128
|
+
|
|
120
129
|
unittest.main()
|
|
121
130
|
|
|
122
|
-
mdl = EPS()
|
|
131
|
+
# mdl = EPS()
|
|
123
132
|
|
|
124
133
|
|
|
125
134
|
# endresults, resgraph, mdlhist = propagate.one_fault(mdl, 'Distribute_EE', 'short')
|