fmdtools 2.0.3__tar.gz → 2.0.5__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 (105) hide show
  1. {fmdtools-2.0.3 → fmdtools-2.0.5}/LICENSE +1 -1
  2. {fmdtools-2.0.3 → fmdtools-2.0.5}/PKG-INFO +35 -18
  3. {fmdtools-2.0.3 → fmdtools-2.0.5}/README.md +30 -15
  4. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/ex_pump.py +4 -0
  5. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/__init__.py +1 -1
  6. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/graph/base.py +1 -1
  7. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/graph/model.py +39 -5
  8. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/graph/style.py +22 -4
  9. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/base.py +3 -2
  10. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/base.py +31 -1
  11. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/block/base.py +25 -24
  12. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/block/function.py +1 -1
  13. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/parameter.py +3 -2
  14. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/environment.py +8 -10
  15. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/object/base.py +37 -10
  16. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/object/coords.py +10 -2
  17. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/sim/propagate.py +15 -10
  18. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools.egg-info/PKG-INFO +35 -18
  19. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools.egg-info/requires.txt +1 -1
  20. {fmdtools-2.0.3 → fmdtools-2.0.5}/pyproject.toml +24 -2
  21. {fmdtools-2.0.3 → fmdtools-2.0.5}/tests/test_graph.py +1 -1
  22. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/__init__.py +0 -0
  23. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/asg_demo/__init__.py +0 -0
  24. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/asg_demo/demo_model.py +0 -0
  25. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/eps/__init__.py +0 -0
  26. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/eps/eps.py +0 -0
  27. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/eps/test_eps.py +0 -0
  28. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multiflow_demo/__init__.py +0 -0
  29. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multiflow_demo/multiflow_demo.py +0 -0
  30. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multiflow_demo/test_multiflow.py +0 -0
  31. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/__init__.py +0 -0
  32. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/drone_mdl_dynamic.py +0 -0
  33. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/drone_mdl_hierarchical.py +0 -0
  34. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/drone_mdl_rural.py +0 -0
  35. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/drone_mdl_static.py +0 -0
  36. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/drone_mdl_urban.py +0 -0
  37. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/opt_drone_rural.py +0 -0
  38. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/multirotor/test_multirotor.py +0 -0
  39. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/__init__.py +0 -0
  40. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/jointfaults_ex.py +0 -0
  41. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/parallelism_methods.py +0 -0
  42. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/pump_indiv.py +0 -0
  43. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/pump_stochastic.py +0 -0
  44. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/test_pump.py +0 -0
  45. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/test_pump_example.py +0 -0
  46. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/pump/test_pump_stochastic.py +0 -0
  47. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/__init__.py +0 -0
  48. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/opt_rover.py +0 -0
  49. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/optimization/ea_analysis.py +0 -0
  50. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/optimization/search_rover.py +0 -0
  51. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/optimization/untitled2.py +0 -0
  52. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/rover_degradation.py +0 -0
  53. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/rover_mode_space.py +0 -0
  54. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/rover_model.py +0 -0
  55. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/rover_model_human.py +0 -0
  56. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/rover/test_rover.py +0 -0
  57. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/tank/__init__.py +0 -0
  58. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/tank/tank_model.py +0 -0
  59. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/tank/tank_optimization_model.py +0 -0
  60. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/tank/test_tank.py +0 -0
  61. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/ATC.py +0 -0
  62. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/asset.py +0 -0
  63. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/common.py +0 -0
  64. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/model.py +0 -0
  65. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/test_asset.py +0 -0
  66. {fmdtools-2.0.3 → fmdtools-2.0.5}/examples/taxiway/test_model.py +0 -0
  67. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/__init__.py +0 -0
  68. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/common.py +0 -0
  69. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/graph/__init__.py +0 -0
  70. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/graph/label.py +0 -0
  71. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/history.py +0 -0
  72. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/phases.py +0 -0
  73. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/result.py +0 -0
  74. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/analyze/tabulate.py +0 -0
  75. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/__init__.py +0 -0
  76. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/__init__.py +0 -0
  77. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/action.py +0 -0
  78. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/component.py +0 -0
  79. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/function.py +0 -0
  80. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/architecture/geom.py +0 -0
  81. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/block/__init__.py +0 -0
  82. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/block/action.py +0 -0
  83. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/block/component.py +0 -0
  84. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/__init__.py +0 -0
  85. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/base.py +0 -0
  86. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/mode.py +0 -0
  87. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/rand.py +0 -0
  88. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/state.py +0 -0
  89. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/container/time.py +0 -0
  90. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/flow/__init__.py +0 -0
  91. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/flow/base.py +0 -0
  92. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/flow/commsflow.py +0 -0
  93. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/flow/multiflow.py +0 -0
  94. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/object/__init__.py +0 -0
  95. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/object/geom.py +0 -0
  96. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/define/object/timer.py +0 -0
  97. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/sim/__init__.py +0 -0
  98. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/sim/sample.py +0 -0
  99. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/sim/scenario.py +0 -0
  100. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools/sim/search.py +0 -0
  101. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools.egg-info/SOURCES.txt +0 -0
  102. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools.egg-info/dependency_links.txt +0 -0
  103. {fmdtools-2.0.3 → fmdtools-2.0.5}/fmdtools.egg-info/top_level.txt +0 -0
  104. {fmdtools-2.0.3 → fmdtools-2.0.5}/setup.cfg +0 -0
  105. {fmdtools-2.0.3 → fmdtools-2.0.5}/tests/test_packages.py +0 -0
