fmdtools 2.4.0__tar.gz → 2.5.1__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 (136) hide show
  1. {fmdtools-2.4.0 → fmdtools-2.5.1}/LICENSE +1 -1
  2. {fmdtools-2.4.0 → fmdtools-2.5.1}/PKG-INFO +24 -10
  3. {fmdtools-2.4.0 → fmdtools-2.5.1}/README.md +21 -7
  4. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/__init__.py +2 -1
  5. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/aircraftarchitecture.py +2 -1
  6. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/controlflight.py +9 -0
  7. fmdtools-2.5.1/examples/airspacelib/water_rescue/__init__.py +23 -0
  8. fmdtools-2.5.1/examples/airspacelib/water_rescue/model_drone.py +138 -0
  9. fmdtools-2.5.1/examples/airspacelib/water_rescue/model_environment.py +170 -0
  10. fmdtools-2.5.1/examples/airspacelib/water_rescue/model_main.py +33 -0
  11. fmdtools-2.5.1/examples/airspacelib/water_rescue/model_responder.py +306 -0
  12. {fmdtools-2.4.0 → fmdtools-2.5.1}/fmdtools.egg-info/PKG-INFO +24 -10
  13. {fmdtools-2.4.0 → fmdtools-2.5.1}/fmdtools.egg-info/SOURCES.txt +9 -1
  14. {fmdtools-2.4.0 → fmdtools-2.5.1}/fmdtools.egg-info/requires.txt +1 -1
  15. {fmdtools-2.4.0 → fmdtools-2.5.1}/pyproject.toml +2 -2
  16. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/__init__.py +1 -1
  17. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/__init__.py +1 -0
  18. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/component.py +0 -2
  19. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/object/coords.py +36 -11
  20. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/object/geom.py +54 -11
  21. fmdtools-2.5.1/src/fmdtools/define/pathplan.py +1425 -0
  22. fmdtools-2.5.1/tests/test_geom.py +139 -0
  23. fmdtools-2.5.1/tests/test_pathplan.py +786 -0
  24. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/__init__.py +0 -0
  25. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/model_asset.py +0 -0
  26. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/model_atc.py +0 -0
  27. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/model_common.py +0 -0
  28. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/model_main.py +0 -0
  29. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/test_asset.py +0 -0
  30. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airport_taxiway/test_model.py +0 -0
  31. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/__init__.py +0 -0
  32. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/aircraft.py +0 -0
  33. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/__init__.py +0 -0
  34. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/aviate.py +0 -0
  35. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/flows.py +0 -0
  36. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/holdpayload.py +0 -0
  37. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/perceiveenvironment.py +0 -0
  38. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/arch/storeee.py +0 -0
  39. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/parameter.py +0 -0
  40. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/base/state.py +0 -0
  41. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/contingency_management/__init__.py +0 -0
  42. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/contingency_management/model_aircraft.py +0 -0
  43. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/contingency_management/model_environment.py +0 -0
  44. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/contingency_management/model_flightplanner.py +0 -0
  45. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/wildfire_response/__init__.py +0 -0
  46. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/wildfire_response/model_aircraft.py +0 -0
  47. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/wildfire_response/model_environment.py +0 -0
  48. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/airspacelib/wildfire_response/model_main.py +0 -0
  49. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/cooling_tank/__init__.py +0 -0
  50. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/cooling_tank/model_main.py +0 -0
  51. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/cooling_tank/model_optimization.py +0 -0
  52. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/cooling_tank/test_tank.py +0 -0
  53. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/electric_power_system/__init__.py +0 -0
  54. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/electric_power_system/model_main.py +0 -0
  55. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/electric_power_system/test_model.py +0 -0
  56. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/human_hazard_mitigation/__init__.py +0 -0
  57. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/human_hazard_mitigation/model_main.py +0 -0
  58. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/__init__.py +0 -0
  59. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/model_dynamic.py +0 -0
  60. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/model_hierarchical.py +0 -0
  61. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/model_rural.py +0 -0
  62. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/model_static.py +0 -0
  63. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/model_urban.py +0 -0
  64. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/script_opt_model_rural.py +0 -0
  65. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/multirotor_drone/test_multirotor.py +0 -0
  66. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/__init__.py +0 -0
  67. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/model_degradation.py +0 -0
  68. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/model_human.py +0 -0
  69. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/model_main.py +0 -0
  70. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/model_troupe.py +0 -0
  71. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/script_ea_analysis.py +0 -0
  72. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/script_mode_space.py +0 -0
  73. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/script_search_rover.py +0 -0
  74. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/navigating_rover/test_rover.py +0 -0
  75. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/state_communication/__init__.py +0 -0
  76. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/state_communication/model_main.py +0 -0
  77. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/state_communication/test_multiflow.py +0 -0
  78. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/__init__.py +0 -0
  79. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/model_indiv.py +0 -0
  80. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/model_main.py +0 -0
  81. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/model_stochastic.py +0 -0
  82. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/script_jointfaults.py +0 -0
  83. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/script_parallelism.py +0 -0
  84. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/test_pump.py +0 -0
  85. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/test_pump_example.py +0 -0
  86. {fmdtools-2.4.0 → fmdtools-2.5.1}/examples/water_pump/test_pump_stochastic.py +0 -0
  87. {fmdtools-2.4.0 → fmdtools-2.5.1}/fmdtools.egg-info/dependency_links.txt +0 -0
  88. {fmdtools-2.4.0 → fmdtools-2.5.1}/fmdtools.egg-info/top_level.txt +0 -0
  89. {fmdtools-2.4.0 → fmdtools-2.5.1}/setup.cfg +0 -0
  90. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/__init__.py +0 -0
  91. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/common.py +0 -0
  92. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/graph/__init__.py +0 -0
  93. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/graph/base.py +0 -0
  94. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/graph/label.py +0 -0
  95. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/graph/model.py +0 -0
  96. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/graph/style.py +0 -0
  97. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/history.py +0 -0
  98. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/phases.py +0 -0
  99. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/result.py +0 -0
  100. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/analyze/tabulate.py +0 -0
  101. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/__init__.py +0 -0
  102. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/action.py +0 -0
  103. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/base.py +0 -0
  104. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/function.py +0 -0
  105. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/architecture/geom.py +0 -0
  106. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/base.py +0 -0
  107. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/block/__init__.py +0 -0
  108. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/block/action.py +0 -0
  109. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/block/base.py +0 -0
  110. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/block/component.py +0 -0
  111. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/block/function.py +0 -0
  112. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/__init__.py +0 -0
  113. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/base.py +0 -0
  114. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/mode.py +0 -0
  115. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/parameter.py +0 -0
  116. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/rand.py +0 -0
  117. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/state.py +0 -0
  118. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/container/time.py +0 -0
  119. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/environment.py +0 -0
  120. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/flow/__init__.py +0 -0
  121. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/flow/base.py +0 -0
  122. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/flow/commsflow.py +0 -0
  123. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/flow/multiflow.py +0 -0
  124. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/object/__init__.py +0 -0
  125. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/object/base.py +0 -0
  126. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/define/object/timer.py +0 -0
  127. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/sim/__init__.py +0 -0
  128. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/sim/propagate.py +0 -0
  129. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/sim/sample.py +0 -0
  130. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/sim/scenario.py +0 -0
  131. {fmdtools-2.4.0 → fmdtools-2.5.1}/src/fmdtools/sim/search.py +0 -0
  132. {fmdtools-2.4.0 → fmdtools-2.5.1}/tests/__init__.py +0 -0
  133. {fmdtools-2.4.0 → fmdtools-2.5.1}/tests/common.py +0 -0
  134. {fmdtools-2.4.0 → fmdtools-2.5.1}/tests/test_graph.py +0 -0
  135. {fmdtools-2.4.0 → fmdtools-2.5.1}/tests/test_hierarchical.py +0 -0
  136. {fmdtools-2.4.0 → fmdtools-2.5.1}/tests/test_packages.py +0 -0
