fmdtools 2.1.0__tar.gz → 2.1.2__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.
Files changed (104) hide show
  1. {fmdtools-2.1.0 → fmdtools-2.1.2}/LICENSE +1 -1
  2. {fmdtools-2.1.0 → fmdtools-2.1.2}/PKG-INFO +25 -15
  3. {fmdtools-2.1.0 → fmdtools-2.1.2}/README.md +21 -12
  4. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/drone_mdl_rural.py +1 -2
  5. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/rover_mode_space.py +27 -30
  6. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/rover_model.py +26 -64
  7. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/__init__.py +1 -1
  8. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/graph/style.py +26 -26
  9. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/tabulate.py +10 -10
  10. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/block/base.py +14 -7
  11. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/base.py +2 -2
  12. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/mode.py +44 -92
  13. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/environment.py +1 -1
  14. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/flow/commsflow.py +7 -6
  15. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/flow/multiflow.py +10 -4
  16. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/object/coords.py +29 -24
  17. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/sim/propagate.py +5 -15
  18. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/sim/sample.py +121 -8
  19. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/sim/scenario.py +22 -9
  20. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools.egg-info/PKG-INFO +25 -15
  21. {fmdtools-2.1.0 → fmdtools-2.1.2}/pyproject.toml +1 -1
  22. {fmdtools-2.1.0 → fmdtools-2.1.2}/tests/test_hierarchical.py +7 -21
  23. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/__init__.py +0 -0
  24. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/asg_demo/__init__.py +0 -0
  25. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/asg_demo/demo_model.py +0 -0
  26. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/eps/__init__.py +0 -0
  27. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/eps/eps.py +0 -0
  28. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/eps/test_eps.py +0 -0
  29. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multiflow_demo/__init__.py +0 -0
  30. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multiflow_demo/multiflow_demo.py +0 -0
  31. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multiflow_demo/test_multiflow.py +0 -0
  32. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/__init__.py +0 -0
  33. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/drone_mdl_dynamic.py +0 -0
  34. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/drone_mdl_hierarchical.py +0 -0
  35. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/drone_mdl_static.py +0 -0
  36. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/drone_mdl_urban.py +0 -0
  37. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/opt_drone_rural.py +0 -0
  38. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/multirotor/test_multirotor.py +0 -0
  39. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/__init__.py +0 -0
  40. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/ex_pump.py +0 -0
  41. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/jointfaults_ex.py +0 -0
  42. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/parallelism_methods.py +0 -0
  43. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/pump_indiv.py +0 -0
  44. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/pump_stochastic.py +0 -0
  45. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/test_pump.py +0 -0
  46. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/test_pump_example.py +0 -0
  47. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/pump/test_pump_stochastic.py +0 -0
  48. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/__init__.py +0 -0
  49. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/optimization/ea_analysis.py +0 -0
  50. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/optimization/search_rover.py +0 -0
  51. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/rover_degradation.py +0 -0
  52. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/rover_model_human.py +0 -0
  53. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/rover/test_rover.py +0 -0
  54. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/tank/__init__.py +0 -0
  55. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/tank/tank_model.py +0 -0
  56. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/tank/tank_optimization_model.py +0 -0
  57. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/tank/test_tank.py +0 -0
  58. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/ATC.py +0 -0
  59. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/asset.py +0 -0
  60. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/common.py +0 -0
  61. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/model.py +0 -0
  62. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/test_asset.py +0 -0
  63. {fmdtools-2.1.0 → fmdtools-2.1.2}/examples/taxiway/test_model.py +0 -0
  64. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/__init__.py +0 -0
  65. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/common.py +0 -0
  66. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/graph/__init__.py +0 -0
  67. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/graph/base.py +0 -0
  68. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/graph/label.py +0 -0
  69. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/graph/model.py +0 -0
  70. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/history.py +0 -0
  71. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/phases.py +0 -0
  72. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/analyze/result.py +0 -0
  73. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/__init__.py +0 -0
  74. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/__init__.py +0 -0
  75. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/action.py +0 -0
  76. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/base.py +0 -0
  77. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/component.py +0 -0
  78. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/function.py +0 -0
  79. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/architecture/geom.py +0 -0
  80. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/base.py +0 -0
  81. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/block/__init__.py +0 -0
  82. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/block/action.py +0 -0
  83. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/block/component.py +0 -0
  84. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/block/function.py +0 -0
  85. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/__init__.py +0 -0
  86. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/parameter.py +0 -0
  87. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/rand.py +0 -0
  88. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/state.py +0 -0
  89. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/container/time.py +0 -0
  90. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/flow/__init__.py +0 -0
  91. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/flow/base.py +0 -0
  92. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/object/__init__.py +0 -0
  93. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/object/base.py +0 -0
  94. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/object/geom.py +0 -0
  95. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/define/object/timer.py +0 -0
  96. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/sim/__init__.py +0 -0
  97. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools/sim/search.py +0 -0
  98. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools.egg-info/SOURCES.txt +0 -0
  99. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools.egg-info/dependency_links.txt +0 -0
  100. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools.egg-info/requires.txt +0 -0
  101. {fmdtools-2.1.0 → fmdtools-2.1.2}/fmdtools.egg-info/top_level.txt +0 -0
  102. {fmdtools-2.1.0 → fmdtools-2.1.2}/setup.cfg +0 -0
  103. {fmdtools-2.1.0 → fmdtools-2.1.2}/tests/test_graph.py +0 -0
  104. {fmdtools-2.1.0 → fmdtools-2.1.2}/tests/test_packages.py +0 -0