@@ -1,4 +1,4 @@
1
- fmdtools version 2.0.3
1
+ fmdtools version 2.0.5
2
2
  ---------------------------
3
3
  Apache License
4
4
  Version 2.0, January 2004
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fmdtools
3
- Version: 2.0.3
3
+ Version: 2.0.5
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.0.3
7
+ License: fmdtools version 2.0.5
8
8
  ---------------------------
9
9
  Apache License
10
10
  Version 2.0, January 2004
@@ -236,7 +236,9 @@ 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
239
240
  Classifier: Programming Language :: Python :: 3.11
241
+ Classifier: Programming Language :: Python :: 3.12
240
242
  Classifier: License :: OSI Approved :: Apache Software License
241
243
  Classifier: Operating System :: OS Independent
242
244
  Classifier: Topic :: Scientific/Engineering
@@ -251,22 +253,24 @@ Requires-Dist: matplotlib>=3.7.0
251
253
  Requires-Dist: pandas
252
254
  Requires-Dist: ordered-set
253
255
  Requires-Dist: dill
254
- Requires-Dist: recordclass==0.21.1
256
+ Requires-Dist: recordclass==0.22.1
255
257
  Requires-Dist: pytest
256
258
  Requires-Dist: graphviz
257
259
  Requires-Dist: shapely>=2.0
258
260
 