@@ -1,4 +1,4 @@
1
- fmdtools version 2.4.0
1
+ fmdtools version 2.5.1
2
2
  ---------------------------
3
3
  Apache License
4
4
  Version 2.0, January 2004
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmdtools
3
- Version: 2.4.0
3
+ Version: 2.5.1
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.4.0
7
+ License: fmdtools version 2.5.1
8
8
  ---------------------------
9
9
  Apache License
10
10
  Version 2.0, January 2004
@@ -250,7 +250,7 @@ Requires-Dist: tqdm
250
250
  Requires-Dist: networkx
251
251
  Requires-Dist: numpy>=2.0
252
252
  Requires-Dist: matplotlib>=3.7.0
253
- Requires-Dist: pandas[all]>=2.2.0
253
+ Requires-Dist: pandas[output-formatting,plot]>=2.2.0
254
254
  Requires-Dist: ordered-set
255
255
  Requires-Dist: dill
256
256
  Requires-Dist: recordclass==0.24
@@ -306,8 +306,8 @@ The fmdtools library provides the computational support needed to perform a simu
306
306
 
307
307
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/flexible.svg">
308
308
 
309
- ### Flexible Modelling Paradigm
310
- Models in fmdtools use a consistent and composable representation of system structure and behavior. Whether you want to model a simple component, a complex system-of-systems, or both, fmdtools can help.
309
+ ### Flexible, AI-Ready Modelling Paradigm
310
+ Models in fmdtools use a straightforward and composable code-based representation of system structure and behavior. Since fmdtools models are based on open-source Python, models can be readily generated from your AI of choice with the right prompting. Whether you want to model a simple component, a complex system-of-systems, or both, fmdtools can help.
311
311
 