@@ -1,4 +1,4 @@
1
- fmdtools version 2.1.0
1
+ fmdtools version 2.1.2
2
2
  ---------------------------
3
3
  Apache License
4
4
  Version 2.0, January 2004
@@ -1,10 +1,10 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: fmdtools
3
- Version: 2.1.0
3
+ Version: 2.1.2
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.0
7
+ License: fmdtools version 2.1.2
8
8
  ---------------------------
9
9
  Apache License
10
10
  Version 2.0, January 2004
@@ -257,6 +257,7 @@ Requires-Dist: recordclass==0.22.1
257
257
  Requires-Dist: pytest
258
258
  Requires-Dist: graphviz
259
259
  Requires-Dist: shapely>=2.0
260
+ Dynamic: license-file
260
261
 
261
262
  [![fmdtools logo - titanic](/docs-source/figures/logo/logo-titanic.png)](https://github.com/nasa/fmdtools)
262
263
 
@@ -296,9 +297,10 @@ Simulation techniques in fmdtools represent the state-of-the-art in dynamical sy
296
297
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/efficient.svg">
297
298
 
298
299
  ### Efficient Analysis Process
299
- Readily-deployable analysis methods are built in to fmdtools to enable the rapid and iterative statistical analysis of simulation results. With fmdtools, you can write 2-3 lines of code to visualize model behavior instead of spending hours writing it yourself.
300
+ Readily-deployable analysis methods are built in to fmdtools to enable the rapid and iterative statistical analysis of simulation results. With fmdtools, you can easily leverage our existing methods to understand simulation results instead of spending hours implementing your own.
300
301
 
301
302
 
303
+ The fmdtools documentation repository is also home to the Functional Reasoning Design Language specification, a graphical language that may be used to represent the structure of behavioral interactions in a system to inform hazard analysis.
302
304
 
303
305
  ## Getting Started
304
306
 
@@ -314,23 +316,31 @@ The fmdtools library is developed in Python 3.11 but tested to maintain compatib
314
316
 
315
317
  Further (functional and integration) tests are performed in the Python 3.11 to ensure that examples run as desired. Thus, it is generally reccommended to use Python 3.11 to keep pace with development, especially when running examples.
316
318
 
317
- ### Set up python environment
319
+ ### Set up python tooling environment
318
320
 
319
- The fmdtools library was developed to run in an anaconda python environment. If you do not have an existing python environment, first [download and install anaconda.](https://docs.anaconda.com/free/anaconda/install/index.html).
321
+ The fmdtools library was developed to run in a python development environments.
320
322
 
321
- After the base installation, set up a new `Python 3.11` environment for fmdtools and install these external external (non-python) packages in it:
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]().
324
+
325
+ After the base installation, set up a new `Python 3.11` environment for fmdtools and install these external external packages in it:
322
326
 
323
327
  ```
328
+ spyder-kernels
329
+ # used for: working with external IDEs
330
+ # license: ()
331
+ # install from: (comes with anaconda) or `uv pip install spyder-kernels`
324
332
  jupyter notebook
325
333
  # used for: repository notebooks
326
334
  # license: (BSD-3) https://jupyter.org/governance/projectlicense.html
327
- # install from: (should be installed already)
335
+ # install from: (comes with anaconda) or `uv pip install jupyter`
328
336
  graphviz
329
337
  # used for: plotting graphs using graphviz
330
338
  # license: (CPL 1.0) https://graphviz.org/license/
331
- # install from: https://anaconda.org/anaconda/graphviz
339
+ # install from: https://anaconda.org/anaconda/graphviz or https://graphviz.org/download/
332
340
  ```
333
341
 
342
+ From there, it can be helpful to install an IDE like [VSCode](https://code.visualstudio.com/) or [Spyder](https://www.spyder-ide.org/).
343
+
334
344
  Note: On Windows, some versions `fmdtools` dependencies may require a compiler such as that provided with [Microsoft Studio Build tools](https://visualstudio.microsoft.com/downloads/?q=build+tools) to build, so it (while not required) may be helpful to install it also.
335
345
 
336
346
 
@@ -357,13 +367,13 @@ This may then be installed using:
357
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.:
358
368
 
359
369
  ```
360
- git checkout v2.1.0
370
+ git checkout v2.1.2
361
371
  ```
362
372
 
363
373
 
364
374
  #### Dependencies
365
375
 
366
- fmdtools requires `Python 3.11` (anaconda recommended) 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.
376
+ fmdtools requires `Python 3.11` 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.
367
377
 
368
378
  ```
369
379
  scipy
@@ -491,16 +501,16 @@ To cite fmdtools in general, you may cite our explanatory publication:
491
501
  To cite a particular version of the fmdtools, you may use:
492
502
 
493
503
  ```
494
- @software{nasa2024fmdtools,
504
+ @software{nasa2025fmdtools,
495
505
  author = {{NASA}},
496
506
  title = {fmdtools},
497
507
  url = {https://github.com/nasa/fmdtools},
498
- version = {2.1.0},
499
- date = {2024-11-13},
508
+ version = {2.1.2},
509
+ date = {2025-5-19},
500
510
  }
501
511
  ```
502
512
 
503
- To cite a particular fmdtools example or published research methodology, use the relevant reference provided in the in accompanying README file for the example.
513
+ To cite a particular fmdtools example use the relevant reference provided in the in accompanying README file for the example. To cite a given published research methodology embodied by fmdtools, see our [publication list](PUBLICATIONS.md).
504
514
 
505
515
  ## License/Notices
506
516
 
@@ -36,9 +36,10 @@ Simulation techniques in fmdtools represent the state-of-the-art in dynamical sy
36
36
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/efficient.svg">
37
37
 
38
38
  ### Efficient Analysis Process
39
- Readily-deployable analysis methods are built in to fmdtools to enable the rapid and iterative statistical analysis of simulation results. With fmdtools, you can write 2-3 lines of code to visualize model behavior instead of spending hours writing it yourself.
39
+ Readily-deployable analysis methods are built in to fmdtools to enable the rapid and iterative statistical analysis of simulation results. With fmdtools, you can easily leverage our existing methods to understand simulation results instead of spending hours implementing your own.
40
40
 
41
41
 
42
+ The fmdtools documentation repository is also home to the Functional Reasoning Design Language specification, a graphical language that may be used to represent the structure of behavioral interactions in a system to inform hazard analysis.
42
43
 
43
44
  ## Getting Started
44
45
 
@@ -54,23 +55,31 @@ The fmdtools library is developed in Python 3.11 but tested to maintain compatib
54
55
 
55
56
  Further (functional and integration) tests are performed in the Python 3.11 to ensure that examples run as desired. Thus, it is generally reccommended to use Python 3.11 to keep pace with development, especially when running examples.
56
57
 
57
- ### Set up python environment
58
+ ### Set up python tooling environment
58
59
 
59
- The fmdtools library was developed to run in an anaconda python environment. If you do not have an existing python environment, first [download and install anaconda.](https://docs.anaconda.com/free/anaconda/install/index.html).
60
+ The fmdtools library was developed to run in a python development environments.
60
61
 
61
- After the base installation, set up a new `Python 3.11` environment for fmdtools and install these external external (non-python) packages in it:
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]().
63
+
64
+ After the base installation, set up a new `Python 3.11` environment for fmdtools and install these external external packages in it:
62
65
 
63
66
  ```
67
+ spyder-kernels
68
+ # used for: working with external IDEs
69
+ # license: ()
70
+ # install from: (comes with anaconda) or `uv pip install spyder-kernels`
64
71
  jupyter notebook
65
72
  # used for: repository notebooks
66
73
  # license: (BSD-3) https://jupyter.org/governance/projectlicense.html
67
- # install from: (should be installed already)
74
+ # install from: (comes with anaconda) or `uv pip install jupyter`
68
75
  graphviz
69
76
  # used for: plotting graphs using graphviz
70
77
  # license: (CPL 1.0) https://graphviz.org/license/
71
- # install from: https://anaconda.org/anaconda/graphviz
78
+ # install from: https://anaconda.org/anaconda/graphviz or https://graphviz.org/download/
72
79
  ```
73
80
 
81
+ From there, it can be helpful to install an IDE like [VSCode](https://code.visualstudio.com/) or [Spyder](https://www.spyder-ide.org/).
82
+
74
83
  Note: On Windows, some versions `fmdtools` dependencies may require a compiler such as that provided with [Microsoft Studio Build tools](https://visualstudio.microsoft.com/downloads/?q=build+tools) to build, so it (while not required) may be helpful to install it also.
75
84
 
76
85
 
@@ -97,13 +106,13 @@ This may then be installed using:
97
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.:
98
107
 
99
108
  ```
100
- git checkout v2.1.0
109
+ git checkout v2.1.2
101
110
  ```
102
111
 
103
112
 
104
113
  #### Dependencies
105
114
 
106
- fmdtools requires `Python 3.11` (anaconda recommended) 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.
115
+ fmdtools requires `Python 3.11` 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.
107
116
 
108
117
  ```
109
118
  scipy
@@ -231,16 +240,16 @@ To cite fmdtools in general, you may cite our explanatory publication:
231
240
  To cite a particular version of the fmdtools, you may use:
232
241
 
233
242
  ```
234
- @software{nasa2024fmdtools,
243
+ @software{nasa2025fmdtools,
235
244
  author = {{NASA}},
236
245
  title = {fmdtools},
237
246
  url = {https://github.com/nasa/fmdtools},
238
- version = {2.1.0},
239
- date = {2024-11-13},
247
+ version = {2.1.2},
248
+ date = {2025-5-19},
240
249
  }
241
250
  ```
242
251
 
243
- To cite a particular fmdtools example or published research methodology, use the relevant reference provided in the in accompanying README file for the example.
252
+ To cite a particular fmdtools example use the relevant reference provided in the in accompanying README file for the example. To cite a given published research methodology embodied by fmdtools, see our [publication list](PUBLICATIONS.md).
244
253
 
245
254
  ## License/Notices
246
255
 
@@ -956,7 +956,6 @@ if __name__ == "__main__":
956
956
 
957
957
  # check single lowcharge fault from approach
958
958
  h = History(nominal=mdlhists.nominal,
959
- faulty=mdlhists.store_ee_lowcharge_t5p0)
959
+ faulty=mdlhists.drone_fxns_store_ee_lowcharge_t5p0)
960
960
  fig, ax = plot_env_with_traj_z(h, mdl)
961
961
  fig, ax = plot_env_with_traj(mdlhists, mdl)
962
-
@@ -25,57 +25,54 @@ from fmdtools.analyze.phases import from_hist
25
25
 
26
26
  import multiprocessing as mp
27
27
 
28
+
29
+ set_ranges = {"s.friction": {1.5, 3.0, 10.0},
30
+ "s.transfer": {0.5, 0.0},
31
+ "s.drift": {-0.2, 0.2}}
32
+
33
+ dist_ranges = ranges = {"s.friction": (0.0, 20, 10),
34
+ "s.transfer": (1.0, 0.0, 10),
35
+ "s.drift": (-0.5, 0.5, 10)}
36
+
37
+ p_test = {'ground': {'linetype': 'turn',
38
+ 'buffer_on': 0.5,
39
+ 'buffer_poor': 0.8,
40
+ 'buffer_near': 1.0}}
41
+
28
42
  if __name__ == "__main__":
29
43
  mdl = Rover()
30
44
  p = RoverParam()
31
45
  endresults, mdlhist = prop.nominal(mdl)
32
46
  pm = from_hist(mdlhist)
47
+ mdl_test = Rover(p=p_test, sp={'end_condition': ''})
33
48
 
34
49
  # range modes
35
- mdl_range = Rover(p={"drive_modes": {"mode_args": 'range-manual-all'},
36
- 'ground':{'linetype': 'turn', 'buffer_on': 0.5, 'buffer_poor': 0.8, 'buffer_near': 1.0}},
37
- sp={'end_condition': ''})
38
- fd_range = FaultDomain(mdl_range)
39
- fd_range.add_all_fxnclass_modes('Drive')
40
- # fd_range.add_fault('drive', 'hmode_5')
41
- # fd_range.add_fault('drive', 'hmode_995')
42
- # fd_range.add_fault('drive', 'elec_open')
43
- # faults = [('drive', 'hmode_'+str(i)) for i in range(800)]
44
- # fd_range.add_faults(*faults)
50
+ fd_range = FaultDomain(mdl_test)
51
+ fd_range.add_fault_space('drive', 'custom', dist_ranges)
52
+
45
53
  fs_range = FaultSample(fd_range, pm['plan_path'])
46
54
  fs_range.add_fault_phases('drive')
47
- results_range, mdlhists_range = prop.fault_sample(mdl_range, fs_range, pool=mp.Pool(4),
55
+ results_range, mdlhists_range = prop.fault_sample(mdl_test, fs_range, pool=mp.Pool(4),
48
56
  staged=True)
49
57
 
50
58
  # set modes
51
- mdl_id = Rover(p={"drive_modes": {"mode_args": "set"}})
52
- pd_id = FaultDomain(mdl_id)
53
- pd_id.add_all_fxn_modes('drive')
59
+ pd_id = FaultDomain(mdl_test)
60
+ pd_id.add_fault_space('drive', 'custom', set_ranges)
54
61
 
55
62
  ps_id = FaultSample(pd_id, phasemap=pm['plan_path'])
56
63
  ps_id.add_fault_phases('drive', args=(3,))
57
64
 
58
- ec_id, hist_id = prop.fault_sample(mdl, ps_id, pool=mp.Pool(4), staged=True)
59
- # manual modes
60
- mdl_id = Rover(p={"drive_modes": {"mode_args": "manual"}})
61
- endresults, mdlhist = prop.one_fault(mdl_id, "drive", "elec_open",
62
- time=1, staged=False)
65
+ ec_id, hist_id = prop.fault_sample(mdl_test, ps_id, pool=mp.Pool(4), staged=True)
63
66
 
64
- # 100 drive faults
65
- mdl_100 = Rover(p={"drive_modes": {"mode_args": 100}})
66
- endresults, mdlhist = prop.one_fault(mdl_100, "drive", "hmode_34",
67
+ # manual modes
68
+ endresults, mdlhist = prop.one_fault(mdl_test, "drive", "elec_open",
67
69
  time=1, staged=False)
68
70
 
69
71
  # custom fault
70
- x = [1.0, 0.0, 1.0]
71
- mdl = Rover(p={"drive_modes":
72
- {"custom_fault":
73
- {"friction": x[0], "drift": x[1], "transfer": x[2]}}})
74
-
75
- _, mdlhist = prop.nominal(mdl)
72
+ f_kw = {'disturbances': {'s.friction': 1.0, 's.transfer': 0.0, 's.drift': 1.0}}
76
73
 
77
- endresults, reshist = prop.one_fault(mdl, "drive", "custom_fault",
78
- time=15, staged=True)
74
+ endresults, reshist = prop.one_fault(mdl, "drive", "custom", time=15,
75
+ staged=True, f_kw=f_kw)
79
76
 
80
77
  line_dist = endresults.endclass.line_dist
81
78
  end_loc = (reshist.faulty.flows.pos.s.x[-1], reshist.faulty.flows.pos.s.y[-1])
@@ -41,7 +41,7 @@ specific language governing permissions and limitations under the License.
41
41
 
42
42
  from fmdtools.define.container.parameter import Parameter
43
43
  from fmdtools.define.container.state import State
44
- from fmdtools.define.container.mode import Mode, FlexibleMode
44
+ from fmdtools.define.container.mode import Mode
45
45
  from fmdtools.define.block.function import Function
46
46
  from fmdtools.define.architecture.function import FunctionArchitecture
47
47
  from fmdtools.define.flow.base import Flow
@@ -608,59 +608,23 @@ def rdiff_from_vects(u_self, u_lin):
608
608
  return rdiff
609
609
 
610
610
 
611
- class DriveMode(FlexibleMode):
612
- """
613
- Instantiate Modes for the Drive Function.
614
-
615
- key_phases_by = 'plan_path' defines that the modes may be intantiated for
616
- certain phases of PlanPath. The phases are defined by opptvect.
617
- mode_options: determines if the how the modes in Drivemodes should be
618
- formulated (e.g., as a parameter, manually, as set of modes, etc. )
619
- """
611
+ class DriveMode(Mode):
612
+ """Mode for the drive function, including custom fault modes."""
620
613
 
621
- mode_options: tuple = tuple()
622
614
  default_phases = (('drive', 1.0), ('start', 1.0),)
623
- set_franges = {"s.friction": {1.5, 3.0, 10.0},
624
- "s.transfer": {0.5, 0.0},
625
- "s.drift": {-0.2, 0.2}}
626
- range_franges = {"s.friction": (0.0, 20, 10),
627
- "s.transfer": (1.0, 0.0, 10),
628
- "s.drift": (-0.5, 0.5, 10)}
615
+ fault_elec_open = {"disturbances": (("s.transfer", 0.0),)}
616
+ fault_stuck: dict = {"disturbances": (("s.friction", 10.0),)}
617
+ fault_stuck_right: dict = {"disturbances": (("s.friction", 3.0), ("s.drift", 0.2))}
618
+ fault_stuck_left: dict = {"disturbances": (("s.friction", 3.0), ("s.drift", -0.2))}
619
+ fault_custom: dict = {}
629
620
 
630
- def __init__(self, *args, **kwargs):
631
- super().__init__(*args, **kwargs)
632
-
633
- if type(self.mode_options) is int:
634
- self.init_faultspace(self.range_franges, n=self.mode_options)
635
- elif type(self.mode_options) is list:
636
- self.add_mode_list()
637
- elif type(self.mode_options) is dict:
638
- self.init_faultmodes(**self.mode_options)
639
- else:
640
- if "manual" in self.mode_options:
641
- self.add_manual_modes()
642
- if "set" in self.mode_options:
643
- self.init_faultspace(self.set_franges)
644
- if "range" in self.mode_options:
645
- if "all" in self.mode_options:
646
- self.init_faultspace(self.range_franges, n="all")
647
- else:
648
- self.init_faultspace(self.range_franges, n=1)
649
-
650
- def add_manual_modes(self, drift=0.0, friction=0.0):
651
- self.init_faultmodes(elec_open={"disturbances": (("s.transfer", 0.0),)},
652
- stuck={"disturbances": (("s.friction", 10.0+friction),)},
653
- stuck_right={"disturbances": (("s.friction", 3.0+friction), ("s.drift", 0.2+drift))},
654
- stuck_left={"disturbances": (("s.friction", 3.0+friction), ("s.drift", -0.2+drift))})
655
-
656
- def add_degradation_modes(self, deg_params):
657
- self.add_manual_modes(drift=deg_params.drift, friction=deg_params.friction)
658
-
659
- def add_mode_list(self):
660
- manual_modes = {"s_" + str(i):
661
- {"friction": mode[0], "transfer": mode[1], "drift": mode[2]}
662
- for i, mode in enumerate(self.mode_options)}
663
- self.init_faultstate_modes(manual_modes)
621
+ def update_degradation_modes(self, drift=0.0, friction=0.0):
622
+ """Update mode parameters based on degradation parameters."""
623
+ self.fault_stuck = {"disturbances": (("s.friction", 10.0+friction),)}
624
+ self.fault_stuck_right = {"disturbances": (("s.friction", 3.0+friction),
625
+ ("s.drift", 0.2+drift))}
626
+ self.fault_stuck_left = {"disturbances": (("s.friction", 3.0+friction),
627
+ ("s.drift", -0.2+drift))}
664
628
 
665
629
 
666
630
  class Drive(Function):
@@ -681,7 +645,8 @@ class Drive(Function):
681
645
  """Set degradation state to input degradation parameters."""
682
646
  self.s.assign(self.p, "friction", "drift")
683
647
  if self.p.drift != 0.0 and self.p.friction != 0.0:
684
- self.m.add_degradation_modes(self.p)
648
+ self.m.update_degradation_modes(friction=self.p.friction,
649
+ drift=self.p.drift)
685
650
 
686
651
  def dynamic_behavior(self, time):
687
652
  """Define the drive behavior for a given time step."""
@@ -844,6 +809,8 @@ class PowerMode(Mode):
844
809
  Battery is out of charge.
845
810
  short: Fault
846
811
  There is a short.
812
+ depletion: Fault
813
+ The battery is depleted to a given percent
847
814
  supply: Mode
848
815
  supply power
849
816
  charge: Mode
@@ -856,6 +823,7 @@ class PowerMode(Mode):
856
823
 
857
824
  fault_no_charge = (1e-5, 100, (("off", 1.0),))
858
825
  fault_short = (1e-5, 100, (("supply", 1.0),))
826
+ fault_depleted: dict = {'disturbances': {'s.charge': 20.0}}
859
827
  opermodes = ("supply", "charge", "off")
860
828
  mode: str = "off"
861
829
  exclusive = True
@@ -876,7 +844,7 @@ class Power(Function):
876
844
  """Determine power use based on mode."""
877
845
  if self.m.in_mode("off"):
878
846
  self.off_power()
879
- elif self.m.in_mode("supply"):
847
+ elif self.m.in_mode("supply", "depleted"):
880
848
  self.supply_power()
881
849
  elif self.m.in_mode("short"):
882
850
  self.short_power()
@@ -925,9 +893,10 @@ class Power(Function):
925
893
  self.ee_12.s.v = 12
926
894
  self.ee_15.s.v = 15
927
895
  else:
928
- self.m.set_mode("no_charge")
896
+ self.m.to_fault("no_charge")
929
897
  if not self.switch.s.power:
930
- self.m.set_mode("off")
898
+ if not self.m.any_faults():
899
+ self.m.set_mode("off")
931
900
 
932
901
  def power_usage(self):
933
902
  """Calculate the power usage in general."""
@@ -1028,14 +997,6 @@ class Operator(Function):
1028
997
  self.set_power(t)
1029
998
 
1030
999
 
1031
- def gen_model_params(x, scen):
1032
- """Generate model parameters for the scenario."""
1033
- params = {"drive_modes": {"custom_fault": {"friction": x[scen][0][0],
1034
- "drift": x[scen][0][1],
1035
- "transfer": x[scen][0][2]}}}
1036
- return params
1037
-
1038
-
1039
1000
  class Rover(FunctionArchitecture):
1040
1001
  """
1041
1002
  Overall rover functional architecture.
@@ -1101,7 +1062,7 @@ class Rover(FunctionArchitecture):
1101
1062
 
1102
1063
  def find_classification(self, scen, mdlhist):
1103
1064
  """
1104
- calculates metrics that need to be tracked for the simulation
1065
+ Calculate metric that need to be tracked for the simulation.
1105
1066
 
1106
1067
  Returns
1107
1068
  ----------
@@ -1206,6 +1167,7 @@ if __name__ == "__main__":
1206
1167
 
1207
1168
  mdl = Rover()
1208
1169
 
1170
+ ec, hist = prop.one_fault(mdl, 'power', 'depleted', time=1)
1209
1171
 
1210
1172
  ec1, hist1 = prop.nominal(mdl)
1211
1173
  fig, ax = hist1.plot_trajectories('flows.pos.s.x', 'flows.pos.s.y',
@@ -22,6 +22,6 @@ import fmdtools.sim as sim
22
22
  import fmdtools.analyze as analyze
23
23
 
24
24
  __all__ = ['analyze', 'sim', 'define']
25
- __version__ = '2.1.0'
25
+ __version__ = '2.1.2'
26
26
  __copyright__ = "Copyright 2024 United States Government"
27
27
  __license__ = "Apache-2.0"
@@ -87,9 +87,9 @@ def mod_prefix():
87
87
  import os
88
88
  wd = os.getcwd()
89
89
  if 'graph' in wd:
90
- return '../../../docs-source/figures/frdl/'
90
+ return '../../../docs-source/figures/frdl/primitives/'
91
91
  else:
92
- return 'docs-source/figures/frdl/'
92
+ return 'docs-source/figures/frdl/primitives/'
93
93
 
94
94
 
95
95
  class BaseStyle(dataobject, copy_default=True):
@@ -297,20 +297,20 @@ def edge_style_factory(style_tag, styles={}, **kwargs):
297
297
  --------
298
298
  >>> loc = mod_prefix()
299
299
  >>> fs = edge_style_factory('flow')
300
- >>> fig, ax = fs.show_nx(saveas=loc+'nx_flowconnection.svg')
301
- >>> sv = fs.show_gv(disp=False, saveas=loc+'gv_flowconnection.svg')
300
+ >>> fig, ax = fs.show_nx(saveas=loc+'nx/flowconnection.svg')
301
+ >>> sv = fs.show_gv(disp=False, saveas=loc+'gv/flowconnection.svg')
302
302
 
303
303
  >>> a_s = edge_style_factory('activation')
304
- >>> fig, ax = a_s.show_nx(saveas=loc+'nx_activation.svg')
305
- >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv_activation.svg')
304
+ >>> fig, ax = a_s.show_nx(saveas=loc+'nx/activation.svg')
305
+ >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv/activation.svg')
306
306
 
307
307
  >>> c_s = edge_style_factory('containment')
308
- >>> fig, ax = c_s.show_nx(saveas=loc+'nx_containment.svg')
309
- >>> sv = c_s.show_gv(disp=False, saveas=loc+'gv_containment.svg')
308
+ >>> fig, ax = c_s.show_nx(saveas=loc+'nx/containment.svg')
309
+ >>> sv = c_s.show_gv(disp=False, saveas=loc+'gv/containment.svg')
310
310
 
311
311
  >>> cs = edge_style_factory('connection')
312
- >>> fig, ax = cs.show_nx(saveas=loc+'nx_connection.svg')
313
- >>> sv = cs.show_gv(disp=False, saveas=loc+'gv_connection.svg')
312
+ >>> fig, ax = cs.show_nx(saveas=loc+'nx/connection.svg')
313
+ >>> sv = cs.show_gv(disp=False, saveas=loc+'gv/connection.svg')
314
314
  """
315
315
  if style_tag in ['flow', 'flows', 'Flow', 'functions', 'aggregation']:
316
316
  style_class = FlowEdgeStyle
@@ -519,36 +519,36 @@ def node_style_factory(style_tag, styles={}, **kwargs):
519
519
  --------
520
520
  >>> loc = mod_prefix()
521
521
  >>> fs = node_style_factory('flow')
522
- >>> fig, ax = fs.show_nx(saveas=loc+'nx_flow.svg')
523
- >>> sv = fs.show_gv(disp=False, saveas=loc+'gv_flow.svg')
522
+ >>> fig, ax = fs.show_nx(saveas=loc+'nx/flow.svg')
523
+ >>> sv = fs.show_gv(disp=False, saveas=loc+'gv/flow.svg')
524
524
 
525
525
  >>> ms = node_style_factory('multiflow')
526
- >>> fig, ax = ms.show_nx(saveas=loc+'nx_multiflow.svg')
527
- >>> sv = ms.show_gv(disp=False, saveas=loc+'gv_multiflow.svg')
526
+ >>> fig, ax = ms.show_nx(saveas=loc+'nx/multiflow.svg')
527
+ >>> sv = ms.show_gv(disp=False, saveas=loc+'gv/multiflow.svg')
528
528
 
529
529
  >>> cs = node_style_factory('commsflow')
530
- >>> fig, ax = cs.show_nx(saveas=loc+'nx_commsflow.svg')
531
- >>> sv = cs.show_gv(disp=False, saveas=loc+'gv_commsflow.svg')
530
+ >>> fig, ax = cs.show_nx(saveas=loc+'nx/commsflow.svg')
531
+ >>> sv = cs.show_gv(disp=False, saveas=loc+'gv/commsflow.svg')
532
532
 
533
533
  >>> fs = node_style_factory('function')
534
- >>> fig, ax = fs.show_nx(saveas=loc+'nx_function.svg')
535
- >>> sv = fs.show_gv(disp=False, saveas=loc+'gv_function.svg')
534
+ >>> fig, ax = fs.show_nx(saveas=loc+'nx/function.svg')
535
+ >>> sv = fs.show_gv(disp=False, saveas=loc+'gv/function.svg')
536
536
 
537
537
  >>> a_s = node_style_factory('action')
538
- >>> fig, ax = a_s.show_nx(saveas=loc+'nx_action.svg')
539
- >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv_action.svg')
538
+ >>> fig, ax = a_s.show_nx(saveas=loc+'nx/action.svg')
539
+ >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv/action.svg')
540
540
 
541
541
  >>> cs = node_style_factory('component')
542
- >>> fig, ax = cs.show_nx(saveas=loc+'nx_component.svg')
543
- >>> sv = cs.show_gv(disp=False, saveas=loc+'gv_component.svg')
542
+ >>> fig, ax = cs.show_nx(saveas=loc+'nx/component.svg')
543
+ >>> sv = cs.show_gv(disp=False, saveas=loc+'gv/component.svg')
544
544
 
545
545
  >>> cs = node_style_factory('container')
546
- >>> fig, ax = cs.show_nx(saveas=loc+'nx_container.svg')
547
- >>> sv = cs.show_gv(disp=False, saveas=loc+'gv_container.svg')
546
+ >>> fig, ax = cs.show_nx(saveas=loc+'nx/container.svg')
547
+ >>> sv = cs.show_gv(disp=False, saveas=loc+'gv/container.svg')
548
548
 
549
549
  >>> a_s = node_style_factory('architecture')
550
- >>> fig, ax = a_s.show_nx(saveas=loc+'nx_architecture.svg')
551
- >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv_architecture.svg')
550
+ >>> fig, ax = a_s.show_nx(saveas=loc+'nx/architecture.svg')
551
+ >>> sv = a_s.show_gv(disp=False, saveas=loc+'gv/architecture.svg')
552
552
  """
553
553
  if style_tag in ['flow', 'Flow']:
554
554
  node_style = FlowNodeStyle
@@ -71,10 +71,10 @@ def result_summary_fmea(endresult, mdlhist, *attrs, metrics=()):
71
71
  degraded ... expected_cost
72
72
  exfxnarch_fxns_ex_fxn_no_charge_t1 ['ex_fxn', 'exf'] ... 0.0
73
73
  exfxnarch_fxns_ex_fxn_no_charge_t2 ['ex_fxn', 'exf'] ... 0.0
74
- exfxnarch_fxns_ex_fxn_short_t1 ['ex_fxn', 'exf'] ... 0.0
75
- exfxnarch_fxns_ex_fxn_short_t2 ['ex_fxn', 'exf'] ... 0.0
76
74
  exfxnarch_fxns_ex_fxn2_no_charge_t1 ['ex_fxn', 'ex_fxn2', 'exf'] ... 0.0
77
75
  exfxnarch_fxns_ex_fxn2_no_charge_t2 ['ex_fxn', 'ex_fxn2', 'exf'] ... 0.0
76
+ exfxnarch_fxns_ex_fxn_short_t1 ['ex_fxn', 'exf'] ... 0.0
77
+ exfxnarch_fxns_ex_fxn_short_t2 ['ex_fxn', 'exf'] ... 0.0
78
78
  exfxnarch_fxns_ex_fxn2_short_t1 ['ex_fxn', 'ex_fxn2', 'exf'] ... 0.0
79
79
  exfxnarch_fxns_ex_fxn2_short_t2 ['ex_fxn', 'ex_fxn2', 'exf'] ... 0.0
80
80
  nominal [] ... 1.0
@@ -450,23 +450,23 @@ class FMEA(BaseTab):
450
450
  >>> FMEA(res, exfs).as_table(sort_by="sum_cost")
451
451
  average_scenario_rate ... expected_cost
452
452
  exfxnarch.fxns.ex_fxn2 short 0.0 ... 0.0
453
- no_charge 0.0 ... 0.0
454
453
  exfxnarch.fxns.ex_fxn short 0.0 ... 0.0
455
- no_charge 0.0 ... 0.0
454
+ exfxnarch.fxns.ex_fxn2 no_charge 0.0 ... 0.0
455
+ exfxnarch.fxns.ex_fxn no_charge 0.0 ... 0.0
456
456
  <BLANKLINE>
457
457
  [4 rows x 3 columns]
458
458
  >>> FMEA(res, exfs, average_metric=["rate"], sum_metric=["cost"], expected_metric=["cost"], rates="rate").as_table()
459
459
  average_rate sum_cost expected_cost
460
460
  exfxnarch.fxns.ex_fxn2 short 1.5 13 20
461
- no_charge 1.5 9 14
462
- exfxnarch.fxns.ex_fxn short 1.5 5 8
463
- no_charge 1.5 1 2
461
+ exfxnarch.fxns.ex_fxn short 1.5 9 14
462
+ exfxnarch.fxns.ex_fxn2 no_charge 1.5 5 8
463
+ exfxnarch.fxns.ex_fxn no_charge 1.5 1 2
464
464
  >>> FMEA(res, exfs, sum_metric=["rate"], average_metric=["cost"]).as_table()
465
465
  sum_rate average_cost
466
466
  exfxnarch.fxns.ex_fxn2 short 3 6.5
467
- no_charge 3 4.5
468
- exfxnarch.fxns.ex_fxn short 3 2.5
469
- no_charge 3 0.5
467
+ exfxnarch.fxns.ex_fxn short 3 4.5
468
+ exfxnarch.fxns.ex_fxn2 no_charge 3 2.5
469
+ exfxnarch.fxns.ex_fxn no_charge 3 0.5
470
470
  """
471
471
 
472
472
  def __init__(self, res, fs, add_res={}, group_by=('function', 'fault'),