fmdtools 2.5.1__tar.gz → 2.5.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.
- {fmdtools-2.5.1 → fmdtools-2.5.2}/LICENSE +1 -1
- {fmdtools-2.5.1/fmdtools.egg-info → fmdtools-2.5.2}/PKG-INFO +9 -6
- {fmdtools-2.5.1 → fmdtools-2.5.2}/README.md +7 -4
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/test_multirotor.py +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/test_rover.py +4 -3
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/model_main.py +8 -6
- {fmdtools-2.5.1 → fmdtools-2.5.2/fmdtools.egg-info}/PKG-INFO +9 -6
- {fmdtools-2.5.1 → fmdtools-2.5.2}/fmdtools.egg-info/SOURCES.txt +24 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/pyproject.toml +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/__init__.py +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/common.py +27 -18
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/history.py +12 -3
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/phases.py +7 -3
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/result.py +32 -18
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/tabulate.py +3 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/geom.py +4 -4
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/base.py +10 -7
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/base.py +2 -2
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/rand.py +25 -2
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/time.py +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/environment.py +6 -7
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/object/base.py +67 -43
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/object/coords.py +2 -2
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/object/geom.py +60 -19
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/sim/propagate.py +7 -3
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/sim/sample.py +16 -12
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/sim/scenario.py +3 -3
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/sim/search.py +2 -2
- fmdtools-2.5.2/tests/test_array_random_states.py +182 -0
- fmdtools-2.5.2/tests/test_calc_metric_ci_constant_outputs.py +218 -0
- fmdtools-2.5.2/tests/test_comparison_groups.py +162 -0
- fmdtools-2.5.2/tests/test_confidence_history_clipping.py +181 -0
- fmdtools-2.5.2/tests/test_error_history_plots.py +197 -0
- fmdtools-2.5.2/tests/test_fault_sample_without_nominal.py +231 -0
- fmdtools-2.5.2/tests/test_fault_time_without_traces.py +141 -0
- fmdtools-2.5.2/tests/test_history_standard_deviation.py +95 -0
- fmdtools-2.5.2/tests/test_join_phasemaps.py +94 -0
- fmdtools-2.5.2/tests/test_joint_fault_weights.py +116 -0
- fmdtools-2.5.2/tests/test_nested_nominal_groups.py +200 -0
- fmdtools-2.5.2/tests/test_nesting_custom_separators.py +151 -0
- fmdtools-2.5.2/tests/test_parameter_sample_seeds.py +104 -0
- fmdtools-2.5.2/tests/test_parameter_subsampling_types.py +147 -0
- fmdtools-2.5.2/tests/test_phase_timestep.py +73 -0
- fmdtools-2.5.2/tests/test_pruned_fault_times.py +163 -0
- fmdtools-2.5.2/tests/test_result.py +173 -0
- fmdtools-2.5.2/tests/test_sample.py +165 -0
- fmdtools-2.5.2/tests/test_scenario.py +111 -0
- fmdtools-2.5.2/tests/test_scenario_defaults.py +168 -0
- fmdtools-2.5.2/tests/test_table_factor_indices.py +154 -0
- fmdtools-2.5.2/tests/test_time.py +101 -0
- fmdtools-2.5.2/tests/test_uniform_density.py +83 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/model_asset.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/model_atc.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/model_common.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/test_asset.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airport_taxiway/test_model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/aircraftarchitecture.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/aviate.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/controlflight.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/flows.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/holdpayload.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/perceiveenvironment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/arch/storeee.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/parameter.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/base/state.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/contingency_management/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/contingency_management/model_aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/contingency_management/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/contingency_management/model_flightplanner.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/water_rescue/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/water_rescue/model_drone.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/water_rescue/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/water_rescue/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/water_rescue/model_responder.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/wildfire_response/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/wildfire_response/model_aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/wildfire_response/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/airspacelib/wildfire_response/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/cooling_tank/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/cooling_tank/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/cooling_tank/model_optimization.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/cooling_tank/test_tank.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/electric_power_system/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/electric_power_system/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/electric_power_system/test_model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/human_hazard_mitigation/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/human_hazard_mitigation/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/model_dynamic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/model_hierarchical.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/model_rural.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/model_static.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/model_urban.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/multirotor_drone/script_opt_model_rural.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/model_degradation.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/model_human.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/model_troupe.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/script_ea_analysis.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/script_mode_space.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/navigating_rover/script_search_rover.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/state_communication/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/state_communication/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/state_communication/test_multiflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/model_indiv.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/model_stochastic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/script_jointfaults.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/script_parallelism.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/test_pump.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/test_pump_example.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/examples/water_pump/test_pump_stochastic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/fmdtools.egg-info/dependency_links.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/fmdtools.egg-info/requires.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/fmdtools.egg-info/top_level.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/setup.cfg +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/graph/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/graph/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/graph/label.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/graph/model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/analyze/graph/style.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/action.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/component.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/architecture/function.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/block/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/block/action.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/block/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/block/component.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/block/function.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/mode.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/parameter.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/container/state.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/flow/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/flow/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/flow/commsflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/flow/multiflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/object/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/object/timer.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/define/pathplan.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/src/fmdtools/sim/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/common.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/test_geom.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/test_graph.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/test_hierarchical.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/test_packages.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.2}/tests/test_pathplan.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmdtools
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.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.5.
|
|
7
|
+
License: fmdtools version 2.5.2
|
|
8
8
|
---------------------------
|
|
9
9
|
Apache License
|
|
10
10
|
Version 2.0, January 2004
|
|
@@ -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.5.
|
|
397
|
+
git checkout v2.5.2
|
|
398
398
|
```
|
|
399
399
|
|
|
400
400
|
|
|
@@ -499,7 +499,10 @@ Once fmdtools is installed, use the following to get acquainted with how to use
|
|
|
499
499
|
Decent (but **very imperfect**) results can be achieved using LLMs for model development using the prompt:
|
|
500
500
|
|
|
501
501
|
```prompt
|
|
502
|
-
You are an experienced software engineer learning a new Python library for the first time.
|
|
502
|
+
You are an experienced software engineer learning a new Python library for the first time.
|
|
503
|
+
Make an fmdtools simulation of a <enter your system here> 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.
|
|
504
|
+
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.
|
|
505
|
+
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
506
|
```
|
|
504
507
|
|
|
505
508
|
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!
|
|
@@ -545,8 +548,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
545
548
|
author = {{NASA}},
|
|
546
549
|
title = {fmdtools},
|
|
547
550
|
url = {https://github.com/nasa/fmdtools},
|
|
548
|
-
version = {2.5.
|
|
549
|
-
date = {2026-9-
|
|
551
|
+
version = {2.5.2},
|
|
552
|
+
date = {2026-9-28},
|
|
550
553
|
}
|
|
551
554
|
```
|
|
552
555
|
|
|
@@ -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.5.
|
|
126
|
+
git checkout v2.5.2
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
|
|
@@ -228,7 +228,10 @@ Once fmdtools is installed, use the following to get acquainted with how to use
|
|
|
228
228
|
Decent (but **very imperfect**) results can be achieved using LLMs for model development using the prompt:
|
|
229
229
|
|
|
230
230
|
```prompt
|
|
231
|
-
You are an experienced software engineer learning a new Python library for the first time.
|
|
231
|
+
You are an experienced software engineer learning a new Python library for the first time.
|
|
232
|
+
Make an fmdtools simulation of a <enter your system here> 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.
|
|
233
|
+
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.
|
|
234
|
+
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
235
|
```
|
|
233
236
|
|
|
234
237
|
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!
|
|
@@ -274,8 +277,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
274
277
|
author = {{NASA}},
|
|
275
278
|
title = {fmdtools},
|
|
276
279
|
url = {https://github.com/nasa/fmdtools},
|
|
277
|
-
version = {2.5.
|
|
278
|
-
date = {2026-9-
|
|
280
|
+
version = {2.5.2},
|
|
281
|
+
date = {2026-9-28},
|
|
279
282
|
}
|
|
280
283
|
```
|
|
281
284
|
|
|
@@ -150,7 +150,7 @@ class DroneDisturbanceTest(unittest.TestCase):
|
|
|
150
150
|
amt = self.mdl.fxns['store_ee'].ca.comps['s1p1'].p.amt
|
|
151
151
|
soc_expected = soc_set - 100/amt
|
|
152
152
|
soc_res = self.edp.f2(soc_set)
|
|
153
|
-
self.
|
|
153
|
+
self.assertAlmostEqual(soc_expected, soc_res)
|
|
154
154
|
|
|
155
155
|
# make sure the disturbance wasn't set permanently
|
|
156
156
|
soc_later = self.edp.f1(soc_set)
|
|
@@ -18,6 +18,7 @@ specific language governing permissions and limitations under the License.
|
|
|
18
18
|
from fmdtools_tests.common import CommonTests
|
|
19
19
|
from fmdtools_examples.navigating_rover.script_search_rover import line_dist, line_dist_faster
|
|
20
20
|
import unittest
|
|
21
|
+
import numpy as np
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class RoverTests(unittest.TestCase, CommonTests):
|
|
@@ -29,9 +30,9 @@ class RoverTests(unittest.TestCase, CommonTests):
|
|
|
29
30
|
dist_int, enddist_int, endpt_int = line_dist_faster(testvalue)
|
|
30
31
|
dist, enddist, endpt = line_dist(testvalue)
|
|
31
32
|
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
33
|
+
self.assertTrue(np.isclose(dist, dist_int))
|
|
34
|
+
self.assertTrue(np.isclose(enddist, enddist_int))
|
|
35
|
+
self.assertTrue(np.isclose(endpt, endpt_int).all())
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
if __name__ == '__main__':
|
|
@@ -632,14 +632,14 @@ def script_sample_faults(track='all', **kwargs):
|
|
|
632
632
|
|
|
633
633
|
gh = mdlhists.get_comp_groups('flows.ee_1.s.current')
|
|
634
634
|
|
|
635
|
-
results, mdlhists_staged = propagate.fault_sample(mdl, faultapp,
|
|
636
|
-
|
|
635
|
+
# results, mdlhists_staged = propagate.fault_sample(mdl, faultapp,
|
|
636
|
+
# staged=True, track='all')
|
|
637
637
|
|
|
638
|
-
tab = an.tabulate.result_summary_fmea(
|
|
639
|
-
|
|
638
|
+
# tab = an.tabulate.result_summary_fmea(
|
|
639
|
+
# results, mdlhists, *mdl.fxns, *mdl.flows)
|
|
640
640
|
|
|
641
641
|
h = mdlhists.get_expected(app=faultapp, with_nominal=True)
|
|
642
|
-
ec = results.get_expected()
|
|
642
|
+
# ec = results.get_expected()
|
|
643
643
|
|
|
644
644
|
# degsumm = h.get_summary(*mdl.fxns, *mdl.flows)
|
|
645
645
|
|
|
@@ -658,7 +658,7 @@ def script_sample_faults(track='all', **kwargs):
|
|
|
658
658
|
fmea = an.tabulate.FMEA(results, faultapp)
|
|
659
659
|
fmea.as_table()
|
|
660
660
|
fmea.sort_by_metric("expected_cost")
|
|
661
|
-
fmea.as_plot("expected_cost", color_factor="
|
|
661
|
+
fmea.as_plot("expected_cost", color_factor="obj")
|
|
662
662
|
|
|
663
663
|
# test cases for multiplot legend/axis sharing
|
|
664
664
|
mdlhists.plot_line("flows.ee_1.s.current", "flows.sig_1.s.power",
|
|
@@ -679,6 +679,8 @@ if __name__ == "__main__":
|
|
|
679
679
|
mdl = Pump()
|
|
680
680
|
res, hist = propagate.nominal(mdl, to_return = {'graph': FunctionArchitectureGraph})
|
|
681
681
|
|
|
682
|
+
# script_sample_faults()
|
|
683
|
+
|
|
682
684
|
"""
|
|
683
685
|
endfaults, mdlhist = propagate.one_fault(mdl, 'export_water', 'block',
|
|
684
686
|
time=10, to_return='faults')
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fmdtools
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.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.5.
|
|
7
|
+
License: fmdtools version 2.5.2
|
|
8
8
|
---------------------------
|
|
9
9
|
Apache License
|
|
10
10
|
Version 2.0, January 2004
|
|
@@ -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.5.
|
|
397
|
+
git checkout v2.5.2
|
|
398
398
|
```
|
|
399
399
|
|
|
400
400
|
|
|
@@ -499,7 +499,10 @@ Once fmdtools is installed, use the following to get acquainted with how to use
|
|
|
499
499
|
Decent (but **very imperfect**) results can be achieved using LLMs for model development using the prompt:
|
|
500
500
|
|
|
501
501
|
```prompt
|
|
502
|
-
You are an experienced software engineer learning a new Python library for the first time.
|
|
502
|
+
You are an experienced software engineer learning a new Python library for the first time.
|
|
503
|
+
Make an fmdtools simulation of a <enter your system here> 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.
|
|
504
|
+
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.
|
|
505
|
+
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
506
|
```
|
|
504
507
|
|
|
505
508
|
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!
|
|
@@ -545,8 +548,8 @@ To cite a particular version of the fmdtools, you may use:
|
|
|
545
548
|
author = {{NASA}},
|
|
546
549
|
title = {fmdtools},
|
|
547
550
|
url = {https://github.com/nasa/fmdtools},
|
|
548
|
-
version = {2.5.
|
|
549
|
-
date = {2026-9-
|
|
551
|
+
version = {2.5.2},
|
|
552
|
+
date = {2026-9-28},
|
|
550
553
|
}
|
|
551
554
|
```
|
|
552
555
|
|
|
@@ -127,8 +127,31 @@ src/fmdtools/sim/scenario.py
|
|
|
127
127
|
src/fmdtools/sim/search.py
|
|
128
128
|
tests/__init__.py
|
|
129
129
|
tests/common.py
|
|
130
|
+
tests/test_array_random_states.py
|
|
131
|
+
tests/test_calc_metric_ci_constant_outputs.py
|
|
132
|
+
tests/test_comparison_groups.py
|
|
133
|
+
tests/test_confidence_history_clipping.py
|
|
134
|
+
tests/test_error_history_plots.py
|
|
135
|
+
tests/test_fault_sample_without_nominal.py
|
|
136
|
+
tests/test_fault_time_without_traces.py
|
|
130
137
|
tests/test_geom.py
|
|
131
138
|
tests/test_graph.py
|
|
132
139
|
tests/test_hierarchical.py
|
|
140
|
+
tests/test_history_standard_deviation.py
|
|
141
|
+
tests/test_join_phasemaps.py
|
|
142
|
+
tests/test_joint_fault_weights.py
|
|
143
|
+
tests/test_nested_nominal_groups.py
|
|
144
|
+
tests/test_nesting_custom_separators.py
|
|
133
145
|
tests/test_packages.py
|
|
134
|
-
tests/
|
|
146
|
+
tests/test_parameter_sample_seeds.py
|
|
147
|
+
tests/test_parameter_subsampling_types.py
|
|
148
|
+
tests/test_pathplan.py
|
|
149
|
+
tests/test_phase_timestep.py
|
|
150
|
+
tests/test_pruned_fault_times.py
|
|
151
|
+
tests/test_result.py
|
|
152
|
+
tests/test_sample.py
|
|
153
|
+
tests/test_scenario.py
|
|
154
|
+
tests/test_scenario_defaults.py
|
|
155
|
+
tests/test_table_factor_indices.py
|
|
156
|
+
tests/test_time.py
|
|
157
|
+
tests/test_uniform_density.py
|
|
@@ -41,7 +41,7 @@ import matplotlib.pyplot as plt
|
|
|
41
41
|
from matplotlib import rcParams
|
|
42
42
|
import inspect
|
|
43
43
|
from scipy.stats import bootstrap
|
|
44
|
-
from fmdtools.define.base import filter_kwargs
|
|
44
|
+
from fmdtools.define.base import filter_kwargs, round_float
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
plt.rcParams['pdf.fonttype'] = 42
|
|
@@ -229,7 +229,8 @@ def metric_preamble(data, dtype=None, rates=None, r_dtype=None, r_norm=False):
|
|
|
229
229
|
|
|
230
230
|
|
|
231
231
|
def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
232
|
-
rates=None, r_dtype=None, r_norm=False,
|
|
232
|
+
rates=None, r_dtype=None, r_norm=False, round_value=True,
|
|
233
|
+
res=1e-6, min_r=7, **kwargs):
|
|
233
234
|
"""
|
|
234
235
|
Calculate a metric from data.
|
|
235
236
|
|
|
@@ -253,12 +254,18 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
253
254
|
Datatype to preprocess the rates over. The default is None.
|
|
254
255
|
r_norm : bool, optional
|
|
255
256
|
Whether to normalize rates. The default is False.
|
|
257
|
+
round_value : bool, optional
|
|
258
|
+
Whether to round the value. Default is True.
|
|
259
|
+
res : float
|
|
260
|
+
Resolution to round to. Default is 1e-6.
|
|
261
|
+
min_r : int
|
|
262
|
+
Maximum number of digits to round to (see round_float).
|
|
256
263
|
**kwargs : kwargs
|
|
257
|
-
Keyword arguments to method.
|
|
264
|
+
Keyword arguments to method (see round_float).
|
|
258
265
|
|
|
259
266
|
Returns
|
|
260
267
|
-------
|
|
261
|
-
metric:
|
|
268
|
+
metric: np.float64/np.int64
|
|
262
269
|
Metric calculated by method over data.
|
|
263
270
|
|
|
264
271
|
Examples
|
|
@@ -266,7 +273,7 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
266
273
|
>>> calc_metric([1,2,3]) # simple average
|
|
267
274
|
np.float64(2.0)
|
|
268
275
|
>>> calc_metric([1,2,3], rates=[0.1, 0.1, 0.0], method=np.sum) # weighted sum
|
|
269
|
-
np.float64(0.
|
|
276
|
+
np.float64(0.3)
|
|
270
277
|
>>> calc_metric([0, 20, 30], dtype=bool, rates=[0.1, 0.1, 0.1], method=np.sum) # rate of nonzero event
|
|
271
278
|
np.float64(0.2)
|
|
272
279
|
>>> calc_metric([0, 1, 2], "total")
|
|
@@ -276,11 +283,15 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
276
283
|
"""
|
|
277
284
|
if isinstance(method, str):
|
|
278
285
|
method = eval("calc_"+method)
|
|
279
|
-
|
|
286
|
+
metric = method(data, args=args, axis=axis, dtype=dtype, rates=rates,
|
|
280
287
|
r_dtype=r_dtype, r_norm=r_norm, **kwargs)
|
|
281
288
|
else:
|
|
282
289
|
vals = metric_preamble(data, dtype, rates, r_dtype, r_norm)
|
|
283
|
-
|
|
290
|
+
metric = method(vals, *args, **filter_kwargs(method, **kwargs, axis=axis))
|
|
291
|
+
if round_value and (isinstance(metric, np.floating) or isinstance(metric, float)):
|
|
292
|
+
return round_float(metric, res=res, min_r=min_r)
|
|
293
|
+
else:
|
|
294
|
+
return metric
|
|
284
295
|
|
|
285
296
|
|
|
286
297
|
def calc_metric_ci(data, method=np.average, return_anyway=False, interval=None,
|
|
@@ -325,15 +336,13 @@ def calc_metric_ci(data, method=np.average, return_anyway=False, interval=None,
|
|
|
325
336
|
bs_kwar['confidence_level'] = interval*0.01
|
|
326
337
|
|
|
327
338
|
vals = metric_preamble(data, **filter_kwargs(metric_preamble, **kwargs))
|
|
328
|
-
|
|
329
|
-
val = vals[axis, 0]
|
|
330
|
-
else:
|
|
331
|
-
val = np.array(vals).flatten()[0]
|
|
339
|
+
val = np.take(vals, [0], axis=axis)
|
|
332
340
|
if "weights" in kwargs and kwargs['weights'] is not None:
|
|
333
341
|
raise Exception("Weights not able to be used w- bootstrap--use rates instead.")
|
|
334
342
|
met_val = method(vals, axis=axis, **filter_kwargs(method, **kwargs))
|
|
335
343
|
vals_vary = vals == val
|
|
336
|
-
|
|
344
|
+
# Preserve the existing policy for globally identical data.
|
|
345
|
+
if not np.all(vals == vals.flat[0]):
|
|
337
346
|
if np.any(np.all(vals_vary, axis=axis)):
|
|
338
347
|
# use more robust/basic algorithm if some indices don't vary
|
|
339
348
|
bs = bootstrap([vals], method, axis=axis, method="basic", **bs_kwar)
|
|
@@ -353,7 +362,7 @@ def calc_rate(data, rates=None, weights=None, **kwargs):
|
|
|
353
362
|
Examples
|
|
354
363
|
--------
|
|
355
364
|
>>> calc_rate([0, 10, 0]) # defaults to equal rate
|
|
356
|
-
np.float64(0.
|
|
365
|
+
np.float64(0.333333)
|
|
357
366
|
>>> calc_rate([0, 10, 100], [0.1, 0.1, 0.1]) # provided rates
|
|
358
367
|
np.float64(0.2)
|
|
359
368
|
"""
|
|
@@ -370,7 +379,7 @@ def calc_percent(data, weights=None, rates=None, **kwargs):
|
|
|
370
379
|
Examples
|
|
371
380
|
--------
|
|
372
381
|
>>> calc_percent([0, 10, 0])
|
|
373
|
-
np.float64(0.
|
|
382
|
+
np.float64(0.333333)
|
|
374
383
|
"""
|
|
375
384
|
return calc_metric(data, **{**kwargs, 'dtype': bool})
|
|
376
385
|
|
|
@@ -386,7 +395,7 @@ def calc_total(data, weights=None, **kwargs):
|
|
|
386
395
|
>>> calc_total([0, 10, 100])
|
|
387
396
|
np.int64(2)
|
|
388
397
|
"""
|
|
389
|
-
return calc_metric(data, **{**kwargs, 'method': np.sum, 'dtype': bool})
|
|
398
|
+
return np.int64(calc_metric(data, **{**kwargs, 'method': np.sum, 'dtype': bool}))
|
|
390
399
|
|
|
391
400
|
|
|
392
401
|
def calc_expected(data, rates=None, weights=None, **kwargs):
|
|
@@ -519,8 +528,8 @@ def plot_err_hist(err_hist, ax=None, fig=None, figsize=(6, 4), boundtype='fill',
|
|
|
519
528
|
fig : mpl figure
|
|
520
529
|
ax :mpl, axis
|
|
521
530
|
"""
|
|
522
|
-
fig, ax = setup_plot(fig, ax, figsize)
|
|
523
|
-
ax.plot(err_hist['stat'], **kwargs)
|
|
531
|
+
fig, ax = setup_plot(fig=fig, ax=ax, figsize=figsize)
|
|
532
|
+
ax.plot(err_hist[time], err_hist['stat'], **kwargs)
|
|
524
533
|
if boundtype == 'fill':
|
|
525
534
|
col = ax.lines[-1].get_color()
|
|
526
535
|
ax.fill_between(err_hist[time], err_hist['low'], err_hist['high'],
|
|
@@ -582,7 +591,7 @@ def plot_err_lines(times, lows, highs, ax=None, fig=None, figsize=(6, 4), **kwar
|
|
|
582
591
|
**kwargs : kwargs
|
|
583
592
|
kwargs for the line
|
|
584
593
|
"""
|
|
585
|
-
fig, ax = setup_plot(
|
|
594
|
+
fig, ax = setup_plot(fig=fig, ax=ax, figsize=figsize)
|
|
586
595
|
ax.plot(times, highs, **kwargs)
|
|
587
596
|
ax.plot(times, lows, **kwargs)
|
|
588
597
|
return fig, ax
|
|
@@ -360,6 +360,9 @@ class History(Result):
|
|
|
360
360
|
"""
|
|
361
361
|
Get the time a fault is present in the system.
|
|
362
362
|
|
|
363
|
+
Only recorded fault traces are considered. Without recorded faults,
|
|
364
|
+
returns zero for ``total`` and ``nan`` for the position metrics.
|
|
365
|
+
|
|
363
366
|
Parameters
|
|
364
367
|
----------
|
|
365
368
|
metric : 'earliest','latest','total', 'times', optional
|
|
@@ -373,6 +376,8 @@ class History(Result):
|
|
|
373
376
|
|
|
374
377
|
Examples
|
|
375
378
|
--------
|
|
379
|
+
>>> History(time=[0, 1, 2]).get_fault_time()
|
|
380
|
+
nan
|
|
376
381
|
>>> History({'m.faults.fault1': [False, False, False]}).get_fault_time()
|
|
377
382
|
nan
|
|
378
383
|
>>> History({'m.faults.fault1': [False, False, True]}).get_fault_time()
|
|
@@ -383,7 +388,7 @@ class History(Result):
|
|
|
383
388
|
if metric == 'total':
|
|
384
389
|
return np.sum(all_faults_hist >= 1)
|
|
385
390
|
else:
|
|
386
|
-
times = np.where(all_faults_hist >= 1)[0]
|
|
391
|
+
times = np.where(np.atleast_1d(all_faults_hist) >= 1)[0]
|
|
387
392
|
if times.size == 0:
|
|
388
393
|
return np.nan
|
|
389
394
|
elif metric == 'times':
|
|
@@ -809,6 +814,8 @@ class History(Result):
|
|
|
809
814
|
"""
|
|
810
815
|
Get aggregated err_hist of means surrounded by std deviation.
|
|
811
816
|
|
|
817
|
+
Calculate the spread across histories separately at each time sample.
|
|
818
|
+
|
|
812
819
|
Parameters
|
|
813
820
|
----------
|
|
814
821
|
value : str
|
|
@@ -829,7 +836,7 @@ class History(Result):
|
|
|
829
836
|
hist = History()
|
|
830
837
|
hist[time] = self.get_metric(time, axis=0)
|
|
831
838
|
hist['stat'] = self.get_metric(value, np.mean, axis=0)
|
|
832
|
-
std_dev = self.get_metric(value, np.std)
|
|
839
|
+
std_dev = self.get_metric(value, np.std, axis=0)
|
|
833
840
|
hist['high'] = hist['stat']+std_dev/2
|
|
834
841
|
hist['low'] = hist['stat']-std_dev/2
|
|
835
842
|
return hist
|
|
@@ -851,7 +858,8 @@ class History(Result):
|
|
|
851
858
|
ci : float
|
|
852
859
|
Fraction for confidence interval. Default is 0.95.
|
|
853
860
|
max_ind : str/int
|
|
854
|
-
|
|
861
|
+
Exclusive slice endpoint for both timestamps and values. Default is
|
|
862
|
+
'max', which uses the shortest history length.
|
|
855
863
|
|
|
856
864
|
Returns
|
|
857
865
|
-------
|
|
@@ -874,6 +882,7 @@ class History(Result):
|
|
|
874
882
|
hist[time] = self.get_metric(time, axis=0)
|
|
875
883
|
if max_ind == 'max':
|
|
876
884
|
max_ind = min([len(h) for h in self.values()])
|
|
885
|
+
hist[time] = hist[time][:max_ind]
|
|
877
886
|
vals = np.array([*self.get_values(value).values()])[:, :max_ind]
|
|
878
887
|
boot_stats = calc_metric_ci(vals, confidence_level=ci, axis=0, **kwargs)
|
|
879
888
|
hist['stat'] = boot_stats[0]
|
|
@@ -80,7 +80,7 @@ class PhaseMap(object):
|
|
|
80
80
|
def __repr__(self):
|
|
81
81
|
return 'PhaseMap(' + str(self.phases) + ', ' + str(self.modephases) + ')'
|
|
82
82
|
|
|
83
|
-
def find_phase(self, time, dt=
|
|
83
|
+
def find_phase(self, time, dt=None):
|
|
84
84
|
"""
|
|
85
85
|
Find the phase that a time occurs in.
|
|
86
86
|
|
|
@@ -88,12 +88,17 @@ class PhaseMap(object):
|
|
|
88
88
|
----------
|
|
89
89
|
time : float
|
|
90
90
|
Occurence time.
|
|
91
|
+
dt : float, optional
|
|
92
|
+
Width of the final sample in each phase. Defaults to this map's dt.
|
|
93
|
+
An explicit value overrides the configured timestep for this lookup.
|
|
91
94
|
|
|
92
95
|
Returns
|
|
93
96
|
-------
|
|
94
97
|
phase : str
|
|
95
98
|
Name of the phase time occurs in.
|
|
96
99
|
"""
|
|
100
|
+
if dt is None:
|
|
101
|
+
dt = self.dt
|
|
97
102
|
for phase, times in self.phases.items():
|
|
98
103
|
if times[0] <= time < times[1]+dt:
|
|
99
104
|
return phase
|
|
@@ -677,8 +682,7 @@ def join_phasemaps(*phasemaps):
|
|
|
677
682
|
joint_phases = {}
|
|
678
683
|
all_combos = [*itertools.product(*[phasemap.phases for phasemap in phasemaps])]
|
|
679
684
|
for combo in all_combos:
|
|
680
|
-
|
|
681
|
-
intervals = [i for i in phases.values()]
|
|
685
|
+
intervals = [phasemaps[i].phases[c] for i, c in enumerate(combo)]
|
|
682
686
|
joined_interval = find_interval_overlap(*intervals)
|
|
683
687
|
if joined_interval:
|
|
684
688
|
joint_phases[combo] = joined_interval
|
|
@@ -41,6 +41,7 @@ specific language governing permissions and limitations under the License.
|
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
43
|
from fmdtools.define.base import t_key, nest_dict, is_numeric, is_bool, is_iter
|
|
44
|
+
from fmdtools.define.base import round_float
|
|
44
45
|
from fmdtools.analyze.common import to_include_keys, create_indiv_filename
|
|
45
46
|
from fmdtools.analyze.common import calc_metric, calc_metric_ci, join_key
|
|
46
47
|
from fmdtools.analyze.common import get_sub_include, unpack_plot_values
|
|
@@ -551,7 +552,9 @@ class Result(UserDict):
|
|
|
551
552
|
*values : str
|
|
552
553
|
Values to get (e.g. `fxns.fxnname.s.val`)
|
|
553
554
|
**groups : list
|
|
554
|
-
Sets of scenarios to group (e.g. set_1=['scen1', 'scen2'...])
|
|
555
|
+
Sets of scenarios to group (e.g. set_1=['scen1', 'scen2'...]).
|
|
556
|
+
Scenario names match at dot-separated path boundaries; selecting a
|
|
557
|
+
parent scenario also includes its nested scenarios.
|
|
555
558
|
|
|
556
559
|
Returns
|
|
557
560
|
-------
|
|
@@ -569,7 +572,7 @@ class Result(UserDict):
|
|
|
569
572
|
elif isinstance(scens, str):
|
|
570
573
|
scens = [scens]
|
|
571
574
|
k_vs = [k for k in self.keys() for scen in scens for v in values
|
|
572
|
-
if k.startswith(scen) and k.endswith(v) and '.t.' not in k]
|
|
575
|
+
if k.startswith(scen+'.') and k.endswith(v) and '.t.' not in k]
|
|
573
576
|
if len(k_vs) > 0 and (group not in group_hist):
|
|
574
577
|
group_hist[group] = self.__class__()
|
|
575
578
|
for k in k_vs:
|
|
@@ -587,22 +590,26 @@ class Result(UserDict):
|
|
|
587
590
|
|
|
588
591
|
def get_default_comp_groups(self):
|
|
589
592
|
"""
|
|
590
|
-
Get
|
|
593
|
+
Get nominal and faulty keys for single or nested scenario samples.
|
|
594
|
+
|
|
595
|
+
Nested samples retain their parent prefix (e.g., ``sample.nominal``).
|
|
596
|
+
Only a scenario named exactly ``nominal`` belongs to the nominal group.
|
|
591
597
|
|
|
592
598
|
Returns
|
|
593
599
|
-------
|
|
594
600
|
comp_groups : dict
|
|
595
601
|
Dict with structure {'nominal': [list of nominal scenarios], 'faulty': [list of faulty scenarios]}.
|
|
596
|
-
If no nominal
|
|
602
|
+
If no nominal scenario is found, returns {'default': 'default'}.
|
|
597
603
|
"""
|
|
598
|
-
|
|
599
|
-
|
|
604
|
+
flat = self.flatten()
|
|
605
|
+
nest = flat.nest(1)
|
|
606
|
+
nest2 = flat.nest(1, skip=1)
|
|
600
607
|
if 'nominal' in nest.keys():
|
|
601
608
|
comp_groups = {'nominal': 'nominal',
|
|
602
609
|
'faulty': [f for f in nest.keys() if f != 'nominal']}
|
|
603
|
-
elif any(
|
|
604
|
-
comp_groups = {'nominal': [f for f in nest2
|
|
605
|
-
'faulty': [f for f in nest2
|
|
610
|
+
elif any(k.endswith('.nominal') for k in nest2):
|
|
611
|
+
comp_groups = {'nominal': [f for f in nest2 if f.endswith('.nominal')],
|
|
612
|
+
'faulty': [f for f in nest2 if not f.endswith('.nominal')]}
|
|
606
613
|
else:
|
|
607
614
|
comp_groups = {'default': 'default'}
|
|
608
615
|
return comp_groups
|
|
@@ -781,7 +788,8 @@ class Result(UserDict):
|
|
|
781
788
|
else:
|
|
782
789
|
return tab.loc[:, metrics]
|
|
783
790
|
|
|
784
|
-
def get_expected(self, app=[], with_nominal=False, difference_from_nominal=False
|
|
791
|
+
def get_expected(self, app=[], with_nominal=False, difference_from_nominal=False,
|
|
792
|
+
round_value=True, res=1e-6, **kwargs):
|
|
785
793
|
"""
|
|
786
794
|
Take the expectation of numeric metrics in the result over given scenarios.
|
|
787
795
|
|
|
@@ -795,6 +803,8 @@ class Result(UserDict):
|
|
|
795
803
|
difference_from_nominal : bool, optional
|
|
796
804
|
Whether to calculated the difference of the expectation from nominal.
|
|
797
805
|
The default is False.
|
|
806
|
+
**kwargs
|
|
807
|
+
kwargs to round_float
|
|
798
808
|
|
|
799
809
|
Returns
|
|
800
810
|
-------
|
|
@@ -808,21 +818,25 @@ class Result(UserDict):
|
|
|
808
818
|
newhists = {k: hist for k, hist in mh.items()
|
|
809
819
|
if not ('nominal' in k and not (with_nominal))}
|
|
810
820
|
if app:
|
|
811
|
-
|
|
821
|
+
scenario_rates = {scen.name: scen.rate for scen in app.scenarios()}
|
|
812
822
|
if with_nominal:
|
|
813
|
-
|
|
823
|
+
scenario_rates['nominal'] = 1
|
|
824
|
+
weights = [scenario_rates[name] for name in newhists]
|
|
814
825
|
else:
|
|
815
826
|
weights = [1 for k in newhists]
|
|
816
827
|
|
|
817
828
|
expres = self.__class__()
|
|
818
829
|
for k in nomhist.keys():
|
|
819
830
|
if difference_from_nominal:
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
831
|
+
value = np.average([nomhist[k]-hist[k] for hist in newhists.values()],
|
|
832
|
+
axis=0, weights=weights)
|
|
833
|
+
else:
|
|
834
|
+
value = np.average([hist[k] for hist in newhists.values()],
|
|
835
|
+
axis=0, weights=weights)
|
|
836
|
+
if round_value:
|
|
837
|
+
expres[k] = round_float(value, res=res, **kwargs)
|
|
823
838
|
else:
|
|
824
|
-
expres[k] =
|
|
825
|
-
axis=0, weights=weights)
|
|
839
|
+
expres[k] = value
|
|
826
840
|
return expres
|
|
827
841
|
|
|
828
842
|
def get_metric(self, value, method=np.average, rates=None, weights=None, prefix="",
|
|
@@ -856,7 +870,7 @@ class Result(UserDict):
|
|
|
856
870
|
>>> r.get_metric("b", method="expected", rates="a")
|
|
857
871
|
np.float64(0.005)
|
|
858
872
|
>>> r.get_metric("b", "expected", rates={"t1": 1, "t2": 2})
|
|
859
|
-
np.float64(0.
|
|
873
|
+
np.float64(0.21)
|
|
860
874
|
"""
|
|
861
875
|
vals, rates, weights = self.get_vals(value, prefix=prefix,
|
|
862
876
|
rates=rates, weights=weights)
|
|
@@ -179,13 +179,15 @@ class BaseTab(UserDict):
|
|
|
179
179
|
Parameters
|
|
180
180
|
----------
|
|
181
181
|
factor : str/int
|
|
182
|
-
|
|
182
|
+
Factor name or zero-based tuple index to sort by. Negative indices
|
|
183
|
+
follow the usual Python indexing convention.
|
|
183
184
|
reverse : bool, optional
|
|
184
185
|
Whether to sort in descending order. The default is False.
|
|
185
186
|
"""
|
|
186
187
|
metric = [*self.keys()][0]
|
|
187
188
|
keys = [k for k in self[metric].keys()]
|
|
188
189
|
|
|
190
|
+
value = factor
|
|
189
191
|
if hasattr(self, 'factors') and isinstance(factor, str):
|
|
190
192
|
value = self.factors.index(factor)
|
|
191
193
|
|
|
@@ -147,7 +147,7 @@ class GeomArchitecture(Architecture):
|
|
|
147
147
|
if not isinstance(gclass, baseclass):
|
|
148
148
|
raise Exception("gclass "+gclass+" not a "+baseclass.__name__)
|
|
149
149
|
|
|
150
|
-
def add_geom(self, name,
|
|
150
|
+
def add_geom(self, name, gclass=GeomJSON, **kwargs):
|
|
151
151
|
"""
|
|
152
152
|
Add/instantiate an individual geom to the architecture.
|
|
153
153
|
|
|
@@ -158,13 +158,13 @@ class GeomArchitecture(Architecture):
|
|
|
158
158
|
----------
|
|
159
159
|
name : str
|
|
160
160
|
Name for the geom.
|
|
161
|
-
|
|
161
|
+
gclass : BaseGeom, optional
|
|
162
162
|
Class to instantiate. The default is GeomJSON.
|
|
163
163
|
**kwargs : kwargs
|
|
164
164
|
Keyword arguments to the class.
|
|
165
165
|
"""
|
|
166
|
-
self.check_geom_class(
|
|
167
|
-
self.add_flex_role_obj("geoms", name, objclass=
|
|
166
|
+
self.check_geom_class(gclass, BaseGeom)
|
|
167
|
+
self.add_flex_role_obj("geoms", name, objclass=gclass, **kwargs)
|
|
168
168
|
|
|
169
169
|
def all_at(self, *pt):
|
|
170
170
|
"""
|