312
312
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/powerful.svg">
313
313
 
@@ -394,7 +394,7 @@ More guidance on development installations is provided in [How to Contribute](ht
394
394
  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`` in the context of a development install you can checkout the tag corresponding to the version you want, e.g.:
395
395
 
396
396
  ```
397
- git checkout v2.4.0
397
+ git checkout v2.5.1
398
398
  ```
399
399
 
400
400
 
@@ -490,10 +490,24 @@ Once fmdtools is installed, use the following to get acquainted with how to use
490
490
 
491
491
  - Explore more [examples](https://nasa.github.io/fmdtools/examples/Examples.html) of particular use-cases by going through the [examples folder](https://github.com/nasa/fmdtools/tree/main/examples)
492
492
 
493
- - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#).
493
+ - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/development-guide.html).
494
494
 
495
495
  - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs-source/fmdtools.html) for syntax and usage documentation.
496
496
 
497
+ ### AI/LLM Tips
498
+
499
+ Decent (but **very imperfect**) results can be achieved using LLMs for model development using the prompt:
500
+
501
+ ```prompt
502
+ You are an experienced software engineer learning a new Python library for the first time. Make an fmdtools simulation of racecar using the latest syntax from `https://github.com/nasa/fmdtools/tree/v2.5.1` for all modeling (`fmdtools.define`), simulation (`fmdtools.sim`), and analysis (`fmdtools.analyze`) classes. The output should be a bare bones but well-commented .py file with simple behaviors for each class and a small script at the bottom leveraging the built-in capabilities in the `fmdtools.analyze` package instead of directly using external libraries like matplotlib. As you are going, explain the structure of each class, the usage of each function call and how they each leverage the correct fmdtools v2.5.1 syntax.
503
+ ```
504
+
505
+ The important aspects of this prompt are specifying the URL and version--otherwise the LLM is likely to hallucinate usage or recall an earlier version of fmdtools. Do not expect perfect output from this--you may have to spend some time identifying the problems so they can be fixed!
506
+
507
+ For somewhat better results, we recommend using an on-machine coding "agent" such as OpenCode/Claude Code/Codex.
508
+
509
+ More elaborate prompts can be found in our [AGENTS.md](AGENTS.md) and repository skills at `.agents/skills`.
510
+
497
511
  ## Contributions
498
512
  fmdtools is developed primarily by researchers at NASA Ames Research Center. External contributions are welcome under a Contributor License Agreement:
499
513
 
@@ -527,12 +541,12 @@ To cite fmdtools in general, you may cite our explanatory publication:
527
541
  To cite a particular version of the fmdtools, you may use:
528
542
 
529
543
  ```
