fmdtools 2.5.1__tar.gz → 2.5.3__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.3}/LICENSE +1 -1
- {fmdtools-2.5.1/fmdtools.egg-info → fmdtools-2.5.3}/PKG-INFO +9 -6
- {fmdtools-2.5.1 → fmdtools-2.5.3}/README.md +7 -4
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/model_urban.py +4 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/test_multirotor.py +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/test_rover.py +4 -3
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/model_main.py +8 -6
- {fmdtools-2.5.1 → fmdtools-2.5.3/fmdtools.egg-info}/PKG-INFO +9 -6
- {fmdtools-2.5.1 → fmdtools-2.5.3}/fmdtools.egg-info/SOURCES.txt +42 -1
- {fmdtools-2.5.1 → fmdtools-2.5.3}/pyproject.toml +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/__init__.py +1 -1
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/common.py +46 -35
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/history.py +16 -4
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/phases.py +16 -6
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/result.py +57 -34
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/tabulate.py +3 -1
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/geom.py +4 -4
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/base.py +12 -8
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/block/base.py +33 -15
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/base.py +2 -2
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/rand.py +132 -41
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/time.py +8 -2
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/environment.py +6 -7
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/object/base.py +67 -43
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/object/coords.py +2 -2
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/object/geom.py +60 -19
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/sim/propagate.py +7 -3
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/sim/sample.py +20 -15
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/sim/scenario.py +3 -3
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/sim/search.py +2 -2
- fmdtools-2.5.3/tests/test_array_differences.py +153 -0
- fmdtools-2.5.3/tests/test_array_random_states.py +182 -0
- fmdtools-2.5.3/tests/test_array_result_equality.py +167 -0
- fmdtools-2.5.3/tests/test_bootstrap_statistic_arguments.py +196 -0
- fmdtools-2.5.3/tests/test_calc_metric_ci_constant_outputs.py +218 -0
- fmdtools-2.5.3/tests/test_comparison_groups.py +162 -0
- fmdtools-2.5.3/tests/test_confidence_history_clipping.py +181 -0
- fmdtools-2.5.3/tests/test_error_history_plots.py +197 -0
- fmdtools-2.5.3/tests/test_exact_nominal_expectation.py +166 -0
- fmdtools-2.5.3/tests/test_explicit_result_file_formats.py +176 -0
- fmdtools-2.5.3/tests/test_exponential_rayleigh_draw_sizes.py +239 -0
- fmdtools-2.5.3/tests/test_fault_sample_without_nominal.py +231 -0
- fmdtools-2.5.3/tests/test_fault_time_without_traces.py +141 -0
- fmdtools-2.5.3/tests/test_gamma_sampling_density.py +233 -0
- fmdtools-2.5.3/tests/test_history_phase_identifiers.py +204 -0
- fmdtools-2.5.3/tests/test_history_standard_deviation.py +95 -0
- fmdtools-2.5.3/tests/test_independent_single_replicate_seeds.py +201 -0
- fmdtools-2.5.3/tests/test_individual_result_paths.py +165 -0
- fmdtools-2.5.3/tests/test_integer_draw_mass.py +266 -0
- fmdtools-2.5.3/tests/test_join_phasemaps.py +94 -0
- fmdtools-2.5.3/tests/test_joint_fault_weights.py +116 -0
- fmdtools-2.5.3/tests/test_json_result_arrays.py +163 -0
- fmdtools-2.5.3/tests/test_named_metric_rounding.py +152 -0
- fmdtools-2.5.3/tests/test_nested_nominal_groups.py +200 -0
- fmdtools-2.5.3/tests/test_nesting_custom_separators.py +151 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/test_packages.py +1 -1
- fmdtools-2.5.3/tests/test_parameter_sample_seeds.py +104 -0
- fmdtools-2.5.3/tests/test_parameter_subsampling_types.py +147 -0
- fmdtools-2.5.3/tests/test_pareto_density.py +203 -0
- fmdtools-2.5.3/tests/test_phase_timestep.py +73 -0
- fmdtools-2.5.3/tests/test_pruned_fault_times.py +163 -0
- fmdtools-2.5.3/tests/test_result.py +173 -0
- fmdtools-2.5.3/tests/test_result_folder_selection.py +191 -0
- fmdtools-2.5.3/tests/test_sample.py +165 -0
- fmdtools-2.5.3/tests/test_scenario.py +111 -0
- fmdtools-2.5.3/tests/test_scenario_defaults.py +168 -0
- fmdtools-2.5.3/tests/test_standard_t_density.py +192 -0
- fmdtools-2.5.3/tests/test_table_factor_indices.py +154 -0
- fmdtools-2.5.3/tests/test_time.py +101 -0
- fmdtools-2.5.3/tests/test_uniform_density.py +83 -0
- fmdtools-2.5.3/tests/test_unit_random_density.py +176 -0
- fmdtools-2.5.3/tests/test_vonmises_density.py +222 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/model_asset.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/model_atc.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/model_common.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/test_asset.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airport_taxiway/test_model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/aircraftarchitecture.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/aviate.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/controlflight.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/flows.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/holdpayload.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/perceiveenvironment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/arch/storeee.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/parameter.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/base/state.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/contingency_management/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/contingency_management/model_aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/contingency_management/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/contingency_management/model_flightplanner.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/water_rescue/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/water_rescue/model_drone.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/water_rescue/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/water_rescue/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/water_rescue/model_responder.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/wildfire_response/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/wildfire_response/model_aircraft.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/wildfire_response/model_environment.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/airspacelib/wildfire_response/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/cooling_tank/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/cooling_tank/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/cooling_tank/model_optimization.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/cooling_tank/test_tank.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/electric_power_system/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/electric_power_system/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/electric_power_system/test_model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/human_hazard_mitigation/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/human_hazard_mitigation/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/model_dynamic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/model_hierarchical.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/model_rural.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/model_static.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/multirotor_drone/script_opt_model_rural.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/model_degradation.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/model_human.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/model_troupe.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/script_ea_analysis.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/script_mode_space.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/navigating_rover/script_search_rover.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/state_communication/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/state_communication/model_main.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/state_communication/test_multiflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/model_indiv.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/model_stochastic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/script_jointfaults.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/script_parallelism.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/test_pump.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/test_pump_example.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/examples/water_pump/test_pump_stochastic.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/fmdtools.egg-info/dependency_links.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/fmdtools.egg-info/requires.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/fmdtools.egg-info/top_level.txt +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/setup.cfg +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/graph/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/graph/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/graph/label.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/graph/model.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/analyze/graph/style.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/action.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/component.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/architecture/function.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/block/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/block/action.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/block/component.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/block/function.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/mode.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/parameter.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/container/state.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/flow/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/flow/base.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/flow/commsflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/flow/multiflow.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/object/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/object/timer.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/define/pathplan.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/src/fmdtools/sim/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/__init__.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/common.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/test_geom.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/test_graph.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/tests/test_hierarchical.py +0 -0
- {fmdtools-2.5.1 → fmdtools-2.5.3}/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.3
|
|
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.3
|
|
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.3
|
|
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.3},
|
|
552
|
+
date = {2026-9-30},
|
|
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.3
|
|
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.3},
|
|
281
|
+
date = {2026-9-30},
|
|
279
282
|
}
|
|
280
283
|
```
|
|
281
284
|
|
|
@@ -322,6 +322,7 @@ class Drone(DroneRural):
|
|
|
322
322
|
('taxi', 12, 20)),
|
|
323
323
|
end_time=30,
|
|
324
324
|
units='min',
|
|
325
|
+
use_local=False,
|
|
325
326
|
dt=0.1)
|
|
326
327
|
|
|
327
328
|
def init_architecture(self, **kwargs):
|
|
@@ -499,6 +500,9 @@ if __name__ == "__main__":
|
|
|
499
500
|
# UrbanDroneEnvironment("a")
|
|
500
501
|
# PlanPath._init_environment("a")
|
|
501
502
|
# p = PlanPath("test", {})
|
|
503
|
+
mdl = Drone(sp={'end_condition': 'scenario_finished', 'dt': 0.1}, t={'local_dt': 0.1})
|
|
504
|
+
results_fault, hist_fault = propagate.one_fault(mdl, "affect_dof.ca.comps.lr", "mechbreak", time=1.4)
|
|
505
|
+
fig, ax = plot_env_with_traj_z(hist_fault, mdl, title = "Urban Drone Trajectory")
|
|
502
506
|
|
|
503
507
|
e = UrbanDroneEnvironment("env")
|
|
504
508
|
e.c.show({"height": {}})
|
|
@@ -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.3
|
|
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.3
|
|
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.3
|
|
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.3},
|
|
552
|
+
date = {2026-9-30},
|
|
550
553
|
}
|
|
551
554
|
```
|
|
552
555
|
|
|
@@ -127,8 +127,49 @@ 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_differences.py
|
|
131
|
+
tests/test_array_random_states.py
|
|
132
|
+
tests/test_array_result_equality.py
|
|
133
|
+
tests/test_bootstrap_statistic_arguments.py
|
|
134
|
+
tests/test_calc_metric_ci_constant_outputs.py
|
|
135
|
+
tests/test_comparison_groups.py
|
|
136
|
+
tests/test_confidence_history_clipping.py
|
|
137
|
+
tests/test_error_history_plots.py
|
|
138
|
+
tests/test_exact_nominal_expectation.py
|
|
139
|
+
tests/test_explicit_result_file_formats.py
|
|
140
|
+
tests/test_exponential_rayleigh_draw_sizes.py
|
|
141
|
+
tests/test_fault_sample_without_nominal.py
|
|
142
|
+
tests/test_fault_time_without_traces.py
|
|
143
|
+
tests/test_gamma_sampling_density.py
|
|
130
144
|
tests/test_geom.py
|
|
131
145
|
tests/test_graph.py
|
|
132
146
|
tests/test_hierarchical.py
|
|
147
|
+
tests/test_history_phase_identifiers.py
|
|
148
|
+
tests/test_history_standard_deviation.py
|
|
149
|
+
tests/test_independent_single_replicate_seeds.py
|
|
150
|
+
tests/test_individual_result_paths.py
|
|
151
|
+
tests/test_integer_draw_mass.py
|
|
152
|
+
tests/test_join_phasemaps.py
|
|
153
|
+
tests/test_joint_fault_weights.py
|
|
154
|
+
tests/test_json_result_arrays.py
|
|
155
|
+
tests/test_named_metric_rounding.py
|
|
156
|
+
tests/test_nested_nominal_groups.py
|
|
157
|
+
tests/test_nesting_custom_separators.py
|
|
133
158
|
tests/test_packages.py
|
|
134
|
-
tests/
|
|
159
|
+
tests/test_parameter_sample_seeds.py
|
|
160
|
+
tests/test_parameter_subsampling_types.py
|
|
161
|
+
tests/test_pareto_density.py
|
|
162
|
+
tests/test_pathplan.py
|
|
163
|
+
tests/test_phase_timestep.py
|
|
164
|
+
tests/test_pruned_fault_times.py
|
|
165
|
+
tests/test_result.py
|
|
166
|
+
tests/test_result_folder_selection.py
|
|
167
|
+
tests/test_sample.py
|
|
168
|
+
tests/test_scenario.py
|
|
169
|
+
tests/test_scenario_defaults.py
|
|
170
|
+
tests/test_standard_t_density.py
|
|
171
|
+
tests/test_table_factor_indices.py
|
|
172
|
+
tests/test_time.py
|
|
173
|
+
tests/test_uniform_density.py
|
|
174
|
+
tests/test_unit_random_density.py
|
|
175
|
+
tests/test_vonmises_density.py
|
|
@@ -41,7 +41,8 @@ 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
|
+
from functools import partial
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
plt.rcParams['pdf.fonttype'] = 42
|
|
@@ -180,11 +181,11 @@ def create_indiv_filename(filename, indiv_id, splitchar='_'):
|
|
|
180
181
|
--------
|
|
181
182
|
>>> create_indiv_filename("hi.csv", "4")
|
|
182
183
|
'hi_4.csv'
|
|
184
|
+
>>> create_indiv_filename("runs.v1/results.v2.csv", "4", splitchar="/")
|
|
185
|
+
'runs.v1/results.v2/4.csv'
|
|
183
186
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
filename_parts.insert(1, splitchar+indiv_id)
|
|
187
|
-
return "".join(filename_parts)
|
|
187
|
+
stem, extension = os.path.splitext(filename)
|
|
188
|
+
return stem + splitchar + indiv_id + extension
|
|
188
189
|
|
|
189
190
|
|
|
190
191
|
def load_folder(folder, filetype):
|
|
@@ -198,20 +199,17 @@ def load_folder(folder, filetype):
|
|
|
198
199
|
folder : str
|
|
199
200
|
Name of the folder. Must be in the current directory
|
|
200
201
|
filetype : str
|
|
201
|
-
Type of files in the folder ('
|
|
202
|
+
Type of files in the folder ('npz', 'csv', or 'json'). Other extensions
|
|
203
|
+
and subdirectories are ignored; matching files are not searched recursively.
|
|
202
204
|
|
|
203
205
|
Returns
|
|
204
206
|
-------
|
|
205
207
|
files_to_read : list
|
|
206
208
|
files to load for results/mdlhists.
|
|
207
209
|
"""
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
read_filetype = auto_filetype(file)
|
|
212
|
-
if read_filetype == filetype:
|
|
213
|
-
files_toread.append(file)
|
|
214
|
-
return files_toread
|
|
210
|
+
return [file for file in os.listdir(folder)
|
|
211
|
+
if file.endswith('.' + filetype)
|
|
212
|
+
and os.path.isfile(os.path.join(folder, file))]
|
|
215
213
|
|
|
216
214
|
|
|
217
215
|
def metric_preamble(data, dtype=None, rates=None, r_dtype=None, r_norm=False):
|
|
@@ -229,7 +227,8 @@ def metric_preamble(data, dtype=None, rates=None, r_dtype=None, r_norm=False):
|
|
|
229
227
|
|
|
230
228
|
|
|
231
229
|
def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
232
|
-
rates=None, r_dtype=None, r_norm=False,
|
|
230
|
+
rates=None, r_dtype=None, r_norm=False, round_value=True,
|
|
231
|
+
res=1e-6, min_r=7, **kwargs):
|
|
233
232
|
"""
|
|
234
233
|
Calculate a metric from data.
|
|
235
234
|
|
|
@@ -253,12 +252,19 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
253
252
|
Datatype to preprocess the rates over. The default is None.
|
|
254
253
|
r_norm : bool, optional
|
|
255
254
|
Whether to normalize rates. The default is False.
|
|
255
|
+
round_value : bool, optional
|
|
256
|
+
Whether to round the final value, including named metrics.
|
|
257
|
+
Applied once after evaluation. Default is True.
|
|
258
|
+
res : float
|
|
259
|
+
Resolution to round to. Default is 1e-6.
|
|
260
|
+
min_r : int
|
|
261
|
+
Maximum number of digits to round to (see round_float).
|
|
256
262
|
**kwargs : kwargs
|
|
257
|
-
Keyword arguments to method.
|
|
263
|
+
Keyword arguments to method (see round_float).
|
|
258
264
|
|
|
259
265
|
Returns
|
|
260
266
|
-------
|
|
261
|
-
metric:
|
|
267
|
+
metric: np.float64/np.int64
|
|
262
268
|
Metric calculated by method over data.
|
|
263
269
|
|
|
264
270
|
Examples
|
|
@@ -266,7 +272,7 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
266
272
|
>>> calc_metric([1,2,3]) # simple average
|
|
267
273
|
np.float64(2.0)
|
|
268
274
|
>>> calc_metric([1,2,3], rates=[0.1, 0.1, 0.0], method=np.sum) # weighted sum
|
|
269
|
-
np.float64(0.
|
|
275
|
+
np.float64(0.3)
|
|
270
276
|
>>> calc_metric([0, 20, 30], dtype=bool, rates=[0.1, 0.1, 0.1], method=np.sum) # rate of nonzero event
|
|
271
277
|
np.float64(0.2)
|
|
272
278
|
>>> calc_metric([0, 1, 2], "total")
|
|
@@ -276,11 +282,16 @@ def calc_metric(data, method=np.average, args=(), axis=None, dtype=None,
|
|
|
276
282
|
"""
|
|
277
283
|
if isinstance(method, str):
|
|
278
284
|
method = eval("calc_"+method)
|
|
279
|
-
|
|
280
|
-
|
|
285
|
+
# Named helpers call calc_metric again; round only the final result.
|
|
286
|
+
metric = method(data, args=args, axis=axis, dtype=dtype, rates=rates,
|
|
287
|
+
r_dtype=r_dtype, r_norm=r_norm, round_value=False, **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,
|
|
@@ -298,7 +309,8 @@ def calc_metric_ci(data, method=np.average, return_anyway=False, interval=None,
|
|
|
298
309
|
axis : int
|
|
299
310
|
Axis along which to calculate the confidence interval(s). The default is 0.
|
|
300
311
|
**kwargs : kwargs
|
|
301
|
-
Keyword arguments to
|
|
312
|
+
Keyword arguments to the statistic, preprocessing, or scipy.bootstrap.
|
|
313
|
+
Statistic arguments are used for both the point estimate and resamples.
|
|
302
314
|
|
|
303
315
|
Returns
|
|
304
316
|
-------
|
|
@@ -325,20 +337,19 @@ def calc_metric_ci(data, method=np.average, return_anyway=False, interval=None,
|
|
|
325
337
|
bs_kwar['confidence_level'] = interval*0.01
|
|
326
338
|
|
|
327
339
|
vals = metric_preamble(data, **filter_kwargs(metric_preamble, **kwargs))
|
|
328
|
-
|
|
329
|
-
val = vals[axis, 0]
|
|
330
|
-
else:
|
|
331
|
-
val = np.array(vals).flatten()[0]
|
|
340
|
+
val = np.take(vals, [0], axis=axis)
|
|
332
341
|
if "weights" in kwargs and kwargs['weights'] is not None:
|
|
333
342
|
raise Exception("Weights not able to be used w- bootstrap--use rates instead.")
|
|
334
|
-
|
|
343
|
+
statistic = partial(method, **filter_kwargs(method, **kwargs))
|
|
344
|
+
met_val = statistic(vals, axis=axis)
|
|
335
345
|
vals_vary = vals == val
|
|
336
|
-
|
|
346
|
+
# Preserve the existing policy for globally identical data.
|
|
347
|
+
if not np.all(vals == vals.flat[0]):
|
|
337
348
|
if np.any(np.all(vals_vary, axis=axis)):
|
|
338
349
|
# use more robust/basic algorithm if some indices don't vary
|
|
339
|
-
bs = bootstrap([vals],
|
|
350
|
+
bs = bootstrap([vals], statistic, axis=axis, method="basic", **bs_kwar)
|
|
340
351
|
else:
|
|
341
|
-
bs = bootstrap([vals],
|
|
352
|
+
bs = bootstrap([vals], statistic, axis=axis, **bs_kwar)
|
|
342
353
|
return met_val, bs.confidence_interval.low, bs.confidence_interval.high
|
|
343
354
|
elif return_anyway:
|
|
344
355
|
return met_val, met_val, met_val
|
|
@@ -353,7 +364,7 @@ def calc_rate(data, rates=None, weights=None, **kwargs):
|
|
|
353
364
|
Examples
|
|
354
365
|
--------
|
|
355
366
|
>>> calc_rate([0, 10, 0]) # defaults to equal rate
|
|
356
|
-
np.float64(0.
|
|
367
|
+
np.float64(0.333333)
|
|
357
368
|
>>> calc_rate([0, 10, 100], [0.1, 0.1, 0.1]) # provided rates
|
|
358
369
|
np.float64(0.2)
|
|
359
370
|
"""
|
|
@@ -370,7 +381,7 @@ def calc_percent(data, weights=None, rates=None, **kwargs):
|
|
|
370
381
|
Examples
|
|
371
382
|
--------
|
|
372
383
|
>>> calc_percent([0, 10, 0])
|
|
373
|
-
np.float64(0.
|
|
384
|
+
np.float64(0.333333)
|
|
374
385
|
"""
|
|
375
386
|
return calc_metric(data, **{**kwargs, 'dtype': bool})
|
|
376
387
|
|
|
@@ -386,7 +397,7 @@ def calc_total(data, weights=None, **kwargs):
|
|
|
386
397
|
>>> calc_total([0, 10, 100])
|
|
387
398
|
np.int64(2)
|
|
388
399
|
"""
|
|
389
|
-
return calc_metric(data, **{**kwargs, 'method': np.sum, 'dtype': bool})
|
|
400
|
+
return np.int64(calc_metric(data, **{**kwargs, 'method': np.sum, 'dtype': bool}))
|
|
390
401
|
|
|
391
402
|
|
|
392
403
|
def calc_expected(data, rates=None, weights=None, **kwargs):
|
|
@@ -519,8 +530,8 @@ def plot_err_hist(err_hist, ax=None, fig=None, figsize=(6, 4), boundtype='fill',
|
|
|
519
530
|
fig : mpl figure
|
|
520
531
|
ax :mpl, axis
|
|
521
532
|
"""
|
|
522
|
-
fig, ax = setup_plot(fig, ax, figsize)
|
|
523
|
-
ax.plot(err_hist['stat'], **kwargs)
|
|
533
|
+
fig, ax = setup_plot(fig=fig, ax=ax, figsize=figsize)
|
|
534
|
+
ax.plot(err_hist[time], err_hist['stat'], **kwargs)
|
|
524
535
|
if boundtype == 'fill':
|
|
525
536
|
col = ax.lines[-1].get_color()
|
|
526
537
|
ax.fill_between(err_hist[time], err_hist['low'], err_hist['high'],
|
|
@@ -582,7 +593,7 @@ def plot_err_lines(times, lows, highs, ax=None, fig=None, figsize=(6, 4), **kwar
|
|
|
582
593
|
**kwargs : kwargs
|
|
583
594
|
kwargs for the line
|
|
584
595
|
"""
|
|
585
|
-
fig, ax = setup_plot(
|
|
596
|
+
fig, ax = setup_plot(fig=fig, ax=ax, figsize=figsize)
|
|
586
597
|
ax.plot(times, highs, **kwargs)
|
|
587
598
|
ax.plot(times, lows, **kwargs)
|
|
588
599
|
return fig, ax
|
|
@@ -182,6 +182,9 @@ class History(Result):
|
|
|
182
182
|
"""
|
|
183
183
|
Find the values of two histories which are different.
|
|
184
184
|
|
|
185
|
+
Array-valued entries are retained when any element of their difference
|
|
186
|
+
is nonzero; the full difference array is returned.
|
|
187
|
+
|
|
185
188
|
Parameters
|
|
186
189
|
----------
|
|
187
190
|
other : History
|
|
@@ -195,7 +198,7 @@ class History(Result):
|
|
|
195
198
|
"""
|
|
196
199
|
diff = self-other
|
|
197
200
|
different = self.__class__()
|
|
198
|
-
different.data = {k: v for k, v in diff.items() if any(v)}
|
|
201
|
+
different.data = {k: v for k, v in diff.items() if np.any(v)}
|
|
199
202
|
return different
|
|
200
203
|
|
|
201
204
|
def copy(self):
|
|
@@ -360,6 +363,9 @@ class History(Result):
|
|
|
360
363
|
"""
|
|
361
364
|
Get the time a fault is present in the system.
|
|
362
365
|
|
|
366
|
+
Only recorded fault traces are considered. Without recorded faults,
|
|
367
|
+
returns zero for ``total`` and ``nan`` for the position metrics.
|
|
368
|
+
|
|
363
369
|
Parameters
|
|
364
370
|
----------
|
|
365
371
|
metric : 'earliest','latest','total', 'times', optional
|
|
@@ -373,6 +379,8 @@ class History(Result):
|
|
|
373
379
|
|
|
374
380
|
Examples
|
|
375
381
|
--------
|
|
382
|
+
>>> History(time=[0, 1, 2]).get_fault_time()
|
|
383
|
+
nan
|
|
376
384
|
>>> History({'m.faults.fault1': [False, False, False]}).get_fault_time()
|
|
377
385
|
nan
|
|
378
386
|
>>> History({'m.faults.fault1': [False, False, True]}).get_fault_time()
|
|
@@ -383,7 +391,7 @@ class History(Result):
|
|
|
383
391
|
if metric == 'total':
|
|
384
392
|
return np.sum(all_faults_hist >= 1)
|
|
385
393
|
else:
|
|
386
|
-
times = np.where(all_faults_hist >= 1)[0]
|
|
394
|
+
times = np.where(np.atleast_1d(all_faults_hist) >= 1)[0]
|
|
387
395
|
if times.size == 0:
|
|
388
396
|
return np.nan
|
|
389
397
|
elif metric == 'times':
|
|
@@ -809,6 +817,8 @@ class History(Result):
|
|
|
809
817
|
"""
|
|
810
818
|
Get aggregated err_hist of means surrounded by std deviation.
|
|
811
819
|
|
|
820
|
+
Calculate the spread across histories separately at each time sample.
|
|
821
|
+
|
|
812
822
|
Parameters
|
|
813
823
|
----------
|
|
814
824
|
value : str
|
|
@@ -829,7 +839,7 @@ class History(Result):
|
|
|
829
839
|
hist = History()
|
|
830
840
|
hist[time] = self.get_metric(time, axis=0)
|
|
831
841
|
hist['stat'] = self.get_metric(value, np.mean, axis=0)
|
|
832
|
-
std_dev = self.get_metric(value, np.std)
|
|
842
|
+
std_dev = self.get_metric(value, np.std, axis=0)
|
|
833
843
|
hist['high'] = hist['stat']+std_dev/2
|
|
834
844
|
hist['low'] = hist['stat']-std_dev/2
|
|
835
845
|
return hist
|
|
@@ -851,7 +861,8 @@ class History(Result):
|
|
|
851
861
|
ci : float
|
|
852
862
|
Fraction for confidence interval. Default is 0.95.
|
|
853
863
|
max_ind : str/int
|
|
854
|
-
|
|
864
|
+
Exclusive slice endpoint for both timestamps and values. Default is
|
|
865
|
+
'max', which uses the shortest history length.
|
|
855
866
|
|
|
856
867
|
Returns
|
|
857
868
|
-------
|
|
@@ -874,6 +885,7 @@ class History(Result):
|
|
|
874
885
|
hist[time] = self.get_metric(time, axis=0)
|
|
875
886
|
if max_ind == 'max':
|
|
876
887
|
max_ind = min([len(h) for h in self.values()])
|
|
888
|
+
hist[time] = hist[time][:max_ind]
|
|
877
889
|
vals = np.array([*self.get_values(value).values()])[:, :max_ind]
|
|
878
890
|
boot_stats = calc_metric_ci(vals, confidence_level=ci, axis=0, **kwargs)
|
|
879
891
|
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
|
|
@@ -383,9 +388,9 @@ def from_hist(hist, fxn_modephases='all', dt=1.0):
|
|
|
383
388
|
Dictionary of distict phases that the system functions pass through,
|
|
384
389
|
of the form: {'fxn': PhaseMap} where each phase is defined by its
|
|
385
390
|
corresponding mode in the modelhist.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
391
|
+
Repeated phases are numbered mode, mode1, mode2, skipping suffixes that
|
|
392
|
+
would collide with actual mode names or previously generated phase names.
|
|
393
|
+
The modephase mapping groups each mode's intervals for future sampling.
|
|
389
394
|
|
|
390
395
|
Examples
|
|
391
396
|
--------
|
|
@@ -406,6 +411,8 @@ def from_hist(hist, fxn_modephases='all', dt=1.0):
|
|
|
406
411
|
fxn = k[k.index('m')-1]
|
|
407
412
|
if len(modehist) != 0:
|
|
408
413
|
modes = OrderedSet(modehist)
|
|
414
|
+
# Reserve actual mode names before generating repeated-phase suffixes.
|
|
415
|
+
used_phaseids = set(modes)
|
|
409
416
|
modephases = dict.fromkeys(modes)
|
|
410
417
|
phases_unsorted = dict()
|
|
411
418
|
for mode in modes:
|
|
@@ -422,6 +429,10 @@ def from_hist(hist, fxn_modephases='all', dt=1.0):
|
|
|
422
429
|
startind = modeinds[i+1]
|
|
423
430
|
phasenum += 1
|
|
424
431
|
phaseid = mode+str(phasenum)
|
|
432
|
+
while phaseid in used_phaseids:
|
|
433
|
+
phasenum += 1
|
|
434
|
+
phaseid = mode+str(phasenum)
|
|
435
|
+
used_phaseids.add(phaseid)
|
|
425
436
|
phases = dict(sorted(phases_unsorted.items(),
|
|
426
437
|
key=lambda item: item[1][0]))
|
|
427
438
|
if fxn_modephases == 'all' or fxn in fxn_modephases:
|
|
@@ -677,8 +688,7 @@ def join_phasemaps(*phasemaps):
|
|
|
677
688
|
joint_phases = {}
|
|
678
689
|
all_combos = [*itertools.product(*[phasemap.phases for phasemap in phasemaps])]
|
|
679
690
|
for combo in all_combos:
|
|
680
|
-
|
|
681
|
-
intervals = [i for i in phases.values()]
|
|
691
|
+
intervals = [phasemaps[i].phases[c] for i, c in enumerate(combo)]
|
|
682
692
|
joined_interval = find_interval_overlap(*intervals)
|
|
683
693
|
if joined_interval:
|
|
684
694
|
joint_phases[combo] = joined_interval
|