259
- [![fmdtools logo - titanic](/docs/figures/logo/logo-titanic.png)](https://github.com/nasa/fmdtools)
261
+ [![fmdtools logo - titanic](/docs-source/figures/logo/logo-titanic.png)](https://github.com/nasa/fmdtools)
260
262
 
261
263
  # Overview
262
264
 
263
265
  ![Python Version](https://img.shields.io/badge/Python-3.11-blue)
264
266
  [![PyPI](https://img.shields.io/pypi/v/fmdtools)](https://pypi.org/project/fmdtools/)
267
+ [![Total Downloads](https://static.pepy.tech/badge/fmdtools)](https://pepy.tech/project/fmdtools)
268
+ [![Downloads/Month](https://static.pepy.tech/badge/fmdtools/month)](https://pepy.tech/project/fmdtools)
265
269
  [![GitHub release (latest by date)](https://img.shields.io/github/v/release/nasa/fmdtools?label=GitHub%20Release)](https://github.com/nasa/fmdtools/releases)
266
270
  [![GitHub Tag](https://img.shields.io/github/v/tag/nasa/fmdtools)](https://github.com/nasa/fmdtools/tags)
267
271
  [![CodeFactor](https://www.codefactor.io/repository/github/nasa/fmdtools/badge)](https://www.codefactor.io/repository/github/nasa/fmdtools)
268
- [![Tests Status](./tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/junit/report.html)
269
- [![Tests Coverage](./coverage-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/coverage/index.html)
272
+ [![Tests Status](./reports/full-py311/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py311/junit/report.html)
273
+ [![Tests Coverage](./reports/full-py311/coverage-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py311/coverage_html/index.html)
270
274
  [![GitHub License](https://img.shields.io/badge/License-Apache%202.0-green)](https://github.com/nasa/fmdtools/blob/main/LICENSE)
271
275
  [![NASA Software Classification](https://img.shields.io/badge/Software_Class-E-blue)](https://nodis3.gsfc.nasa.gov/displayDir.cfm?Internal_ID=N_PR_7150_002D_&page_name=AppendixD)
272
276
 
@@ -274,21 +278,22 @@ Requires-Dist: shapely>=2.0
274
278
 
275
279
  [Click here to view the the full documentation website.](https://nasa.github.io/fmdtools)
276
280
 
281
+
277
282
  ## About
278
283
 
279
- The fmdtools library provides the computational support needed to perform a simulation-based (rather than document-based) hazard analysis process that [**enables the consideration of systems resilience**](https://nasa.github.io/fmdtools/docs/Development%20Guide.html#why-fmdtools). This means that it can be used to extend the scope of hazard analysis from component faults to the dynamic interactions between the system, operators, and the environment. Some key features include:
284
+ The fmdtools library provides the computational support needed to perform a simulation-based (rather than document-based) hazard analysis process that [**enables the consideration of systems resilience**](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#why-fmdtools). This means that it can be used to extend the scope of hazard analysis from component faults to the dynamic interactions between the system, operators, and the environment. Some key features include:
280
285
 
281
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/flexible.svg">
286
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/flexible.svg">
282
287
 
283
288
  ### Flexible Modelling Paradigm
284
289
  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.
285
290
 
286
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/powerful.svg">
291
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/powerful.svg">
287
292
 
288
293
  ### Powerful Simulation Techniques
289
294
  Simulation techniques in fmdtools represent the state-of-the-art in dynamical systems modelling for resilience quantification. With fmdtools, you can simulate the dynamic effects of hazardous scenarios over a wide range of variables to quantify and optimize risk, resilience, and safety metrics.
290
295
 
291
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/efficient.svg">
296
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/efficient.svg">
292
297
 
293
298
  ### Efficient Analysis Process
294
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.
@@ -297,6 +302,18 @@ Readily-deployable analysis methods are built in to fmdtools to enable the rapid
297
302
 
298
303
  ## Getting Started
299
304
 
305
+ ### Python version compatibility
306
+
307
+ The fmdtools library is developed in Python 3.11 but tested to maintain compatibility over three versions of Python. See current doctest reports below:
308
+
309
+ | Python Version | Doctests |
310
+ | -------- | ------- |
311
+ | 3.10 | [![Python 3.10 Tests](./reports/doctests-py310/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py310/junit/report.html) |
312
+ | 3.11 | [![Python 3.11 Tests](./reports/doctests-py311/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py311/junit/report.html) |
313
+ | 3.12 | [![Python 3.12 Tests](./reports/doctests-py312/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py312/junit/report.html) |
314
+
315
+ 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
+
300
317
  ### Set up python environment
301
318
 
302
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).
@@ -314,7 +331,7 @@ graphviz
314
331
  # install from: https://anaconda.org/anaconda/graphviz
315
332
  ```
316
333
 
317
- Note: some versions `fmdtools` dependencies may additionally require `Microsoft Studio Build tools <https://visualstudio.microsoft.com/license-terms/vs2022-ga-diagnosticbuildtools/>`_ to build properly, so it may be helpful to install it also.
334
+ 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.
318
335
 
319
336
 
320
337
  ### Install fmdtools
@@ -340,7 +357,7 @@ This may then be installed using:
340
357
  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.:
341
358
 
342
359
  ```
343
- git checkout v2.0.3
360
+ git checkout v2.0.5
344
361
  ```
345
362
 
346
363
 
@@ -365,7 +382,7 @@ ordered-set
365
382
  # license: (MIT) https://github.com/rspeer/ordered-set/blob/master/MIT-LICENSE
366
383
  dill
367
384
  # license: (MIT) https://github.com/uqfoundation/dill/blob/master/LICENSE
368
- recordclass == 0.21.1
385
+ recordclass == 0.22.1
369
386
  # license: (MIT) https://github.com/intellimath/recordclass/blob/main/LICENSE.txt
370
387
  pytest
371
388
  # license: (MIT) https://docs.pytest.org/en/7.3.x/license.html
@@ -433,13 +450,13 @@ If a development install has been performed, you can further check aspects of yo
433
450
 
434
451
  Once fmdtools is installed, use the following to get acquainted with how to use the library:
435
452
 
436
- - Go through the [Intro to fmdtools workshop](https://nasa.github.io/fmdtools/docs/Intro_to_fmdtools.html) to learn about some of the basics of the fmdtools library and work with an existing model.
453
+ - Go through the [Intro to fmdtools workshop](https://nasa.github.io/fmdtools/docs-source/Intro_to_fmdtools.html) to learn about some of the basics of the fmdtools library and work with an existing model.
437
454
 
438
455
  - 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)
439
456
 
440
- - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs/Development%20Guide.html#).
457
+ - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#).
441
458
 
442
- - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs/fmdtools.html) for syntax and usage documentation.
459
+ - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs-source/fmdtools.html) for syntax and usage documentation.
443
460
 
444
461
  ## Contributions
445
462
  fmdtools is developed primarily by researchers at NASA Ames Research Center. External contributions are welcome under a Contributor License Agreement:
@@ -478,8 +495,8 @@ To cite a particular version of the fmdtools, you may use:
478
495
  author = {{NASA}},
479
496
  title = {fmdtools},
480
497
  url = {https://github.com/nasa/fmdtools},
481
- version = {2.0.3}, # <- replace with your version number
482
- date = {2024-08-22},
498
+ version = {2.0.5}, # <- replace with your version number
499
+ date = {2024-11-13},
483
500
  }
484
501
  ```
485
502
 
@@ -1,14 +1,16 @@
1
- [![fmdtools logo - titanic](/docs/figures/logo/logo-titanic.png)](https://github.com/nasa/fmdtools)
1
+ [![fmdtools logo - titanic](/docs-source/figures/logo/logo-titanic.png)](https://github.com/nasa/fmdtools)
2
2
 
3
3
  # Overview
4
4
 
5
5
  ![Python Version](https://img.shields.io/badge/Python-3.11-blue)
6
6
  [![PyPI](https://img.shields.io/pypi/v/fmdtools)](https://pypi.org/project/fmdtools/)
7
+ [![Total Downloads](https://static.pepy.tech/badge/fmdtools)](https://pepy.tech/project/fmdtools)
8
+ [![Downloads/Month](https://static.pepy.tech/badge/fmdtools/month)](https://pepy.tech/project/fmdtools)
7
9
  [![GitHub release (latest by date)](https://img.shields.io/github/v/release/nasa/fmdtools?label=GitHub%20Release)](https://github.com/nasa/fmdtools/releases)
8
10
  [![GitHub Tag](https://img.shields.io/github/v/tag/nasa/fmdtools)](https://github.com/nasa/fmdtools/tags)
9
11
  [![CodeFactor](https://www.codefactor.io/repository/github/nasa/fmdtools/badge)](https://www.codefactor.io/repository/github/nasa/fmdtools)
10
- [![Tests Status](./tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/junit/report.html)
11
- [![Tests Coverage](./coverage-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/coverage/index.html)
12
+ [![Tests Status](./reports/full-py311/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py311/junit/report.html)
13
+ [![Tests Coverage](./reports/full-py311/coverage-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/full-py311/coverage_html/index.html)
12
14
  [![GitHub License](https://img.shields.io/badge/License-Apache%202.0-green)](https://github.com/nasa/fmdtools/blob/main/LICENSE)
13
15
  [![NASA Software Classification](https://img.shields.io/badge/Software_Class-E-blue)](https://nodis3.gsfc.nasa.gov/displayDir.cfm?Internal_ID=N_PR_7150_002D_&page_name=AppendixD)
14
16
 
@@ -16,21 +18,22 @@
16
18
 
17
19
  [Click here to view the the full documentation website.](https://nasa.github.io/fmdtools)
18
20
 
21
+
19
22
  ## About
20
23
 
21
- The fmdtools library provides the computational support needed to perform a simulation-based (rather than document-based) hazard analysis process that [**enables the consideration of systems resilience**](https://nasa.github.io/fmdtools/docs/Development%20Guide.html#why-fmdtools). This means that it can be used to extend the scope of hazard analysis from component faults to the dynamic interactions between the system, operators, and the environment. Some key features include:
24
+ The fmdtools library provides the computational support needed to perform a simulation-based (rather than document-based) hazard analysis process that [**enables the consideration of systems resilience**](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#why-fmdtools). This means that it can be used to extend the scope of hazard analysis from component faults to the dynamic interactions between the system, operators, and the environment. Some key features include:
22
25
 
23
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/flexible.svg">
26
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/flexible.svg">
24
27
 
25
28
  ### Flexible Modelling Paradigm
26
29
  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.
27
30
 
28
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/powerful.svg">
31
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/powerful.svg">
29
32
 
30
33
  ### Powerful Simulation Techniques
31
34
  Simulation techniques in fmdtools represent the state-of-the-art in dynamical systems modelling for resilience quantification. With fmdtools, you can simulate the dynamic effects of hazardous scenarios over a wide range of variables to quantify and optimize risk, resilience, and safety metrics.
32
35
 
33
- <img align="left" width="100" height="100" src="/docs/figures/powerpoint/efficient.svg">
36
+ <img align="left" width="100" height="100" src="/docs-source/figures/powerpoint/efficient.svg">
34
37
 
35
38
  ### Efficient Analysis Process
36
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,6 +42,18 @@ Readily-deployable analysis methods are built in to fmdtools to enable the rapid
39
42
 
40
43
  ## Getting Started
41
44
 
45
+ ### Python version compatibility
46
+
47
+ The fmdtools library is developed in Python 3.11 but tested to maintain compatibility over three versions of Python. See current doctest reports below:
48
+
49
+ | Python Version | Doctests |
50
+ | -------- | ------- |
51
+ | 3.10 | [![Python 3.10 Tests](./reports/doctests-py310/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py310/junit/report.html) |
52
+ | 3.11 | [![Python 3.11 Tests](./reports/doctests-py311/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py311/junit/report.html) |
53
+ | 3.12 | [![Python 3.12 Tests](./reports/doctests-py312/tests-badge.svg)](https://htmlpreview.github.io/?https://github.com/nasa/fmdtools/blob/main/reports/doctests-py312/junit/report.html) |
54
+
55
+ 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
+
42
57
  ### Set up python environment
43
58
 
44
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).
@@ -56,7 +71,7 @@ graphviz
56
71
  # install from: https://anaconda.org/anaconda/graphviz
57
72
  ```
58
73
 
59
- Note: some versions `fmdtools` dependencies may additionally require `Microsoft Studio Build tools <https://visualstudio.microsoft.com/license-terms/vs2022-ga-diagnosticbuildtools/>`_ to build properly, so it may be helpful to install it also.
74
+ 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.
60
75
 
61
76
 
62
77
  ### Install fmdtools
@@ -82,7 +97,7 @@ This may then be installed using:
82
97
  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.:
83
98
 
84
99
  ```
85
- git checkout v2.0.3
100
+ git checkout v2.0.5
86
101
  ```
87
102
 
88
103
 
@@ -107,7 +122,7 @@ ordered-set
107
122
  # license: (MIT) https://github.com/rspeer/ordered-set/blob/master/MIT-LICENSE
108
123
  dill
109
124
  # license: (MIT) https://github.com/uqfoundation/dill/blob/master/LICENSE
110
- recordclass == 0.21.1
125
+ recordclass == 0.22.1
111
126
  # license: (MIT) https://github.com/intellimath/recordclass/blob/main/LICENSE.txt
112
127
  pytest
113
128
  # license: (MIT) https://docs.pytest.org/en/7.3.x/license.html
@@ -175,13 +190,13 @@ If a development install has been performed, you can further check aspects of yo
175
190
 
176
191
  Once fmdtools is installed, use the following to get acquainted with how to use the library:
177
192
 
178
- - Go through the [Intro to fmdtools workshop](https://nasa.github.io/fmdtools/docs/Intro_to_fmdtools.html) to learn about some of the basics of the fmdtools library and work with an existing model.
193
+ - Go through the [Intro to fmdtools workshop](https://nasa.github.io/fmdtools/docs-source/Intro_to_fmdtools.html) to learn about some of the basics of the fmdtools library and work with an existing model.
179
194
 
180
195
  - 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)
181
196
 
182
- - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs/Development%20Guide.html#).
197
+ - Read about contributions and model development best practices by perusing the [Development Guide](https://nasa.github.io/fmdtools/docs-source/Development%20Guide.html#).
183
198
 
184
- - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs/fmdtools.html) for syntax and usage documentation.
199
+ - Explore the searchable [module reference](https://nasa.github.io/fmdtools/docs-source/fmdtools.html) for syntax and usage documentation.
185
200
 
186
201
  ## Contributions
187
202
  fmdtools is developed primarily by researchers at NASA Ames Research Center. External contributions are welcome under a Contributor License Agreement:
@@ -220,8 +235,8 @@ To cite a particular version of the fmdtools, you may use:
220
235
  author = {{NASA}},
221
236
  title = {fmdtools},
222
237
  url = {https://github.com/nasa/fmdtools},
223
- version = {2.0.3}, # <- replace with your version number
224
- date = {2024-08-22},
238
+ version = {2.0.5}, # <- replace with your version number
239
+ date = {2024-11-13},
225
240
  }
226
241
  ```
227
242
 
@@ -672,6 +672,7 @@ if __name__ == "__main__":
672
672
  Pump().get_vars("flows.ee_1")
673
673
  g = Pump().create_graph()
674
674
  from fmdtools.analyze.graph.base import Graph
675
+ from fmdtools.define.object.base import ObjectGraph
675
676
  # horizontal alignment test:
676
677
  g2 = Graph(g)
677
678
  g2.set_node_labels(subtext="nodetype", title_style={'horizontalalignment': 'left'},
@@ -685,3 +686,6 @@ if __name__ == "__main__":
685
686
  check_model_pickleability(Pump(), try_pick=True)
686
687
  import inspect
687
688
  source = inspect.getsource(Pump)
689
+ og = ObjectGraph(Pump(), get_source=True)
690
+ og.set_node_labels(title='shortname', title2='classname', subtext='docs')
691
+ og.draw_graphviz()
@@ -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.0.0'
25
+ __version__ = '2.0.5'
26
26
  __copyright__ = "Copyright 2024 United States Government"
27
27
  __license__ = "Apache-2.0"
@@ -86,7 +86,7 @@ class Graph(object):
86
86
  >>> graph.set_pos(auto='kamada_kawai')
87
87
  >>> fig, ax = graph.draw(saveas=loc+'nx_funcdecomp.svg')
88
88
  >>> graph.set_edge_labels(title="name")
89
- >>> dot = graph.draw_graphviz(saveas=loc+'gv_funcdecomp.svg')
89
+ >>> dot = graph.draw_graphviz(disp=False, saveas=loc+'gv_funcdecomp.svg')
90
90
  """
91
91
 
92
92
  def __init__(self, g, check_info=True):
@@ -30,7 +30,7 @@ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
30
30
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
31
31
  specific language governing permissions and limitations under the License.
32
32
  """
33
- from fmdtools.define.base import get_code_attrs, get_obj_name
33
+ from fmdtools.define.base import get_code_attrs, get_obj_name, get_inheritance
34
34
  from fmdtools.analyze.graph.base import Graph
35
35
  from fmdtools.analyze.graph.label import shorten_name
36
36
  from fmdtools.analyze.result import Result
@@ -58,12 +58,12 @@ def add_node(obj, g=None, name='', classname='', nodetype='', get_attrs=False,
58
58
  """
59
59
  if not g:
60
60
  g = nx.DiGraph()
61
- if hasattr(obj, 'get_full_name'):
62
- name = obj.get_full_name()
61
+ if not name:
62
+ name = get_obj_name(obj)
63
63
  if not classname:
64
64
  classname = obj.__class__.__name__
65
65
  if not nodetype:
66
- if hasattr(obj, 'get_typename'):
66
+ if hasattr(obj, 'get_typename') and not inspect.isclass(obj):
67
67
  nodetype = obj.get_typename()
68
68
  else:
69
69
  nodetype = obj.__class__.__name__
@@ -103,6 +103,41 @@ def add_edge(g, basename, name, rolename, edgetype):
103
103
  g.add_edge(basename, name, edgetype=edgetype, role=rolename)
104
104
 
105
105
 
106
+ def create_inheritance_subgraph(obj, g=None, name='', end_at_fmdtools=True):
107
+ """
108
+ Create a graph of the inheritance of a given object from fmdtools classes.
109
+
110
+ Parameters
111
+ ----------
112
+ obj : Object
113
+ Object.
114
+ g : graph, optional
115
+ Networkx graph to add to. The default is None.
116
+ end_at_fmdtools : bool
117
+ Option to end at first fmdtools node while building the subgraph
118
+ Default is False, which stops the subgraph at the first fmdtools class, rather
119
+ than includeing the fmdtools class inheritance.
120
+
121
+ Returns
122
+ -------
123
+ g : graph
124
+ Networkx graph of inheritance from classes.
125
+ """
126
+ if not name:
127
+ name = get_obj_name(obj)
128
+ if inspect.isclass(obj):
129
+ nodetype = "class"
130
+ g = add_node(obj, g, name=name, nodetype=nodetype)
131
+ else:
132
+ g = add_node(obj, g, name=name)
133
+ if not (end_at_fmdtools and 'fmdtools.' in name):
134
+ base_classes = get_inheritance(obj)
135
+ for bc in base_classes:
136
+ g = create_inheritance_subgraph(bc, g, end_at_fmdtools=end_at_fmdtools)
137
+ add_edge(g, name, get_obj_name(bc), "base", "inheritance")
138
+ return g
139
+
140
+
106
141
  def set_node_states(g, obj, name, time=None):
107
142
  """
108
143
  Attach stateful attributes to the given node.
@@ -155,7 +190,6 @@ def remove_base(g, basename):
155
190
  g.remove_nodes_from([*nx.isolates(g)])
156
191
 
157
192
 
158
-
159
193
  class ModelGraph(Graph):
160
194
  """
161
195
  Superclass for Graphs meant to represent specific model constructs.
@@ -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/figures/frdl/'
90
+ return '../../../docs-source/figures/frdl/'
91
91
  else:
92
- return 'docs/figures/frdl/'
92
+ return 'docs-source/figures/frdl/'
93
93
 
94
94
 
95
95
  class BaseStyle(dataobject, copy_default=True):
@@ -199,7 +199,7 @@ def save_dot(dot, saveas=''):
199
199
  """Save a graphviz diagram."""
200
200
  if saveas:
201
201
  filecomponents = saveas.split('.')
202
- dot.render('.'.join(filecomponents[:-1]), format=filecomponents[-1])
202
+ dot.render('.'.join(filecomponents[:-1]), format=filecomponents[-1], view=False)
203
203
 
204
204
 
205
205
  class FlowEdgeStyle(EdgeStyle):
@@ -267,6 +267,19 @@ class ConnectionEdgeStyle(EdgeStyle):
267
267
  gv_style: str = 'dashed'
268
268
 
269
269
 
270
+ class InheritanceEdgeStyle(EdgeStyle):
271
+ """EdgeStyle representing inheritance."""
272
+
273
+ nx_edge_color: str = 'grey'
274
+ nx_style: str = 'solid'
275
+ nx_arrows: bool = True
276
+ nx_arrowstyle: str = '-|>'
277
+ nx_arrowsize: int = 15
278
+ gv_arrowhead: str = 'empty'
279
+ gv_color: str = 'black'
280
+ gv_style: str = 'solid'
281
+
282
+
270
283
  def edge_style_factory(style_tag, styles={}, **kwargs):
271
284
  """
272
285
  Get the appropriate EdgeStyle for networkx plotting.
@@ -307,6 +320,8 @@ def edge_style_factory(style_tag, styles={}, **kwargs):
307
320
  style_class = ContainmentEdgeStyle
308
321
  elif style_tag == 'connection':
309
322
  style_class = ConnectionEdgeStyle
323
+ elif style_tag == 'inheritance':
324
+ style_class = InheritanceEdgeStyle
310
325
  else:
311
326
  raise Exception("Invalid edge style: "+str(style_tag))
312
327
  return style_class(styles=styles, **kwargs)
@@ -383,7 +398,8 @@ class NodeStyle(BaseStyle):
383
398
  Digraph, Graph = gv_import_check()
384
399
  dot = Digraph()
385
400
  dot.node('0', label=self.__class__.__name__, **self.gv_kwargs())
386
- display(SVG(dot._repr_image_svg_xml()))
401
+ if disp:
402
+ display(SVG(dot._repr_image_svg_xml()))
387
403
  gv_plot_ending(dot, disp=disp, saveas=saveas)
388
404
  return dot
389
405
 
@@ -556,6 +572,8 @@ def node_style_factory(style_tag, styles={}, **kwargs):
556
572
  node_style = MethodNodeStyle
557
573
  elif style_tag in ['dict', 'flexible']:
558
574
  node_style = OtherNodeStyle
575
+ elif style_tag in ['class', 'Class']:
576
+ node_style = OtherNodeStyle
559
577
  else:
560
578
  raise Exception("Invalid node style: "+str(style_tag))
561
579
  return node_style(styles=styles, **kwargs)
@@ -156,6 +156,9 @@ class Architecture(Simulable):
156
156
  as_copy = self.as_copy
157
157
 
158
158
  track = get_sub_include(name, get_sub_include(flex_role, self.track))
159
+ # sync rands, if present
160
+ if hasattr(self, 'r') and hasattr(objclass, "container_r"):
161
+ kwargs = {**{'r': {"seed": self.r.seed}}, **kwargs}
159
162
  obj = init_obj(name=name, objclass=objclass, track=track,
160
163
  as_copy=as_copy, root=self.get_full_name()+"."+flex_role,
161
164
  **kwargs)
@@ -231,8 +234,6 @@ class Architecture(Simulable):
231
234
  """
232
235
  flows = self.get_flows(*flownames, all_if_empty=False)
233
236
  fkwargs = {**{'sp': self.sp.asdict()}, **kwargs}
234
- if hasattr(self, 'r'):
235
- fkwargs = {**{'r': {"seed": self.r.seed}}, **fkwargs}
236
237
  if not self.sp.use_local:
237
238
  fkwargs = {**{'t': {'dt': self.sp.dt}}, **fkwargs}
238
239
 
@@ -244,11 +244,17 @@ def get_code_attrs(obj):
244
244
  code = "\n".join(code.split("\n "))
245
245
  code = remove_para(code)
246
246
  else:
247
- source = inspect.getsource(obj.__class__)
247
+ if inspect.isclass(obj):
248
+ objcl = obj
249
+ else:
250
+ objcl = obj.__class__
251
+ source = inspect.getsource(objcl)
248
252
  if hasattr(obj, 'get_code'):
249
253
  code = obj.get_code(source)
250
254
  else:
251
255
  code = ""
256
+ if str(obj.__doc__) not in source or 'fmdtools.' in objcl.__module__:
257
+ docs = ""
252
258
  return {'source': source, 'code': code, 'docs': docs}
253
259
 
254
260
 
@@ -259,6 +265,7 @@ def remove_para(source):
259
265
  else:
260
266
  return source
261
267
 
268
+
262
269
  def get_methods(obj):
263
270
  """Get methods from the given object."""
264
271
  methods = {at[0]: at[1] for at in inspect.getmembers(obj)
@@ -282,6 +289,8 @@ def get_obj_name(obj, role='', basename=''):
282
289
  name : str
283
290
  Name of the object.
284
291
  """
292
+ if inspect.isclass(obj):
293
+ return obj.__module__ + '.' + obj.__name__
285
294
  if hasattr(obj, 'get_full_name'):
286
295
  return obj.get_full_name()
287
296
  elif inspect.ismethod(obj):
@@ -301,3 +310,24 @@ def get_memory(role):
301
310
  else:
302
311
  mem = sys.getsizeof(role)
303
312
  return mem
313
+
314
+
315
+ def get_inheritance(obj):
316
+ """
317
+ Get the base class(es) that the object inherits from.
318
+
319
+ Parameters
320
+ ----------
321
+ obj : object
322
+ Object to get base of.
323
+
324
+ Returns
325
+ -------
326
+ classes : tuple
327
+ Tuple of classes that are the base of the object.
328
+ """
329
+ if inspect.isclass(obj):
330
+ return tuple([b for b in obj.__bases__
331
+ if b is not object and b is not dataobject])
332
+ else:
333
+ return (obj.__class__, )
@@ -37,30 +37,31 @@ class SimParam(Parameter, readonly=True):
37
37
  """
38
38
  Class defining Simulation parameters.
39
39
 
40
- Has fields:
41
- phases : tuple
42
- phases (('name', start, end)...) that the simulation progresses through
43
- start_time : float
44
- Start time of the simulation.
45
- end_time : float
46
- End time of the simulation.
47
- track_times : tuple
48
- Defines what times to include in the history.
49
- Options are:
50
- - ('all',)--all simulated times
51
- - ('interval', n)--includes every nth time in the history
52
- - ('times', [t1, ... tn])--only includes times defined in the
53
- vector [t1 ... tn]
54
- dt : float
55
- time-step used in the simulation. default is 1.0
56
- units : str
57
- time-units. default is hours`
58
- end_condition : str
59
- Name of indicator method to use to end the simulation. If not provided (''),
60
- the simulation ends at the final time. Default is ''
61
- use_local : bool
62
- Whether to use locally-defined time-steps in functions (if any).
63
- Default is True.
40
+ Parameters
41
+ ----------
42
+ phases : tuple
43
+ phases (('name', start, end)...) that the simulation progresses through
44
+ start_time : float
45
+ Start time of the simulation.
46
+ end_time : float
47
+ End time of the simulation.
48
+ track_times : tuple
49
+ Defines what times to include in the history.
50
+ Options are:
51
+ - ('all',)--all simulated times
52
+ - ('interval', n)--includes every nth time in the history
53
+ - ('times', [t1, ... tn])--only includes times defined in the
54
+ vector [t1 ... tn]
55
+ dt : float
56
+ time-step used in the simulation. default is 1.0
57
+ units : str
58
+ time-units. default is hours`
59
+ end_condition : str
60
+ Name of indicator method to use to end the simulation. If not provided (''),
61
+ the simulation ends at the final time. Default is ''
62
+ use_local : bool
63
+ Whether to use locally-defined time-steps in functions (if any).
64
+ Default is True.
64
65
  """
65
66
 
66
67
  rolename = "sp"
@@ -120,7 +120,7 @@ class Function(Block):
120
120
 
121
121
  def update_seed(self, seed=[]):
122
122
  """
123
- Update seed and propogates update to contained actions/components.
123
+ Update seed and propagates update to contained actions/components.
124
124
 
125
125
  (keeps seeds in sync)
126
126
 
@@ -27,8 +27,9 @@ import numpy as np
27
27
 
28
28
  class Parameter(BaseContainer, readonly=True):
29
29
  """
30
- The Parameter class defines model/function/flow values which are immutable,
31
- that is, the same from model instantiation through a simulation. Parameters
30
+ The Parameter class defines model/function/flow values which are immutable.
31
+
32
+ That is, the same from model instantiation through a simulation. Parameters
32
33
  inherit from recordclass, giving them a low memory footprint, and use type
33
34
  hints and ranges to ensure parameter values are valid. e.g.,:
34
35