530
- @software{nasa2025fmdtools,
544
+ @software{nasa2026fmdtools,
531
545
  author = {{NASA}},
532
546
  title = {fmdtools},
533
547
  url = {https://github.com/nasa/fmdtools},
534
- version = {2.4.0},
535
- date = {2026-5-29},
548
+ version = {2.5.1},
549
+ date = {2026-9-22},
536
550
  }
537
551
  ```
538
552
 
@@ -35,8 +35,8 @@ The fmdtools library provides the computational support needed to perform a simu
35
35
 
36
36
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/flexible.svg">
37
37
 
38
- ### Flexible Modelling Paradigm
39
- Models in fmdtools use a consistent and composable representation of system structure and behavior. Whether you want to model a simple component, a complex system-of-systems, or both, fmdtools can help.
38
+ ### Flexible, AI-Ready Modelling Paradigm
39
+ Models in fmdtools use a straightforward and composable code-based representation of system structure and behavior. Since fmdtools models are based on open-source Python, models can be readily generated from your AI of choice with the right prompting. Whether you want to model a simple component, a complex system-of-systems, or both, fmdtools can help.
40
40
 
41
41
  <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/powerful.svg">
42
42
 
@@ -123,7 +123,7 @@ More guidance on development installations is provided in [How to Contribute](ht
123
123
  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`` in the context of a development install you can checkout the tag corresponding to the version you want, e.g.:
124
124
 
125
125
  ```
126
- git checkout v2.4.0
126
+ git checkout v2.5.1
127
127
  ```
128
128
 
129
129
 
@@ -219,10 +219,24 @@ Once fmdtools is installed, use the following to get acquainted with how to use
219
219
 
220
220
  - Explore more [examples](https://nasa.github.io/fmdtools/examples/Examples.html) of particular use-cases by going through the [examples folder](https://github.com/nasa/fmdtools/tree/main/examples)
221
221
 
222
- - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#).
222
+ - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/development-guide.html).
223
223
 
224
224
  - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs-source/fmdtools.html) for syntax and usage documentation.
225
225
 
226
+ ### AI/LLM Tips
227
+
228
+ Decent (but **very imperfect**) results can be achieved using LLMs for model development using the prompt:
229
+
230
+ ```prompt
231
+ You are an experienced software engineer learning a new Python library for the first time. Make an fmdtools simulation of racecar using the latest syntax from `https://github.com/nasa/fmdtools/tree/v2.5.1` for all modeling (`fmdtools.define`), simulation (`fmdtools.sim`), and analysis (`fmdtools.analyze`) classes. The output should be a bare bones but well-commented .py file with simple behaviors for each class and a small script at the bottom leveraging the built-in capabilities in the `fmdtools.analyze` package instead of directly using external libraries like matplotlib. As you are going, explain the structure of each class, the usage of each function call and how they each leverage the correct fmdtools v2.5.1 syntax.
232
+ ```
233
+
234
+ The important aspects of this prompt are specifying the URL and version--otherwise the LLM is likely to hallucinate usage or recall an earlier version of fmdtools. Do not expect perfect output from this--you may have to spend some time identifying the problems so they can be fixed!
235
+
236
+ For somewhat better results, we recommend using an on-machine coding "agent" such as OpenCode/Claude Code/Codex.
237
+
238
+ More elaborate prompts can be found in our [AGENTS.md](AGENTS.md) and repository skills at `.agents/skills`.
239
+
226
240
  ## Contributions
227
241
  fmdtools is developed primarily by researchers at NASA Ames Research Center. External contributions are welcome under a Contributor License Agreement:
228
242
 
@@ -256,12 +270,12 @@ To cite fmdtools in general, you may cite our explanatory publication:
256
270
  To cite a particular version of the fmdtools, you may use:
257
271
 
258
272
  ```
259
- @software{nasa2025fmdtools,
273
+ @software{nasa2026fmdtools,
260
274
  author = {{NASA}},
261
275
  title = {fmdtools},
262
276
  url = {https://github.com/nasa/fmdtools},
263
- version = {2.4.0},
264
- date = {2026-5-29},
277
+ version = {2.5.1},
278
+ date = {2026-9-22},
265
279
  }
266
280
  ```
267
281
 
@@ -18,5 +18,6 @@ specific language governing permissions and limitations under the License.
18
18
  import fmdtools_examples.airspacelib.base as base
19
19
  import fmdtools_examples.airspacelib.contingency_management as contingency_management
20
20
  import fmdtools_examples.airspacelib.wildfire_response as wildfire_response
21
+ import fmdtools_examples.airspacelib.water_rescue as water_rescue
21
22
 
22
- __all__ = ['base', 'contingency_management', 'wildfire_response']
23
+ __all__ = ['base', 'contingency_management', 'wildfire_response', 'water_rescue']
@@ -32,7 +32,8 @@ from fmdtools_examples.airspacelib.base.arch.holdpayload import HoldPayload
32
32
 
33
33
  class AircraftArchParameter(Parameter):
34
34
  """Overall Parameter Defining the AircraftArchitecture."""
35
-
35
+ startpt: tuple = (0.0, 0.0)
36
+ endpt: tuple = (25.0, 25.0)
36
37
  flightplan: tuple = ((0.0, 0.0), (25.0, 25.0))
37
38
  height: float = 25.0
38
39
 
@@ -20,6 +20,7 @@ specific language governing permissions and limitations under the License.
20
20
  from fmdtools.define.block.function import Function
21
21
  from fmdtools.define.container.state import State
22
22
  from fmdtools.define.container.mode import Mode
23
+ from fmdtools.define.pathplan import PathPlannerBase
23
24
 
24
25
  from fmdtools_examples.airspacelib.base.arch.flows import Trajectories, Force, Electricity
25
26
  from fmdtools_examples.airspacelib.base.arch.flows import AircraftEnvironment
@@ -120,6 +121,8 @@ class ControlFlight(Function):
120
121
  """Add the desired trajectory local flow to the Function."""
121
122
  self.perc_traj = self.trajectories.create_local("perc_traj")
122
123
  self.des_traj = self.trajectories.create_local("des_traj")
124
+ # self.planner = PathPlannerBase()
125
+ # self.planner.init_environment(self.environment)
123
126
 
124
127
  def static_behavior(self):
125
128
  """
@@ -197,6 +200,12 @@ class ControlFlight(Function):
197
200
  newgoal = self.des_traj.s.get_loc()
198
201
  self.des_traj.s.assign(newgoal, 'goal_x', 'goal_y', 'goal_z')
199
202
 
203
+ # def run_planner(self, start, goal, algorithm, **kwargs):
204
+ # path = self.planner.compute_path(start, goal, planner=algorithm, **kwargs)
205
+ # self.s.flightplan = self.planner.s.flightplan
206
+ # self.s.pt = self.planner.s.pt
207
+ # return path
208
+
200
209
 
201
210
  if __name__ == "__main__":
202
211
  import doctest
@@ -0,0 +1,23 @@
1
+ """
2
+ Water rescue model.
3
+
4
+ Copyright © 2024, United States Government, as represented by the Administrator
5
+ of the National Aeronautics and Space Administration. All rights reserved.
6
+
7
+ The "Fault Model Design tools - fmdtools version 2" software is licensed
8
+ under the Apache License, Version 2.0 (the "License"); you may not use this
9
+ file except in compliance with the License. You may obtain a copy of the
10
+ License at http://www.apache.org/licenses/LICENSE/2.0.
11
+
12
+ Unless required by applicable law or agreed to in writing, software distributed
13
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
15
+ specific language governing permissions and limitations under the License.
16
+ """
17
+
18
+ import fmdtools_examples.airspacelib.water_rescue.model_environment as model_environment
19
+ import fmdtools_examples.airspacelib.water_rescue.model_responder as model_responder
20
+ import fmdtools_examples.airspacelib.water_rescue.model_drone as model_drone
21
+ import fmdtools_examples.airspacelib.water_rescue.model_main as model_main
22
+
23
+ __all__ = ['model_environment', 'model_responder', 'model_drone', 'model_main']
@@ -0,0 +1,138 @@
1
+ """
2
+ Patrol drone model for the water-rescue simulation.
3
+
4
+ The drone flies a zigzag patrol path along the shoreline. When it spots a
5
+ distressed swimmer within its viewing radius, it switches to rescue mode,
6
+ alerts the responder, flies to the victim, and drops a buoy before returning
7
+ to patrol.
8
+
9
+ Copyright © 2024, United States Government, as represented by the Administrator
10
+ of the National Aeronautics and Space Administration. All rights reserved.
11
+
12
+ The “"Fault Model Design tools - fmdtools version 2"” software is licensed
13
+ under the Apache License, Version 2.0 (the "License"); you may not use this
14
+ file except in compliance with the License. You may obtain a copy of the
15
+ License at http://www.apache.org/licenses/LICENSE-2.0.
16
+
17
+ Unless required by applicable law or agreed to in writing, software distributed
18
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
19
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
20
+ specific language governing permissions and limitations under the License.
21
+ """
22
+ from fmdtools_examples.airspacelib.base.aircraft import BaseAircraft
23
+ from fmdtools_examples.airspacelib.base.state import AircraftState
24
+ from fmdtools_examples.airspacelib.water_rescue.model_environment import BeachEnvironment
25
+ from fmdtools.define.container.mode import Mode
26
+ import numpy as np
27
+
28
+
29
+ # Patrol path construction
30
+ # The shoreline runs along the x-axis (y=0 is the shore).
31
+ # The drone sweeps between two offshore bands: 100ft ~ 30m, 200ft ~ 60m.
32
+ near_shore = 150 # inner band, 150ft offshore
33
+ far_shore = 270 # outer band, 270ft offshore
34
+
35
+ # extent of the beach along the x-axis
36
+ x_min = -50
37
+ x_max = 1900
38
+
39
+ # Build a zigzag path: alternate between the near and far bands while
40
+ # stepping 100 units along the beach each waypoint.
41
+ zigzag_path = []
42
+ x_positions = np.arange(x_min, x_max+100, 100)
43
+
44
+ for i, x in enumerate(x_positions):
45
+ if i % 2 == 0:
46
+ zigzag_path.append((x, near_shore))
47
+ else:
48
+ zigzag_path.append((x, far_shore))
49
+
50
+
51
+ class BeachAircraftModes(Mode):
52
+ """Drone operating modes: patrolling the shore or rescuing a swimmer."""
53
+ opermodes = ("patrol", "rescue")
54
+ mode: str = "patrol"
55
+
56
+
57
+ class BeachAircraftState(AircraftState):
58
+ """State of the drone: position, path progress, and rescue bookkeeping."""
59
+ victim_spotted: bool = False # whether a victim has been detected
60
+ flight_path: list = zigzag_path # patrol waypoints to cycle through
61
+ patrol_idx: int = 0 # index of the current patrol waypoint
62
+ rescue_idx: int = 0 # index along the rescue path
63
+ time_arrived: float = -1.0 # sim time the drone reached the victim (-1 = not yet)
64
+ location: tuple = (0, 0) # current (x, y) position
65
+
66
+
67
+ class BeachAircraft(BaseAircraft):
68
+ """Aircraft that spots struggling swimmers and notifies responders."""
69
+ container_m = BeachAircraftModes
70
+ container_s = BeachAircraftState
71
+ flow_environment = BeachEnvironment
72
+
73
+ def init_block(self, **kwargs):
74
+ """Set initial aircraft location to its assigned base."""
75
+ self.s.x = self.environment.c.p.base_locations[self.p.base][0]
76
+ self.s.y = self.environment.c.p.base_locations[self.p.base][1]
77
+
78
+ def set_rescue_goal(self):
79
+ """Switch to rescue mode, alert the responder, and target the victim."""
80
+ self.m.set_mode("rescue")
81
+ self.send_rescue_alert()
82
+ # fall back to the first configured rescue location if none recorded
83
+ victim = getattr(self.environment.c, "person_location",
84
+ self.environment.c.p.rescue_locations[0])
85
+ self.s.assign(victim, "goal_x", "goal_y")
86
+
87
+ def fly_patrol(self):
88
+ """Fly toward the current patrol waypoint; advance to the next on arrival."""
89
+ self.m.set_mode("patrol")
90
+ waypoint = self.s.flight_path[self.s.patrol_idx]
91
+ self.s.assign(waypoint, "goal_x", "goal_y")
92
+ self.fly_to_goal()
93
+ if self.indicate_at_goal():
94
+ # loop back to the start of the path after the last waypoint
95
+ self.s.patrol_idx = (self.s.patrol_idx + 1) % len(self.s.flight_path)
96
+
97
+ def fly_rescue(self):
98
+ """Fly to the victim; on arrival drop a buoy and return to patrol."""
99
+ victim = getattr(self.environment.c, "person_location",
100
+ self.environment.c.p.rescue_locations[0])
101
+ self.s.assign(victim, "goal_x", "goal_y")
102
+
103
+ self.fly_to_goal()
104
+
105
+ self.s.location = self.s.get_loc()
106
+
107
+ if self.indicate_at_goal():
108
+ # record first arrival time
109
+ if self.s.time_arrived < 0:
110
+ self.s.time_arrived = self.t.time
111
+
112
+ # drop the buoy: victim now floats and no longer needs the drone
113
+ self.environment.c.set_pts([victim], "with_buoy", True)
114
+ self.environment.c.set_pts([victim], "person_to_rescue", False)
115
+ self.m.set_mode("patrol")
116
+
117
+ def send_rescue_alert(self):
118
+ """Raise the shared rescue flag so the responder knows to act."""
119
+ self.environment.c.s.rescue = True
120
+
121
+ def dynamic_behavior(self):
122
+ """
123
+ Per-timestep behavior.
124
+
125
+ If in patrol, the drone checks the area around it with check_vicinity,
126
+ which returns whether the closest distressed person is within viewing
127
+ radius (and their location).
128
+
129
+ If a person needs rescue, the drone switches to rescue mode and flies
130
+ to the person to drop the buoy, then returns to patrol.
131
+ """
132
+ if self.m.in_mode("patrol"):
133
+ self.fly_patrol()
134
+ in_range, _ = self.environment.c.check_vicinity(self.s.get_loc())
135
+ if in_range:
136
+ self.set_rescue_goal()
137
+ elif self.m.in_mode("rescue"):
138
+ self.fly_rescue()
@@ -0,0 +1,170 @@
1
+ """
2
+ Beach environment model for the water-rescue simulation.
3
+
4
+ Defines the beach/water grid, where distressed swimmers appear, and the
5
+ "swimmer behavior" function that counts down distress and survival timers.
6
+
7
+ Copyright © 2024, United States Government, as represented by the Administrator
8
+ of the National Aeronautics and Space Administration. All rights reserved.
9
+
10
+ The “"Fault Model Design tools - fmdtools version 2"” software is licensed
11
+ under the Apache License, Version 2.0 (the "License"); you may not use this
12
+ file except in compliance with the License. You may obtain a copy of the
13
+ License at http://www.apache.org/licenses/LICENSE-2.0.
14
+
15
+ Unless required by applicable law or agreed to in writing, software distributed
16
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
18
+ specific language governing permissions and limitations under the License.
19
+ """
20
+ from fmdtools.define.object.coords import Coords, CoordsParam
21
+ from fmdtools.define.environment import Environment
22
+ from fmdtools.define.block.function import Function
23
+ from fmdtools.define.container.state import State
24
+ import numpy as np
25
+
26
+
27
+ class BeachMapParam(CoordsParam):
28
+ """Parameters defining the size and layout of the beach grid."""
29
+ x_size: int = 20 # width of grid (number of tiles)
30
+ y_size: int = 5 # length of grid (number of tiles)
31
+ blocksize: float = 100 # 100 meters per tile
32
+ base_locations: tuple = ((400.0, 0.0), (1600.0, 0.0)) # points where drones launch from
33
+ rescue_locations: tuple = ((1000.0, 300.0),) # points where people need rescue
34
+ num_distress: int = 1 # how many swimmers will go into distress
35
+ time_to_reach: float = 10.0 # expected time for responder to reach a victim
36
+ vicinity_radius: float = 200.0 # default detection radius for check_vicinity()
37
+
38
+
39
+ class BeachBehaviorState(State):
40
+ """Shared state used to communicate rescue alerts between functions."""
41
+ time_to_reach: int = 30 # time budget for reaching a victim
42
+ rescue: bool = False # set True when a victim has been spotted (rescue alert)
43
+
44
+
45
+ class BeachMap(Coords):
46
+ """
47
+ Grid representation of the beach.
48
+
49
+ Each tile carries per-point states (survival rate, timers, rescue status)
50
+ and features marking what type of terrain it is (beach, water, base, etc.).
51
+ """
52
+ container_p = BeachMapParam
53
+ container_s = BeachBehaviorState
54
+
55
+ # states for every point in environment
56
+ state_survival_rate = (float, 1) # likelihood the victim survives
57
+ state_person_to_rescue = (bool, False) # True once a swimmer at this point is in distress
58
+ point_person_location = (0, 0) # location of the (first) distressed swimmer
59
+ state_with_buoy = (bool, False) # True after the drone drops a buoy at this point
60
+ state_rescued = (bool, False) # True once the responder completes the rescue
61
+ state_distress_timer = (float, 100.0) # countdown until the swimmer shows distress
62
+ state_survival_timer = (float, 300.0) # countdown until a distressed swimmer dies
63
+ state_dead = (bool, False) # True if the survival timer ran out
64
+
65
+ # terrain features
66
+ feature_beach = (bool, False) # sandy area (y between 0 and blocksize)
67
+ feature_water = (bool, False) # open water (y beyond 2*blocksize)
68
+ feature_base = (bool, False) # drone launch points
69
+ feature_rescue_location = (bool, False) # designated victim locations
70
+
71
+ def init_properties(self, *args, **kwargs):
72
+ """Lay out the map: mark bases, victim points, beach strip, and water."""
73
+ self.set_pts(self.p.base_locations, "base", True)
74
+ self.set_pts(self.p.rescue_locations, "person_to_rescue", False)
75
+ b = self.p.blocksize
76
+ self.set_range("beach", True, ymin=0, ymax=b) # first row of tiles is sand
77
+ self.set_range("water", True, ymin=b * 2) # everything past 2 tiles is water
78
+
79
+ # record the first victim's location for easy lookup by other functions
80
+ victim_pts = self.p.rescue_locations[:self.p.num_distress]
81
+ if victim_pts:
82
+ self.person_location = victim_pts[0]
83
+
84
+ def check_vicinity(self, point, radius=None):
85
+ """
86
+ Check whether any distressed swimmer is within radius of point.
87
+
88
+ Returns
89
+ -------
90
+ (in_range, closest_pt) : tuple
91
+ in_range : True if the nearest active victim is within radius.
92
+ closest_pt : location of that victim, or None if no one is in distress.
93
+ """
94
+ if radius is None:
95
+ radius = self.p.vicinity_radius
96
+
97
+ # gather only victims currently flagged as needing rescue
98
+ active = []
99
+ for pt in self.p.rescue_locations:
100
+ if self.get(pt[0], pt[1], "person_to_rescue"):
101
+ active.append(pt)
102
+ if not active:
103
+ return (False, None)
104
+
105
+ # find the closest active victim and test it against the radius
106
+ pts = np.array(active)
107
+ dists = np.hypot(pts[:, 0] - point[0], pts[:, 1] - point[1])
108
+ i = int(np.argmin(dists))
109
+ return (dists[i] <= radius, tuple(pts[i]))
110
+
111
+
112
+ class BeachEnvironment(Environment):
113
+ """Environment flow wrapping the BeachMap grid, shared by all functions."""
114
+ coords_c = BeachMap
115
+
116
+
117
+ class BeachBehavior(Function):
118
+ """
119
+ Simulates swimmer behavior over time.
120
+
121
+ Counts down each swimmer's distress timer; once it hits zero the swimmer
122
+ is flagged as needing rescue. From then on, a survival timer counts down —
123
+ slower if a buoy has been dropped — and the swimmer dies if it reaches zero.
124
+ """
125
+ container_s = BeachBehaviorState
126
+ flow_environment = BeachEnvironment
127
+
128
+ def dynamic_behavior(self):
129
+ env = self.environment.c
130
+
131
+ # distress phase: count down until each swimmer starts struggling
132
+ for pt in env.p.rescue_locations:
133
+ rescued = env.get(pt[0], pt[1], "rescued")
134
+ if rescued:
135
+ continue # skip already rescued victims
136
+ timer = env.get(pt[0], pt[1], "distress_timer")
137
+ print(f"timer: {timer}, person_to_rescue: {env.get(pt[0], pt[1], 'person_to_rescue')}")
138
+ if timer > 0:
139
+ env.set(pt[0], pt[1], "distress_timer", timer - self.t.dt)
140
+ elif not env.get(pt[0], pt[1], "with_buoy"):
141
+ # timer expired and no buoy yet -> flag swimmer as needing rescue
142
+ env.set_pts([pt], "person_to_rescue", True)
143
+
144
+ # survival phase: distressed swimmer's survival timer counts down
145
+ victim = env.p.rescue_locations[0]
146
+ if env.get(victim[0], victim[1], "distress_timer") <= 0 \
147
+ and not env.get(victim[0], victim[1], "rescued") \
148
+ and not env.get(victim[0], victim[1], "dead"):
149
+ timer = env.get(victim[0], victim[1], "survival_timer")
150
+ if env.get(victim[0], victim[1], "with_buoy"):
151
+ timer -= self.t.dt * 0.1 # buoy slows the countdown 10x
152
+ else:
153
+ timer -= self.t.dt
154
+ if timer <= 0:
155
+ # survival time ran out -> victim dies
156
+ timer = 0.0
157
+ env.set_pts([victim], "dead", True)
158
+ env.set(victim[0], victim[1], "survival_timer", timer)
159
+
160
+
161
+ # Colors used when plotting the map states/features in simulation visuals
162
+ sim_properties = {
163
+ 'beach': {'color': 'sandybrown'},
164
+ 'water': {'color': 'steelblue'},
165
+ 'person_to_rescue': {'color': 'red'},
166
+ 'base': {'color': 'black'},
167
+ 'with_buoy': {'color': 'yellow'},
168
+ 'rescued': {'color': 'green'},
169
+ 'dead': {'color': 'purple'},
170
+ }
@@ -0,0 +1,33 @@
1
+ """
2
+ Top-level model for the water-rescue simulation.
3
+
4
+ Wires together the shared beach environment with the three functions:
5
+ the lifeguard responder, the swimmer behavior, and the patrol drone.
6
+
7
+ Copyright © 2024, United States Government, as represented by the Administrator
8
+ of the National Aeronautics and Space Administration. All rights reserved.
9
+
10
+ The “"Fault Model Design tools - fmdtools version 2"” software is licensed
11
+ under the Apache License, Version 2.0 (the "License"); you may not use this
12
+ file except in compliance with the License. You may obtain a copy of the
13
+ License at http://www.apache.org/licenses/LICENSE-2.0.
14
+
15
+ Unless required by applicable law or agreed to in writing, software distributed
16
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
18
+ specific language governing permissions and limitations under the License.
19
+ """
20
+ from fmdtools_examples.airspacelib.water_rescue.model_environment import BeachEnvironment, BeachBehavior
21
+ from fmdtools_examples.airspacelib.water_rescue.model_responder import Responder
22
+ from fmdtools_examples.airspacelib.water_rescue.model_drone import BeachAircraft
23
+ from fmdtools.define.architecture.function import FunctionArchitecture
24
+
25
+
26
+ class Beach(FunctionArchitecture):
27
+ """Function architecture connecting all functions through the environment flow."""
28
+
29
+ def init_architecture(self, **kwargs):
30
+ self.add_flow("environment", BeachEnvironment)
31
+ self.add_fxn("responder", Responder, "environment")
32
+ self.add_fxn("swimmers", BeachBehavior, "environment")
33
+ self.add_fxn("beach_aircraft", BeachAircraft, "environment")