Using Parallel Computing in fmdtools

This notebook will discuss how to use parallel programming in fmdtools, including:

  • how to set up a model for parallelism

  • syntax for using parallelism in simulation functions

  • considerations for optimizing computational performance in a model

Copyright © 2024, United States Government, as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.

The “"Fault Model Design tools - fmdtools version 2"” software is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
[1]:
from ex_pump import *
from fmdtools.sim.sample import FaultDomain, FaultSample
import fmdtools.sim.propagate as propagate
import fmdtools.analyze as an

This notebook uses the pump example (see ex_pump.py) to illustrate the use of parallelism in fmdtools. This is fairly simple model, and thus it should be noted that there may be considerations with more complex models which may not be adequately covered here.

[2]:
mdl = Pump()
[3]:
result, mdlhist = propagate.nominal(mdl, desired_result='graph')
[4]:
fig, ax = result.graph.draw()
../../_images/examples_pump_Parallelism_Tutorial_5_0.png
[5]:
fig, ax = mdlhist.plot_line('flows.ee_1.s.current', 'flows.wat_2.s.flowrate')
../../_images/examples_pump_Parallelism_Tutorial_6_0.png

Model Checks

Before attempting to leverage parallelism in model execution, it can be helpful to check whether a model is compatible with python parallel computing libraries. In order for a model to be parallelized, it must be compatible with pickling–python’s method of data serialization. This is used in parallel programming methods to copy the model from the main process thread to the seperate processes of the pool.

fmdtools has two methods to check whether a model can be pickled, check_pickleability and check_model_pickleability. The main difference between these is that check_pickleability works for all objects (e.g. functions and flows), while check_model_pickleability gives more information for an overall model structure

[6]:
from fmdtools.define.object.base import check_pickleability
from fmdtools.define.architecture.base import check_model_pickleability
[7]:
unpickleable_attributes = check_pickleability(mdl)
The object is pickleable
[8]:
check_model_pickleability(mdl)
FLOWS
ee_1
The object is pickleable
sig_1
The object is pickleable
wat_1
The object is pickleable
wat_2
The object is pickleable
FUNCTIONS
import_ee
ee_out
The object is pickleable
import_water
wat_out
The object is pickleable
import_signal
sig_out
The object is pickleable
move_water
ee_in
sig_in
wat_in
wat_out
The object is pickleable
export_water
wat_in
The object is pickleable
MODEL
The object is pickleable

As you can see, this model is pickleable. However, this may not be the case for all structures if they rely on unpickleable data structures, one common one being iterators like .values().

Using Parallelism in Simulation

Parallelism generally requires using some external parallel processing toolkit. The syntax used by fmdtools methods is compatible with:

  • multiprocessing, python’s default parallel computing library

  • multiprocess, a fork of multiprocessing developed by The UQ Foundation

  • pathos, a broader parallel computing package developed by The UQ Foundation

And any other package that emulates multiprocessing.Pool

[9]:
import multiprocessing as mp
import multiprocess as ms

Parallelism can speed up simulation time when there is a large number of independent simulations to run. The prefered methods for using parallelism are to use a NominalApproach or SampleApproach with the methods:

  • propagate.singlefaults (for all single-fault scenarios in a static model with no approach)

  • propagate.approach (for sampling a set of faults)

  • propagate.nominal_approach (for simulating the model nominally over a set of parameters)

  • propagate.nested_approach (for sampling a set of faults over a set of model parameters)

These methods can be run in parallel by sending them a pool object from one of these modules as the optional pool argument. Further details on setting up and running an approach are provided in docs/Approach Use-Cases.ipynb

[10]:
pool = mp.Pool(4)
fd = FaultDomain(mdl)
fd.add_all()
fs = FaultSample(fd)
fs.add_fault_phases()
endclasses, mdlhists = propagate.fault_sample(mdl, fs, pool=pool)
#an.tabulate.simplefmea(endclasses)
SCENARIOS COMPLETE: 100%|██████████| 24/24 [00:02<00:00,  8.36it/s]
[11]:
pool
[11]:
<multiprocessing.pool.Pool state=TERMINATE pool_size=4>

Sometimes, it helps to “warm up” the pool. See, for example, how much longer per-second iterations take for the above compared to below:

[12]:
pool = mp.Pool(4)
endclasses, mdlhists = propagate.single_faults(mdl, pool=pool)
#an.tabulate.simplefmea(endclasses)
SCENARIOS COMPLETE: 100%|██████████| 8/8 [00:02<00:00,  3.07it/s]

It can also be helpful to verify that the results of parallel simulation and normal serial execution are the same:

[13]:
pool = mp.Pool(4)
endclasses_par, mdlhists = propagate.single_faults(mdl, pool=pool, close_pool=False)
#tab_par = an.tabulate.simplefmea(endclasses_par)
endclasses, mdlhists = propagate.single_faults(mdl)
#tab = an.tabulate.simplefmea(endclasses)
#tab - tab_par
SCENARIOS COMPLETE: 100%|██████████| 8/8 [00:02<00:00,  2.96it/s]
SCENARIOS COMPLETE: 100%|██████████| 8/8 [00:00<00:00, 15.05it/s]
[14]:
# pool = mp.Pool(4)
endclasses_par, mdlhists = propagate.fault_sample(mdl, fs, pool=pool)
#tab_par = an.tabulate.simplefmea(endclasses_par)
endclasses, mdlhists = propagate.fault_sample(mdl, fs)
#tab = an.tabulate.simplefmea(endclasses)
#tab - tab_par
pool
SCENARIOS COMPLETE: 100%|██████████| 24/24 [00:00<00:00, 50.47it/s]
SCENARIOS COMPLETE: 100%|██████████| 24/24 [00:01<00:00, 15.40it/s]
[14]:
<multiprocessing.pool.Pool state=TERMINATE pool_size=4>

While fmdtools built-in methods are the easiest way to leverage parallelism, it can also be used with custom arguments/methods to meet the needs of simulation. However, (on Windows) these methods need to be defined in an external module with an “if name==’main’:” statement, otherwise execution will hang from spawning new processes. This has to do with how multiprocessing works in windows.

To show how parellism can be leveraged manually for a desired use-case, below the model is run over the blockage fault mode at time t=1 with a different model parameter (delayed failure behavior), as defined in the parallelism_methods.py module in this folder.

[15]:
from parallelism_methods import delay_test
[16]:
results = delay_test()
results
[16]:
[endclass.rate:                     1e-05
 endclass.cost:        20125.000000000007
 endclass.expected_cost: 20125.000000000007,
 endclass.rate:                     1e-05
 endclass.cost:        20102.500000000007
 endclass.expected_cost: 20102.500000000007,
 endclass.rate:                     1e-05
 endclass.cost:        20080.000000000007
 endclass.expected_cost: 20080.000000000007,
 endclass.rate:                     1e-05
 endclass.cost:        20057.500000000007
 endclass.expected_cost: 20057.500000000007,
 endclass.rate:                     1e-05
 endclass.cost:        20035.000000000007
 endclass.expected_cost: 20035.000000000007,
 endclass.rate:                     1e-05
 endclass.cost:        15023.750000000005
 endclass.expected_cost: 15023.750000000005,
 endclass.rate:                     1e-05
 endclass.cost:        15023.750000000005
 endclass.expected_cost: 15023.750000000005,
 endclass.rate:                     1e-05
 endclass.cost:        15023.750000000005
 endclass.expected_cost: 15023.750000000005,
 endclass.rate:                     1e-05
 endclass.cost:        15023.750000000005
 endclass.expected_cost: 15023.750000000005,
 endclass.rate:                     1e-05
 endclass.cost:        15023.750000000005
 endclass.expected_cost: 15023.750000000005]

In this method, the model is run many times over a given fault with different delay parameters. It should be noted that this approach is not especially efficient, since the nominal scenario is simulated at each call of propagate.one_fault(). It is thus preferred to use the appropriate fault/parameter sampling approaches and propagate methods, since these methods only run the nominal simulation once for fault scenarios and can also use staged execution (copying the model at fault time for fault scenarios) to reduce the cost of each simulation.

Performance Comparison

Parallelism is often used in computation to speed up up a set of independent simulations. Conventionally, one might say it leads to a reduced computational cost of t/n, where t was the original time of the set of processes, and n is the number of cores.

However, this computational performance increase is dependent on the implementation. In Python, there is some overhead from from communicating data structures in and out of parallel threads which can become a significant consideration when the data structures are large. Additionally, different Pools can execute more or less efficiently. Below these are each compared.

[17]:
import matplotlib.pyplot as plt
from parallelism_methods import compare_pools, instantiate_pools, terminate_pools
[18]:
cores=4
pools = instantiate_pools(cores)

Below is the baseline comparison, where the the following parameters characterize the sampling approach:

  • single faults: only the single-fault scenarios are considered

  • 3 points per phase: an evenly-spaced quadrature is sampled at each phase of operation (start, on, end) for the model

  • staged: the model is copied at each point in time where faults is injected during the model time to save computation

  • track: the entire model history is returned for each simulation

This is typical for a small model like this where the per-model expense is low.

[19]:
mdl=Pump(track='all')
fs = FaultSample(fd)
fs.add_fault_phases(args = (3,))

pools = instantiate_pools(5)
_ = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[20]:
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
exectimes_baseline = exectimes
[21]:
fig = plt.figure(figsize=(9, 3),)
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center')
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Baseline Performance - Some faults, Staged, Normal Simulation, Full Model History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
../../_images/examples_pump_Parallelism_Tutorial_33_0.png

As shown, in this situation, both the multiprocessing and threadpool pools give computational performance increases.

Comparison: No Histories

In the below comparison, the same simulation approach is run, except without tracking a history of model states through the simulation.

[22]:
mdl=Pump(track='none')
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[23]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.5, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Many Faults, Staged, Normal Simulation, No Model History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[23]:
<matplotlib.legend.Legend at 0x1b94d180750>
../../_images/examples_pump_Parallelism_Tutorial_37_1.png

As shown, in this situation, the overall simulation expense decreases, even in the serial execution case.

Additionally, the case for using a parallel processing pool increases somewhat. This is because passing the model history back to the main process is nearly comparable in time to simulation itself.

As a result, removing it saves a large amount of computational time when using parallel processing.

Comparison: Many Faults

In the below comparison, many faults are injected in the system to increase the number of scenarios (ostensibly making the case better for parallelism)

[24]:
fs_many = FaultSample(fd)
fs_many.add_fault_phases(args = (7,))
mdl=Pump(track='all')
exectimes = compare_pools(mdl, fs_many, pools, staged=True, verbose=False)
[25]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.8, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Many Faults, Staged, Normal Simulation, Full Model History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[25]:
<matplotlib.legend.Legend at 0x1b94d2b9050>
../../_images/examples_pump_Parallelism_Tutorial_41_1.png

As shown, increasing the number of joint-fault scenarios increases computational costs significantly–as would be expected.

In this situation, multiprocessing performs comparatively better, but only slightly–instead of taking 1/4 the time, it only takes about 1/2 the time.

Comparison: Long simulation

It may be of interest to simulate how the comparative performance changes for longer simulations. In this comparison, the simulation time is extended tenfold.

[26]:
mdl=Pump(sp=dict(times=(0,20, 500)), track='all')
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[27]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.8, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Normal Faults, Staged, Long Simulation, Full Model History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[27]:
<matplotlib.legend.Legend at 0x1b94b02d2d0>
../../_images/examples_pump_Parallelism_Tutorial_45_1.png

As shown, the simulation time does increase significantly–about tenfold. In terms of comparative performance, pools other than multiprocessing now become competitive, though multiprocessing is still the fastest overall.

This shows the main case for using parallesism–speeding up long simulations. Short simulations unfortunately require a significant amount of overhead due to copying in and out of the individual thread and we thus see less of a case for them there.

Comparison: Long Simulation No Tracking

Finally, it may be interesting to see how performance is affected in long simulations when there is no tracking. This is because in these simulations, there should be very little overhead from creating the respective data structures, even when there is a long simulation. This comparison is shown below.

[28]:
mdl=Pump(sp=dict(times=(0,20, 500)), track='none')
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[29]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.8, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Normal Faults, Staged, Long Simulation, No Model History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[29]:
<matplotlib.legend.Legend at 0x1b94d41f2d0>
../../_images/examples_pump_Parallelism_Tutorial_49_1.png

As shown, removing the tracking makes the long simulations much take less time than the short simulation!

Comparison: Long Simulation Only Necessary Tracking

In practice, it can be necessary to track some states over time. Here we perform the same comparison using the ‘valstates’ option, which only tracks states which have been defined in the model to be necessary to track (using ‘valparams’)

[30]:
mdl=Pump(sp=dict(times=(0,20, 500))) # see default track for Pump
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[31]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.8, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Normal Faults, Staged, Long Simulation, Only Necessary History")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[31]:
<matplotlib.legend.Legend at 0x1b94d75ce10>
../../_images/examples_pump_Parallelism_Tutorial_53_1.png

As shown, only tracking a few variables results in similar computational time no tracking.

This is because a major computational performance limitation in this model is not necessarily the model simulation itself, but the generation, update, and passing of the history. So it is often best to only track necessary parameters when possible, rather than the entire model history.

Comparison: Lower Tracking Time Resolution

Finally, the number of recorded timesteps can be lowered to lower computational costs while still returning all relevant variables.

[32]:
mdl=Pump(sp=dict(times=(0,20, 500), track_times=("interval", 5)), track='all')
exectimes = compare_pools(mdl, fs, pools, staged=True, verbose=False)
[33]:
fig = plt.figure(figsize=(9, 3),)
width = 0.8
plt.bar(range(len(exectimes)), list(exectimes.values()), align='center', color="blue", label="comparison")
plt.bar(range(len(exectimes_baseline)), list(exectimes_baseline.values()), align='center', color="gray", alpha=0.8, label="baseline")
plt.xticks(range(len(exectimes)), list(exectimes.keys()))
plt.title("Computational Performance - Many Faults, Staged, Normal Simulation, Lower Time Resolution")
plt.ylabel("Computational Time (s)")
plt.grid(axis='y')
plt.legend()
[33]:
<matplotlib.legend.Legend at 0x1b94d4f8f90>
../../_images/examples_pump_Parallelism_Tutorial_57_1.png

As shown, while lowering time resolution could theoretically lower computational time, it does not significantly change much in this example.

[34]:
terminate_pools(pools)

Comparison Conclusions:

Parallelism can the improve computational performance of a given resilience simulation approach. However, this improvement is dependent on the parameters of the simulation. Generally, the official python multiprocessing module seems consistently give the best performance improvement over a single-process execution, although this can change depending on the underlying model and modelling approach. There are additionally reasons you might choose other pools– multiprocess pools may enable more data structures in the model because they extend what can be communicated in and out of threads.

In general, one of the major considerations for optimization compuational time is not just the simulation of the model, but the size of the returned data structures. Minimizing the size of the returned data structures can reduce computational time both by reducing the time of an individual simulation and by reducing the parallelism overhead from copying these data structures in and out of parallel threads. However, it is important to recognize that for resilience assessment, one often needs a history of model states (or, at least, states of interest) to properly quantify the dynamic costs (i.e., Cf(t)dt). Indeed, in this model, only repair costs were able to be used in the comparison of non-tracked states, because the other dynamic costs required a history of their corresponding flows. Changing the number and size of tracked model states can influence the computational time, but only to a point–while one would expect lowering time-fidelity to have a significant effect, it does not because the overhead is less to do with filling the underlying data structures as it has to do with instantiating and returning them–a far more effective method is to only return the functions/flows which are needed by the model.

Further Computational Cost Reduction via Profiling

While parallelism and staged execution are helpful and relatively easy-to-implement methods of computational cost reduction, it can be helpful (especially for more complex models) to see what aspects of the model are taking the most computational time.

While staged execution was not explored here, it can make a difference when faults are to be injected near the end of the simulation by making it unnecessary to simulate up to the fault time. However, it is less helpful when model instantiation/copy time is a significant fraction of simulation time.

Python’s builtin cProfile package can ge used to see the relative computational times of different functions/processes.

[35]:
import cProfile
[36]:
mdl=Pump(sp=dict(track='all'))
prof = cProfile.run('propagate.nominal(mdl)', sort='tottime')
         153548 function calls (149238 primitive calls) in 0.104 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     3890    0.016    0.000    0.041    0.000 base.py:490(get_roles_as_dict)
     5394    0.008    0.000    0.009    0.000 base.py:465(<listcomp>)
     5394    0.006    0.000    0.018    0.000 base.py:462(get_roles)
3834/2032    0.005    0.000    0.033    0.000 base.py:689(<listcomp>)
     3834    0.005    0.000    0.052    0.000 base.py:673(find_mutables)
     3834    0.004    0.000    0.007    0.000 base.py:675(<listcomp>)
     9284    0.004    0.000    0.004    0.000 base.py:453(get_default_roletypes)
3834/2032    0.004    0.000    0.067    0.000 base.py:678(return_mutables)
       56    0.003    0.000    0.083    0.001 function.py:722(prop_static)
  910/620    0.003    0.000    0.006    0.000 base.py:410(get_faults)
     3890    0.003    0.000    0.003    0.000 base.py:508(<dictcomp>)
    16952    0.002    0.000    0.002    0.000 {built-in method builtins.getattr}
     4810    0.002    0.000    0.002    0.000 base.py:469(get_flex_role_objs)
     7212    0.002    0.000    0.003    0.000 inspect.py:300(ismethod)
       50    0.002    0.000    0.003    0.000 base.py:259(<listcomp>)
     3890    0.002    0.000    0.002    0.000 base.py:495(<listcomp>)
     3890    0.002    0.000    0.002    0.000 base.py:501(<listcomp>)
     1124    0.002    0.000    0.002    0.000 time.py:110(return_mutables)
    11490    0.002    0.000    0.002    0.000 {built-in method builtins.hasattr}
      562    0.002    0.000    0.012    0.000 function.py:129(__call__)
       72    0.002    0.000    0.002    0.000 {built-in method builtins.dir}
    12129    0.001    0.000    0.001    0.000 {built-in method builtins.isinstance}
  560/224    0.001    0.000    0.002    0.000 base.py:54(get_var)
       56    0.001    0.000    0.003    0.000 history.py:205(log)
     3162    0.001    0.000    0.001    0.000 base.py:409(return_mutables)
     9134    0.001    0.000    0.001    0.000 {method 'startswith' of 'str' objects}
     1148    0.001    0.000    0.001    0.000 copy.py:66(copy)
      618    0.001    0.000    0.007    0.000 base.py:404(set_sub_faults)
      900    0.001    0.000    0.001    0.000 mode.py:297(has_fault)
     1124    0.001    0.000    0.002    0.000 mode.py:220(return_mutables)
       22    0.001    0.000    0.001    0.000 base.py:389(<listcomp>)
      113    0.001    0.000    0.003    0.000 ex_pump.py:423(static_behavior)
      562    0.000    0.000    0.002    0.000 function.py:115(prop_arch_behaviors)
       40    0.000    0.000    0.006    0.000 base.py:269(init_roles)
  259/231    0.000    0.000    0.001    0.000 copy.py:128(deepcopy)
     4986    0.000    0.000    0.000    0.000 {method 'values' of 'dict' objects}
      226    0.000    0.000    0.001    0.000 base.py:267(set_field)
      113    0.000    0.000    0.002    0.000 base.py:230(assign)
     3162    0.000    0.000    0.000    0.000 {built-in method recordclass._dataobject.astuple}
       22    0.000    0.000    0.001    0.000 inspect.py:2331(_signature_from_function)
      113    0.000    0.000    0.000    0.000 base.py:169(get_field_dict)
        1    0.000    0.000    0.091    0.091 propagate.py:1051(prop_one_scen)
     1350    0.000    0.000    0.000    0.000 time.py:111(<genexpr>)
      300    0.000    0.000    0.000    0.000 __init__.py:180(add)
       18    0.000    0.000    0.002    0.000 parameter.py:62(__init__)
      113    0.000    0.000    0.001    0.000 ex_pump.py:237(static_behavior)
     2151    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
    44/22    0.000    0.000    0.001    0.000 inspect.py:2435(_signature_from_callable)
       56    0.000    0.000    0.087    0.002 function.py:682(propagate)
       90    0.000    0.000    0.000    0.000 inspect.py:2669(__init__)
       44    0.000    0.000    0.000    0.000 inspect.py:2955(__init__)
       18    0.000    0.000    0.000    0.000 base.py:125(set_arg_type)
       18    0.000    0.000    0.000    0.000 parameter.py:136(check_immutable)
      113    0.000    0.000    0.000    0.000 ex_pump.py:414(indicate_over_pressure)
     1249    0.000    0.000    0.000    0.000 {method 'copy' of 'set' objects}
      112    0.000    0.000    0.000    0.000 ex_pump.py:270(static_behavior)
    42/32    0.000    0.000    0.001    0.000 result.py:575(flatten)
       33    0.000    0.000    0.000    0.000 {method 'round' of 'numpy.ndarray' objects}
       18    0.000    0.000    0.009    0.001 base.py:135(add_flex_role_obj)
      112    0.000    0.000    0.000    0.000 ex_pump.py:317(static_behavior)
      900    0.000    0.000    0.000    0.000 {method 'intersection' of 'set' objects}
     1252    0.000    0.000    0.000    0.000 {method 'items' of 'dict' objects}
       18    0.000    0.000    0.000    0.000 inspect.py:3215(__str__)
       14    0.000    0.000    0.000    0.000 base.py:90(find_any_phase_overlap)
      390    0.000    0.000    0.000    0.000 abc.py:117(__instancecheck__)
       60    0.000    0.000    0.000    0.000 _collections_abc.py:717(__ior__)
1694/1684    0.000    0.000    0.000    0.000 {built-in method builtins.len}
       56    0.000    0.000    0.003    0.000 base.py:226(log_hist)
      919    0.000    0.000    0.000    0.000 {built-in method builtins.any}
       10    0.000    0.000    0.007    0.001 base.py:497(__init__)
       56    0.000    0.000    0.001    0.000 base.py:560(set_vars)
       30    0.000    0.000    0.001    0.000 base.py:633(create_hist)
      580    0.000    0.000    0.000    0.000 {method 'update' of 'dict' objects}
       78    0.000    0.000    0.000    0.000 result.py:167(__init__)
       12    0.000    0.000    0.000    0.000 time.py:117(set_timestep)
      280    0.000    0.000    0.000    0.000 base.py:260(is_known_mutable)
      113    0.000    0.000    0.000    0.000 base.py:217(<dictcomp>)
       78    0.000    0.000    0.000    0.000 __init__.py:1111(__init__)
      118    0.000    0.000    0.000    0.000 parameter.py:108(check_lim)
      390    0.000    0.000    0.000    0.000 {built-in method _abc._abc_instancecheck}
      113    0.000    0.000    0.000    0.000 ex_pump.py:390(set_faults)
       33    0.000    0.000    0.000    0.000 base.py:336(gen_timerange)
    22/20    0.000    0.000    0.007    0.000 base.py:155(__init__)
       64    0.000    0.000    0.000    0.000 common.py:48(get_sub_include)
       18    0.000    0.000    0.000    0.000 parameter.py:157(check_type)
       22    0.000    0.000    0.000    0.000 inspect.py:2037(_signature_bound_method)
       79    0.000    0.000    0.000    0.000 _collections_abc.py:941(update)
    32/30    0.000    0.000    0.006    0.000 base.py:238(init_roletypes)
      112    0.000    0.000    0.000    0.000 ex_pump.py:296(static_behavior)
      344    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}
       12    0.000    0.000    0.006    0.000 base.py:195(__init__)
       50    0.000    0.000    0.004    0.000 base.py:258(find_roletype_initiators)
      293    0.000    0.000    0.000    0.000 {method 'update' of 'set' objects}
       56    0.000    0.000    0.000    0.000 inspect.py:2756(__str__)
        1    0.000    0.000    0.104    0.104 {built-in method builtins.exec}
      338    0.000    0.000    0.000    0.000 {built-in method builtins.setattr}
      466    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
       90    0.000    0.000    0.000    0.000 enum.py:688(__call__)
      168    0.000    0.000    0.000    0.000 __init__.py:304(__iter__)
      226    0.000    0.000    0.000    0.000 {built-in method builtins.min}
       14    0.000    0.000    0.002    0.000 base.py:79(__init__)
       62    0.000    0.000    0.000    0.000 __init__.py:65(__init__)
      113    0.000    0.000    0.000    0.000 ex_pump.py:220(set_faults)
       56    0.000    0.000    0.001    0.000 __init__.py:130(copy)
       78    0.000    0.000    0.000    0.000 result.py:347(__setattr__)
       10    0.000    0.000    0.008    0.001 base.py:226(add_sim)
      112    0.000    0.000    0.000    0.000 inspect.py:3002(<genexpr>)
      105    0.000    0.000    0.000    0.000 result.py:324(items)
       18    0.000    0.000    0.001    0.000 parameter.py:180(check_pickle)
      496    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
        6    0.000    0.000    0.000    0.000 result.py:400(all_with)
       18    0.000    0.000    0.008    0.000 base.py:980(init_obj)
       56    0.000    0.000    0.000    0.000 base.py:150(get_hist_ind)
       33    0.000    0.000    0.000    0.000 {built-in method numpy.arange}
       26    0.000    0.000    0.000    0.000 numerictypes.py:357(issubdtype)
       28    0.000    0.000    0.000    0.000 fromnumeric.py:865(sort)
       12    0.000    0.000    0.000    0.000 base.py:98(get_true_fields)
       10    0.000    0.000    0.008    0.001 function.py:543(add_fxn)
       22    0.000    0.000    0.000    0.000 inspect.py:167(get_annotations)
       33    0.000    0.000    0.000    0.000 base.py:104(get_timerange)
       12    0.000    0.000    0.000    0.000 time.py:92(__init__)
      118    0.000    0.000    0.000    0.000 base.py:173(set_arg_as_type)
       22    0.000    0.000    0.001    0.000 base.py:387(init_indicators)
       22    0.000    0.000    0.000    0.000 inspect.py:735(unwrap)
       12    0.000    0.000    0.000    0.000 mode.py:199(__init__)
       33    0.000    0.000    0.000    0.000 fromnumeric.py:53(_wrapfunc)
      313    0.000    0.000    0.000    0.000 {built-in method builtins.id}
       31    0.000    0.000    0.000    0.000 base.py:119(get_histrange)
       56    0.000    0.000    0.000    0.000 ex_pump.py:518(indicate_on)
        4    0.000    0.000    0.001    0.000 parameter.py:176(copy_with_vals)
       28    0.000    0.000    0.000    0.000 {built-in method numpy.asanyarray}
       26    0.000    0.000    0.000    0.000 base.py:213(is_numeric)
       22    0.000    0.000    0.000    0.000 base.py:213(init_track)
      112    0.000    0.000    0.000    0.000 __init__.py:74(__len__)
      245    0.000    0.000    0.000    0.000 copy.py:182(_deepcopy_atomic)
       33    0.000    0.000    0.000    0.000 fromnumeric.py:3269(round)
       56    0.000    0.000    0.000    0.000 ex_pump.py:499(indicate_finished)
       63    0.000    0.000    0.000    0.000 __init__.py:1138(__contains__)
        8    0.000    0.000    0.000    0.000 history.py:132(init_att)
      224    0.000    0.000    0.000    0.000 inspect.py:2734(kind)
       42    0.000    0.000    0.000    0.000 result.py:112(check_include_errors)
       28    0.000    0.000    0.000    0.000 {method 'copy' of 'numpy.ndarray' objects}
       22    0.000    0.000    0.000    0.000 inspect.py:3023(replace)
       10    0.000    0.000    0.007    0.001 function.py:77(__init__)
       22    0.000    0.000    0.001    0.000 inspect.py:3007(from_callable)
        2    0.000    0.000    0.000    0.000 graph.py:968(add_edges_from)
       52    0.000    0.000    0.000    0.000 numerictypes.py:283(issubclass_)
       56    0.000    0.000    0.000    0.000 propagate.py:1023(check_end_condition)
        1    0.000    0.000    0.000    0.000 ex_pump.py:522(find_classification)
        1    0.000    0.000    0.103    0.103 propagate.py:501(nom_helper)
       52    0.000    0.000    0.000    0.000 base.py:51(check_role)
       10    0.000    0.000    0.001    0.000 base.py:531(create_arch_kwargs)
        2    0.000    0.000    0.011    0.006 base.py:84(__init__)
       26    0.000    0.000    0.000    0.000 {built-in method numpy.array}
       12    0.000    0.000    0.001    0.000 base.py:212(init_hist)
     10/4    0.000    0.000    0.000    0.000 copy.py:227(_deepcopy_dict)
        6    0.000    0.000    0.000    0.000 base.py:421(init_indicator_hist)
        1    0.000    0.000    0.000    0.000 {method 'reduce' of 'numpy.ufunc' objects}
       90    0.000    0.000    0.000    0.000 enum.py:1095(__new__)
       22    0.000    0.000    0.001    0.000 inspect.py:3261(signature)
        8    0.000    0.000    0.000    0.000 result.py:336(__getattr__)
       28    0.000    0.000    0.000    0.000 {method 'sort' of 'numpy.ndarray' objects}
      158    0.000    0.000    0.000    0.000 inspect.py:2722(name)
       10    0.000    0.000    0.000    0.000 base.py:550(check_flows)
        2    0.000    0.000    0.009    0.005 ex_pump.py:471(init_architecture)
       14    0.000    0.000    0.000    0.000 base.py:95(<listcomp>)
        4    0.000    0.000    0.000    0.000 graph.py:566(add_nodes_from)
        2    0.000    0.000    0.001    0.000 base.py:264(new_params)
      190    0.000    0.000    0.000    0.000 {built-in method builtins.iter}
       52    0.000    0.000    0.000    0.000 __init__.py:1118(__len__)
       12    0.000    0.000    0.000    0.000 function.py:767(<listcomp>)
       10    0.000    0.000    0.000    0.000 base.py:590(is_dynamic)
       12    0.000    0.000    0.000    0.000 base.py:105(<listcomp>)
       10    0.000    0.000    0.000    0.000 function.py:98(update_seed)
       14    0.000    0.000    0.000    0.000 base.py:92(<dictcomp>)
        2    0.000    0.000    0.000    0.000 function.py:597(build)
       38    0.000    0.000    0.000    0.000 {method 'format' of 'str' objects}
      130    0.000    0.000    0.000    0.000 {built-in method builtins.issubclass}
        2    0.000    0.000    0.000    0.000 function.py:609(construct_graph)
        1    0.000    0.000    0.103    0.103 propagate.py:208(nominal)
      113    0.000    0.000    0.000    0.000 {method 'clear' of 'set' objects}
       55    0.000    0.000    0.000    0.000 __init__.py:1128(__setitem__)
       10    0.000    0.000    0.000    0.000 base.py:570(<listcomp>)
       14    0.000    0.000    0.000    0.000 {built-in method recordclass._dataobject.asdict}
      113    0.000    0.000    0.000    0.000 {method 'copy' of 'list' objects}
      112    0.000    0.000    0.000    0.000 {method 'index' of 'list' objects}
        1    0.000    0.000    0.000    0.000 propagate.py:1151(get_result)
       14    0.000    0.000    0.000    0.000 copy.py:243(_keep_alive)
        8    0.000    0.000    0.002    0.000 base.py:186(add_flow)
       32    0.000    0.000    0.000    0.000 base.py:207(check_slots)
       90    0.000    0.000    0.000    0.000 {method '__contains__' of 'frozenset' objects}
       44    0.000    0.000    0.000    0.000 inspect.py:378(isfunction)
        2    0.000    0.000    0.000    0.000 copyreg.py:113(_slotnames)
        2    0.000    0.000    0.000    0.000 function.py:605(<listcomp>)
       90    0.000    0.000    0.000    0.000 {method 'isidentifier' of 'str' objects}
        4    0.000    0.000    0.000    0.000 base.py:361(create_hist)
        2    0.000    0.000    0.000    0.000 base.py:257(build)
        1    0.000    0.000    0.103    0.103 <string>:1(<module>)
        2    0.000    0.000    0.012    0.006 base.py:298(new)
       20    0.000    0.000    0.000    0.000 graph.py:1318(neighbors)
        2    0.000    0.000    0.000    0.000 functools.py:981(__get__)
       10    0.000    0.000    0.000    0.000 base.py:512(<dictcomp>)
        2    0.000    0.000    0.000    0.000 {method '__reduce_ex__' of 'object' objects}
       14    0.000    0.000    0.000    0.000 base.py:94(<listcomp>)
        8    0.000    0.000    0.000    0.000 function.py:606(<listcomp>)
       42    0.000    0.000    0.000    0.000 result.py:121(check_include_error)
        2    0.000    0.000    0.011    0.006 function.py:510(__init__)
        1    0.000    0.000    0.000    0.000 function.py:621(calc_repaircost)
       20    0.000    0.000    0.000    0.000 reportviews.py:529(__iter__)
        1    0.000    0.000    0.000    0.000 history.py:271(cut)
       12    0.000    0.000    0.000    0.000 base.py:208(<dictcomp>)
        4    0.000    0.000    0.000    0.000 base.py:348(init_hist_att)
       10    0.000    0.000    0.000    0.000 base.py:538(<dictcomp>)
       10    0.000    0.000    0.000    0.000 base.py:279(get_flows)
       10    0.000    0.000    0.000    0.000 __init__.py:201(update)
        8    0.000    0.000    0.001    0.000 base.py:92(create_hist)
       40    0.000    0.000    0.000    0.000 {method 'values' of 'mappingproxy' objects}
        2    0.000    0.000    0.000    0.000 graph.py:332(__init__)
        2    0.000    0.000    0.000    0.000 function.py:600(<listcomp>)
        2    0.000    0.000    0.000    0.000 copy.py:259(_reconstruct)
       40    0.000    0.000    0.000    0.000 __init__.py:165(__contains__)
       10    0.000    0.000    0.000    0.000 base.py:283(<dictcomp>)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:71(_wrapreduction)
       10    0.000    0.000    0.000    0.000 base.py:565(<listcomp>)
       14    0.000    0.000    0.000    0.000 base.py:413(asdict)
        2    0.000    0.000    0.000    0.000 function.py:602(<listcomp>)
       18    0.000    0.000    0.000    0.000 base.py:262(get_full_name)
        8    0.000    0.000    0.000    0.000 result.py:93(get_dict_attr)
       10    0.000    0.000    0.000    0.000 base.py:584(is_static)
        4    0.000    0.000    0.000    0.000 base.py:272(<dictcomp>)
       44    0.000    0.000    0.000    0.000 inspect.py:3015(parameters)
        2    0.000    0.000    0.000    0.000 isolate.py:42(isolates)
       33    0.000    0.000    0.000    0.000 fromnumeric.py:3265(_round_dispatcher)
        4    0.000    0.000    0.000    0.000 state.py:345(init_hist_att)
       66    0.000    0.000    0.000    0.000 {built-in method builtins.callable}
        2    0.000    0.000    0.000    0.000 <class 'networkx.utils.decorators.argmap'> compilation 4:1(argmap_isolates_1)
        2    0.000    0.000    0.000    0.000 isolate.py:85(<genexpr>)
        2    0.000    0.000    0.000    0.000 {built-in method builtins.sum}
       18    0.000    0.000    0.000    0.000 inspect.py:292(isclass)
        1    0.000    0.000    0.000    0.000 base.py:130(get_shift)
        8    0.000    0.000    0.000    0.000 {built-in method numpy.empty}
       22    0.000    0.000    0.000    0.000 base.py:191(create_name)
        2    0.000    0.000    0.000    0.000 base.py:114(init_flexible_roles)
        2    0.000    0.000    0.000    0.000 reportviews.py:419(__init__)
       28    0.000    0.000    0.000    0.000 fromnumeric.py:861(_sort_dispatcher)
        2    0.000    0.000    0.000    0.000 backends.py:627(__call__)
        2    0.000    0.000    0.000    0.000 copy.py:201(_deepcopy_list)
        2    0.000    0.000    0.000    0.000 base.py:401(<dictcomp>)
        6    0.000    0.000    0.000    0.000 base.py:654(<listcomp>)
        2    0.000    0.000    0.000    0.000 timer.py:61(__init__)
        4    0.000    0.000    0.000    0.000 base.py:69(get_track)
        2    0.000    0.000    0.000    0.000 base.py:453(return_faultmodes)
        6    0.000    0.000    0.000    0.000 misc.py:595(_clear_cache)
        7    0.000    0.000    0.000    0.000 propagate.py:121(<genexpr>)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:2836(min)
        2    0.000    0.000    0.000    0.000 graph.py:1484(degree)
        7    0.000    0.000    0.000    0.000 __init__.py:1121(__getitem__)
       16    0.000    0.000    0.000    0.000 base.py:65(check_role)
        2    0.000    0.000    0.000    0.000 base.py:392(get_indicators)
        1    0.000    0.000    0.000    0.000 scenario.py:136(__init__)
       20    0.000    0.000    0.000    0.000 {built-in method builtins.repr}
       22    0.000    0.000    0.000    0.000 {built-in method sys.getrecursionlimit}
        4    0.000    0.000    0.000    0.000 result.py:320(keys)
       18    0.000    0.000    0.000    0.000 inspect.py:3019(return_annotation)
        1    0.000    0.000    0.000    0.000 propagate.py:879(check_overwrite)
        2    0.000    0.000    0.000    0.000 graph.py:59(__set__)
       10    0.000    0.000    0.000    0.000 base.py:593(<listcomp>)
        1    0.000    0.000    0.000    0.000 base.py:220(init_time_hist)
        4    0.000    0.000    0.000    0.000 copy.py:264(<genexpr>)
       10    0.000    0.000    0.000    0.000 base.py:232(update_seed)
        2    0.000    0.000    0.000    0.000 function.py:617(<listcomp>)
       10    0.000    0.000    0.000    0.000 base.py:527(init_block)
       12    0.000    0.000    0.000    0.000 inspect.py:2726(default)
       12    0.000    0.000    0.000    0.000 copy.py:107(_copy_immutable)
        1    0.000    0.000    0.000    0.000 propagate.py:242(save_helper)
        2    0.000    0.000    0.000    0.000 graph.py:37(__set__)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:72(<dictcomp>)
        2    0.000    0.000    0.000    0.000 base.py:295(update_seed)
        1    0.000    0.000    0.000    0.000 propagate.py:119(unpack_sim_kwargs)
        2    0.000    0.000    0.000    0.000 {built-in method fromkeys}
        4    0.000    0.000    0.000    0.000 {method 'endswith' of 'str' objects}
        2    0.000    0.000    0.000    0.000 {method 'get' of 'mappingproxy' objects}
        2    0.000    0.000    0.000    0.000 __init__.py:1134(__iter__)
        2    0.000    0.000    0.000    0.000 parameter.py:105(keys)
        4    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
        2    0.000    0.000    0.000    0.000 reportviews.py:426(__call__)
        1    0.000    0.000    0.000    0.000 propagate.py:1167(<listcomp>)
        1    0.000    0.000    0.000    0.000 {method 'pop' of 'dict' objects}
        1    0.000    0.000    0.000    0.000 propagate.py:1191(<listcomp>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.RLock' objects}
        2    0.000    0.000    0.000    0.000 base.py:455(<dictcomp>)
        1    0.000    0.000    0.000    0.000 scenario.py:138(<dictcomp>)
        1    0.000    0.000    0.000    0.000 function.py:643(<listcomp>)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:2831(_min_dispatcher)


[37]:
prof = cProfile.run('propagate.fault_sample(mdl, fs)', sort='tottime')
SCENARIOS COMPLETE: 100%|██████████| 72/72 [00:06<00:00, 10.87it/s]
         10942521 function calls (10630059 primitive calls) in 6.728 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   284498    1.061    0.000    2.708    0.000 base.py:490(get_roles_as_dict)
   392880    0.530    0.000    0.624    0.000 base.py:465(<listcomp>)
   392880    0.413    0.000    1.190    0.000 base.py:462(get_roles)
280338/148582    0.383    0.000    2.270    0.000 base.py:689(<listcomp>)
   280338    0.334    0.000    3.431    0.000 base.py:673(find_mutables)
   280338    0.265    0.000    0.439    0.000 base.py:675(<listcomp>)
   677378    0.257    0.000    0.257    0.000 base.py:453(get_default_roletypes)
280338/148582    0.251    0.000    4.472    0.000 base.py:678(return_mutables)
     4088    0.212    0.000    5.538    0.001 function.py:722(prop_static)
66049/45239    0.193    0.000    0.590    0.000 base.py:410(get_faults)
   284498    0.176    0.000    0.220    0.000 base.py:508(<dictcomp>)
   350917    0.157    0.000    0.168    0.000 base.py:469(get_flex_role_objs)
  1214358    0.155    0.000    0.155    0.000 {built-in method builtins.getattr}
   284498    0.130    0.000    0.130    0.000 base.py:501(<listcomp>)
   284498    0.130    0.000    0.130    0.000 base.py:495(<listcomp>)
    82154    0.127    0.000    0.153    0.000 time.py:110(return_mutables)
   527310    0.127    0.000    0.174    0.000 inspect.py:300(ismethod)
    41077    0.119    0.000    0.805    0.000 function.py:129(__call__)
   831538    0.108    0.000    0.108    0.000 {built-in method builtins.hasattr}
     5566    0.097    0.000    0.097    0.000 {built-in method builtins.dir}
   856316    0.082    0.000    0.096    0.000 {built-in method builtins.isinstance}
40880/16352    0.076    0.000    0.106    0.000 base.py:54(get_var)
     4088    0.068    0.000    0.217    0.000 history.py:205(log)
     1850    0.065    0.000    0.083    0.000 base.py:259(<listcomp>)
    97552    0.060    0.000    0.080    0.000 copy.py:66(copy)
   231246    0.058    0.000    0.083    0.000 base.py:409(return_mutables)
     2902    0.057    0.000    0.077    0.000 base.py:431(<dictcomp>)
    45165    0.049    0.000    0.634    0.000 base.py:404(set_sub_faults)
   582574    0.048    0.000    0.048    0.000 {method 'startswith' of 'str' objects}
    82154    0.046    0.000    0.113    0.000 mode.py:220(return_mutables)
    63249    0.046    0.000    0.063    0.000 mode.py:297(has_fault)
     8267    0.040    0.000    0.185    0.000 ex_pump.py:423(static_behavior)
   363610    0.028    0.000    0.028    0.000 {method 'values' of 'dict' objects}
    41077    0.028    0.000    0.123    0.000 function.py:115(prop_arch_behaviors)
    16534    0.027    0.000    0.062    0.000 base.py:267(set_field)
   231246    0.025    0.000    0.025    0.000 {built-in method recordclass._dataobject.astuple}
17794/16758    0.025    0.000    0.035    0.000 copy.py:128(deepcopy)
     8267    0.024    0.000    0.116    0.000 base.py:230(assign)
      814    0.022    0.000    0.029    0.000 base.py:389(<listcomp>)
      315    0.019    0.000    0.019    0.000 {method 'acquire' of '_thread.lock' objects}
       73    0.019    0.000    6.298    0.086 propagate.py:1051(prop_one_scen)
    98688    0.019    0.000    0.019    0.000 time.py:111(<genexpr>)
     8267    0.018    0.000    0.029    0.000 base.py:169(get_field_dict)
    21180    0.016    0.000    0.019    0.000 __init__.py:180(add)
     2902    0.016    0.000    0.184    0.000 mode.py:223(get_fault)
     1480    0.015    0.000    0.191    0.000 base.py:269(init_roles)
     8264    0.015    0.000    0.034    0.000 ex_pump.py:237(static_behavior)
   151272    0.014    0.000    0.014    0.000 {method 'get' of 'dict' objects}
     4088    0.014    0.000    6.017    0.001 function.py:682(propagate)
     3346    0.013    0.000    0.033    0.000 base.py:98(get_true_fields)
    90865    0.011    0.000    0.011    0.000 {method 'copy' of 'set' objects}
     8185    0.010    0.000    0.025    0.000 ex_pump.py:270(static_behavior)
    63249    0.009    0.000    0.009    0.000 {method 'intersection' of 'set' objects}
     8176    0.009    0.000    0.017    0.000 ex_pump.py:317(static_behavior)
      814    0.009    0.000    0.026    0.000 inspect.py:2331(_signature_from_function)
    85990    0.009    0.000    0.009    0.000 {method 'items' of 'dict' objects}
125970/125239    0.008    0.000    0.009    0.000 {built-in method builtins.len}
     4236    0.008    0.000    0.029    0.000 _collections_abc.py:717(__ior__)
     4088    0.008    0.000    0.078    0.000 base.py:560(set_vars)
    63916    0.008    0.000    0.008    0.000 {built-in method builtins.any}
     4088    0.008    0.000    0.227    0.000 base.py:226(log_hist)
    39859    0.008    0.000    0.008    0.000 {method 'update' of 'dict' objects}
    25758    0.008    0.000    0.013    0.000 abc.py:117(__instancecheck__)
    20440    0.007    0.000    0.007    0.000 base.py:260(is_known_mutable)
      666    0.007    0.000    0.074    0.000 parameter.py:62(__init__)
     8267    0.007    0.000    0.008    0.000 base.py:217(<dictcomp>)
     3346    0.007    0.000    0.019    0.000 base.py:105(<listcomp>)
     2902    0.006    0.000    0.036    0.000 mode.py:64(__init__)
1776/1187    0.006    0.000    0.022    0.000 result.py:575(flatten)
 1628/814    0.006    0.000    0.042    0.000 inspect.py:2435(_signature_from_callable)
     8267    0.006    0.000    0.010    0.000 ex_pump.py:390(set_faults)
      666    0.006    0.000    0.008    0.000 parameter.py:136(check_immutable)
     1628    0.006    0.000    0.009    0.000 inspect.py:2955(__init__)
    25758    0.006    0.000    0.006    0.000 {built-in method _abc._abc_instancecheck}
     3330    0.006    0.000    0.009    0.000 inspect.py:2669(__init__)
     2902    0.005    0.000    0.130    0.000 base.py:428(get_pref_attrs)
     1329    0.005    0.000    0.005    0.000 {method 'round' of 'numpy.ndarray' objects}
      666    0.005    0.000    0.007    0.000 base.py:125(set_arg_type)
     8185    0.005    0.000    0.014    0.000 ex_pump.py:296(static_behavior)
    25256    0.005    0.000    0.005    0.000 {method 'split' of 'str' objects}
      666    0.005    0.000    0.301    0.000 base.py:135(add_flex_role_obj)
    21506    0.004    0.000    0.004    0.000 {method 'update' of 'set' objects}
     3251    0.004    0.000    0.016    0.000 result.py:167(__init__)
      518    0.004    0.000    0.011    0.000 base.py:90(find_any_phase_overlap)
    12264    0.004    0.000    0.005    0.000 __init__.py:304(__iter__)
    33370    0.004    0.000    0.004    0.000 {method 'join' of 'str' objects}
      370    0.004    0.000    0.231    0.001 base.py:497(__init__)
      666    0.004    0.000    0.007    0.000 inspect.py:3215(__str__)
     8264    0.004    0.000    0.004    0.000 ex_pump.py:220(set_faults)
     4310    0.004    0.000    0.033    0.000 __init__.py:65(__init__)
    15123    0.004    0.000    0.004    0.000 {built-in method builtins.min}
     4088    0.004    0.000    0.036    0.000 __init__.py:130(copy)
     1110    0.004    0.000    0.037    0.000 base.py:633(create_hist)
     3251    0.003    0.000    0.012    0.000 __init__.py:1111(__init__)
      444    0.003    0.000    0.003    0.000 time.py:117(set_timestep)
     8267    0.003    0.000    0.003    0.000 ex_pump.py:414(indicate_over_pressure)
     6377    0.003    0.000    0.004    0.000 result.py:324(items)
  814/740    0.003    0.000    0.216    0.000 base.py:155(__init__)
     3324    0.003    0.000    0.007    0.000 _collections_abc.py:941(update)
     4366    0.003    0.000    0.005    0.000 parameter.py:108(check_lim)
      438    0.003    0.000    0.007    0.000 result.py:400(all_with)
    20678    0.003    0.000    0.003    0.000 {built-in method builtins.setattr}
     1329    0.003    0.000    0.003    0.000 {built-in method numpy.arange}
      666    0.003    0.000    0.003    0.000 parameter.py:157(check_type)
1184/1110    0.002    0.000    0.193    0.000 base.py:238(init_roletypes)
      814    0.002    0.000    0.008    0.000 inspect.py:2037(_signature_bound_method)
    28432    0.002    0.000    0.002    0.000 {method 'append' of 'list' objects}
     2584    0.002    0.000    0.182    0.000 mode.py:263(<dictcomp>)
     1850    0.002    0.000    0.119    0.000 base.py:258(find_roletype_initiators)
     4088    0.002    0.000    0.002    0.000 ex_pump.py:518(indicate_on)
     1329    0.002    0.000    0.013    0.000 base.py:336(gen_timerange)
     8176    0.002    0.000    0.003    0.000 __init__.py:74(__len__)
     4088    0.002    0.000    0.002    0.000 ex_pump.py:499(indicate_finished)
     4599    0.002    0.000    0.002    0.000 __init__.py:1138(__contains__)
     2587    0.002    0.000    0.002    0.000 common.py:48(get_sub_include)
     2584    0.002    0.000    0.184    0.000 mode.py:259(get_faults)
     3251    0.002    0.000    0.002    0.000 result.py:347(__setattr__)
     3330    0.002    0.000    0.003    0.000 enum.py:688(__call__)
     2072    0.002    0.000    0.003    0.000 inspect.py:2756(__str__)
      444    0.002    0.000    0.190    0.000 base.py:195(__init__)
    19800    0.002    0.000    0.002    0.000 {built-in method builtins.id}
    17274    0.002    0.000    0.002    0.000 copy.py:182(_deepcopy_atomic)
     4088    0.002    0.000    0.002    0.000 base.py:150(get_hist_ind)
      119    0.002    0.000    0.002    0.000 socket.py:621(send)
     1779    0.002    0.000    0.004    0.000 numerictypes.py:357(issubdtype)
     4088    0.002    0.000    0.002    0.000 propagate.py:1023(check_end_condition)
      518    0.002    0.000    0.068    0.000 base.py:79(__init__)
      370    0.002    0.000    0.249    0.001 base.py:226(add_sim)
       73    0.002    0.000    0.024    0.000 ex_pump.py:522(find_classification)
     4144    0.002    0.000    0.002    0.000 inspect.py:3002(<genexpr>)
     1770    0.002    0.000    0.006    0.000 base.py:213(is_numeric)
     1036    0.002    0.000    0.002    0.000 {method 'copy' of 'numpy.ndarray' objects}
      666    0.002    0.000    0.264    0.000 base.py:980(init_obj)
      584    0.002    0.000    0.009    0.000 result.py:336(__getattr__)
      666    0.002    0.000    0.044    0.000 parameter.py:180(check_pickle)
        1    0.001    0.001    6.625    6.625 propagate.py:779(scenlist_helper)
       73    0.001    0.000    0.001    0.000 {method 'reduce' of 'numpy.ufunc' objects}
    14954    0.001    0.000    0.001    0.000 copy.py:107(_copy_immutable)
      873    0.001    0.000    0.002    0.000 function.py:767(<listcomp>)
    13579    0.001    0.000    0.001    0.000 {built-in method builtins.iter}
     3558    0.001    0.000    0.002    0.000 numerictypes.py:283(issubclass_)
     1036    0.001    0.000    0.005    0.000 fromnumeric.py:865(sort)
      370    0.001    0.000    0.252    0.001 function.py:543(add_fxn)
     1036    0.001    0.000    0.001    0.000 {method 'sort' of 'numpy.ndarray' objects}
     4366    0.001    0.000    0.001    0.000 base.py:173(set_arg_as_type)
       73    0.001    0.000    0.027    0.000 propagate.py:1151(get_result)
      814    0.001    0.000    0.002    0.000 inspect.py:167(get_annotations)
     8267    0.001    0.000    0.001    0.000 {method 'clear' of 'set' objects}
     1776    0.001    0.000    0.002    0.000 result.py:112(check_include_errors)
      814    0.001    0.000    0.001    0.000 inspect.py:735(unwrap)
      814    0.001    0.000    0.001    0.000 base.py:213(init_track)
     1183    0.001    0.000    0.013    0.000 base.py:119(get_histrange)
     8176    0.001    0.000    0.001    0.000 {method 'index' of 'list' objects}
     1036    0.001    0.000    0.001    0.000 {built-in method numpy.asanyarray}
      814    0.001    0.000    0.046    0.000 base.py:387(init_indicators)
      444    0.001    0.000    0.009    0.000 time.py:92(__init__)
     1329    0.001    0.000    0.008    0.000 fromnumeric.py:3269(round)
       38    0.001    0.000    0.002    0.000 std.py:464(format_meter)
     1329    0.001    0.000    0.014    0.000 base.py:104(get_timerange)
     8267    0.001    0.000    0.001    0.000 {method 'copy' of 'list' objects}
      444    0.001    0.000    0.004    0.000 mode.py:199(__init__)
     1329    0.001    0.000    0.007    0.000 fromnumeric.py:53(_wrapfunc)
      370    0.001    0.000    0.232    0.001 function.py:77(__init__)
      814    0.001    0.000    0.043    0.000 inspect.py:3007(from_callable)
      148    0.001    0.000    0.023    0.000 parameter.py:176(copy_with_vals)
     3531    0.001    0.000    0.001    0.000 __init__.py:1128(__setitem__)
     1770    0.001    0.000    0.001    0.000 {built-in method numpy.array}
   144/72    0.001    0.000    0.009    0.000 base.py:366(inject_faults)
       74    0.001    0.000    0.001    0.000 graph.py:968(add_edges_from)
      296    0.001    0.000    0.002    0.000 history.py:132(init_att)
      814    0.001    0.000    0.043    0.000 inspect.py:3261(signature)
      814    0.001    0.000    0.005    0.000 inspect.py:3023(replace)
     2357    0.001    0.000    0.001    0.000 __init__.py:1118(__len__)
     7261    0.001    0.000    0.001    0.000 {built-in method builtins.issubclass}
     8288    0.001    0.000    0.001    0.000 inspect.py:2734(kind)
     1924    0.001    0.000    0.001    0.000 base.py:51(check_role)
      444    0.001    0.000    0.020    0.000 base.py:212(init_hist)
      370    0.001    0.000    0.026    0.000 base.py:531(create_arch_kwargs)
       74    0.001    0.000    0.362    0.005 base.py:84(__init__)
      184    0.001    0.000    0.002    0.000 {built-in method builtins.sum}
      370    0.001    0.000    0.002    0.000 base.py:550(check_flows)
     3330    0.001    0.000    0.001    0.000 enum.py:1095(__new__)
     1482    0.001    0.000    0.001    0.000 {method 'format' of 'str' objects}
      222    0.001    0.000    0.003    0.000 base.py:421(init_indicator_hist)
  372/150    0.001    0.000    0.004    0.000 copy.py:227(_deepcopy_dict)
      148    0.001    0.000    0.001    0.000 graph.py:566(add_nodes_from)
     1169    0.001    0.000    0.001    0.000 graph.py:1318(neighbors)
       73    0.001    0.000    0.013    0.000 function.py:621(calc_repaircost)
     5846    0.001    0.000    0.001    0.000 inspect.py:2722(name)
       74    0.001    0.000    0.001    0.000 history.py:271(cut)
      518    0.001    0.000    0.001    0.000 base.py:95(<listcomp>)
       74    0.001    0.000    0.309    0.004 ex_pump.py:471(init_architecture)
       74    0.001    0.000    0.005    0.000 function.py:609(construct_graph)
       74    0.001    0.000    0.015    0.000 function.py:597(build)
     2571    0.001    0.000    0.001    0.000 utils.py:375(<genexpr>)
      370    0.001    0.000    0.002    0.000 function.py:98(update_seed)
      518    0.001    0.000    0.001    0.000 base.py:92(<dictcomp>)
      370    0.001    0.000    0.002    0.000 base.py:590(is_dynamic)
      518    0.001    0.000    0.001    0.000 {built-in method recordclass._dataobject.asdict}
       74    0.001    0.000    0.028    0.000 base.py:264(new_params)
      370    0.001    0.000    0.001    0.000 base.py:570(<listcomp>)
      296    0.001    0.000    0.056    0.000 base.py:186(add_flow)
     1184    0.001    0.000    0.001    0.000 base.py:207(check_slots)
       40    0.001    0.000    0.003    0.000 iostream.py:655(write)
      584    0.000    0.000    0.001    0.000 result.py:93(get_dict_attr)
     2338    0.000    0.000    0.000    0.000 __init__.py:165(__contains__)
     1628    0.000    0.000    0.001    0.000 inspect.py:378(isfunction)
      148    0.000    0.000    0.003    0.000 base.py:361(create_hist)
       72    0.000    0.000    6.213    0.086 propagate.py:828(exec_scen)
       36    0.000    0.000    0.029    0.001 std.py:1198(update)
       74    0.000    0.000    0.001    0.000 function.py:605(<listcomp>)
      520    0.000    0.000    0.000    0.000 copy.py:243(_keep_alive)
       73    0.000    0.000    0.002    0.000 fromnumeric.py:71(_wrapreduction)
      119    0.000    0.000    0.003    0.000 iostream.py:259(schedule)
     3330    0.000    0.000    0.000    0.000 {method '__contains__' of 'frozenset' objects}
     1776    0.000    0.000    0.000    0.000 result.py:121(check_include_error)
     3330    0.000    0.000    0.000    0.000 {method 'isidentifier' of 'str' objects}
       74    0.000    0.000    0.005    0.000 base.py:257(build)
      370    0.000    0.000    0.000    0.000 base.py:512(<dictcomp>)
      810    0.000    0.000    0.000    0.000 base.py:262(get_full_name)
      370    0.000    0.000    0.001    0.000 base.py:279(get_flows)
       74    0.000    0.000    0.391    0.005 base.py:298(new)
       40    0.000    0.000    0.020    0.000 threading.py:611(wait)
       74    0.000    0.000    0.362    0.005 function.py:510(__init__)
      518    0.000    0.000    0.000    0.000 base.py:94(<listcomp>)
      370    0.000    0.000    0.000    0.000 base.py:538(<dictcomp>)
      296    0.000    0.000    0.019    0.000 base.py:92(create_hist)
      296    0.000    0.000    0.000    0.000 function.py:606(<listcomp>)
       72    0.000    0.000    0.002    0.000 base.py:529(get_vars)
      740    0.000    0.000    0.000    0.000 reportviews.py:529(__iter__)
      148    0.000    0.000    0.001    0.000 base.py:348(init_hist_att)
       74    0.000    0.000    0.000    0.000 graph.py:332(__init__)
       74    0.000    0.000    0.001    0.000 functools.py:981(__get__)
       74    0.000    0.000    0.001    0.000 {method '__reduce_ex__' of 'object' objects}
       40    0.000    0.000    0.022    0.001 iostream.py:592(flush)
      370    0.000    0.000    0.001    0.000 __init__.py:201(update)
      444    0.000    0.000    0.000    0.000 base.py:208(<dictcomp>)
      217    0.000    0.000    0.000    0.000 std.py:231(__call__)
     1480    0.000    0.000    0.000    0.000 {method 'values' of 'mappingproxy' objects}
       74    0.000    0.000    0.001    0.000 copy.py:259(_reconstruct)
       74    0.000    0.000    0.001    0.000 function.py:600(<listcomp>)
      370    0.000    0.000    0.000    0.000 base.py:283(<dictcomp>)
      656    0.000    0.000    0.000    0.000 __init__.py:1121(__getitem__)
       79    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
       75    0.000    0.000    0.000    0.000 std.py:400(format_interval)
       74    0.000    0.000    0.001    0.000 isolate.py:42(isolates)
      148    0.000    0.000    0.000    0.000 base.py:272(<dictcomp>)
       39    0.000    0.000    0.019    0.000 threading.py:295(wait)
      370    0.000    0.000    0.000    0.000 base.py:565(<listcomp>)
       72    0.000    0.000    0.000    0.000 base.py:606(<listcomp>)
       74    0.000    0.000    0.002    0.000 function.py:602(<listcomp>)
      148    0.000    0.000    0.001    0.000 state.py:345(init_hist_att)
       73    0.000    0.000    0.029    0.000 std.py:1160(__iter__)
     1329    0.000    0.000    0.000    0.000 fromnumeric.py:3265(_round_dispatcher)
      666    0.000    0.000    0.000    0.000 inspect.py:292(isclass)
      518    0.000    0.000    0.001    0.000 base.py:413(asdict)
       76    0.000    0.000    0.000    0.000 utils.py:273(_is_ascii)
      370    0.000    0.000    0.000    0.000 base.py:584(is_static)
       72    0.000    0.000    0.006    0.000 base.py:395(set_fault_disturbances)
     2533    0.000    0.000    0.000    0.000 {built-in method unicodedata.east_asian_width}
      296    0.000    0.000    0.000    0.000 {built-in method numpy.empty}
      159    0.000    0.000    0.000    0.000 threading.py:1192(is_alive)
       74    0.000    0.000    0.001    0.000 <class 'networkx.utils.decorators.argmap'> compilation 4:1(argmap_isolates_1)
       40    0.000    0.000    0.000    0.000 threading.py:243(__init__)
       38    0.000    0.000    0.000    0.000 std.py:1446(format_dict)
       73    0.000    0.000    0.002    0.000 fromnumeric.py:2836(min)
       72    0.000    0.000    0.000    0.000 base.py:600(_get_role_call)
      511    0.000    0.000    0.000    0.000 propagate.py:121(<genexpr>)
       78    0.000    0.000    0.024    0.000 utils.py:194(inner)
       74    0.000    0.000    0.001    0.000 isolate.py:85(<genexpr>)
       74    0.000    0.000    0.000    0.000 copyreg.py:113(_slotnames)
     2442    0.000    0.000    0.000    0.000 {built-in method builtins.callable}
       74    0.000    0.000    0.000    0.000 reportviews.py:419(__init__)
     1628    0.000    0.000    0.000    0.000 inspect.py:3015(parameters)
       41    0.000    0.000    0.000    0.000 {method 'acquire' of '_multiprocessing.SemLock' objects}
       72    0.000    0.000    0.006    0.000 mode.py:419(get_fault_disturbances)
      814    0.000    0.000    0.000    0.000 base.py:191(create_name)
       96    0.000    0.000    0.000    0.000 mode.py:337(add_fault)
       38    0.000    0.000    0.003    0.000 std.py:1150(__str__)
       73    0.000    0.000    0.001    0.000 base.py:130(get_shift)
       74    0.000    0.000    0.010    0.000 base.py:453(return_faultmodes)
       38    0.000    0.000    0.028    0.001 std.py:1464(display)
       37    0.000    0.000    0.028    0.001 std.py:1325(refresh)
       74    0.000    0.000    0.001    0.000 backends.py:627(__call__)
      119    0.000    0.000    0.000    0.000 iostream.py:138(_event_pipe)
     1036    0.000    0.000    0.000    0.000 fromnumeric.py:861(_sort_dispatcher)
      293    0.000    0.000    0.000    0.000 result.py:320(keys)
       74    0.000    0.000    0.000    0.000 base.py:114(init_flexible_roles)
       74    0.000    0.000    0.000    0.000 propagate.py:242(save_helper)
      148    0.000    0.000    0.000    0.000 base.py:69(get_track)
       38    0.000    0.000    0.000    0.000 std.py:186(__format__)
       73    0.000    0.000    0.001    0.000 base.py:220(init_time_hist)
      222    0.000    0.000    0.000    0.000 base.py:654(<listcomp>)
       74    0.000    0.000    0.004    0.000 timer.py:61(__init__)
      592    0.000    0.000    0.000    0.000 base.py:65(check_role)
       38    0.000    0.000    0.025    0.001 std.py:457(print_status)
       74    0.000    0.000    0.000    0.000 graph.py:1484(degree)
       41    0.000    0.000    0.000    0.000 std.py:102(acquire)
       74    0.000    0.000    0.000    0.000 copy.py:201(_deepcopy_list)
       38    0.000    0.000    0.024    0.001 std.py:451(fp_write)
       74    0.000    0.000    0.000    0.000 base.py:455(<dictcomp>)
      222    0.000    0.000    0.000    0.000 misc.py:595(_clear_cache)
      159    0.000    0.000    0.000    0.000 threading.py:1125(_wait_for_tstate_lock)
       41    0.000    0.000    0.000    0.000 std.py:106(release)
       74    0.000    0.000    0.000    0.000 base.py:401(<dictcomp>)
      814    0.000    0.000    0.000    0.000 {built-in method sys.getrecursionlimit}
       40    0.000    0.000    0.002    0.000 iostream.py:577(_schedule_flush)
        1    0.000    0.000    6.728    6.728 <string>:1(<module>)
       74    0.000    0.000    0.000    0.000 base.py:392(get_indicators)
       73    0.000    0.000    0.000    0.000 function.py:643(<listcomp>)
       74    0.000    0.000    0.000    0.000 graph.py:59(__set__)
      740    0.000    0.000    0.000    0.000 {built-in method builtins.repr}
       40    0.000    0.000    0.000    0.000 threading.py:562(__init__)
       73    0.000    0.000    0.000    0.000 propagate.py:119(unpack_sim_kwargs)
       38    0.000    0.000    0.000    0.000 std.py:153(__init__)
      146    0.000    0.000    0.000    0.000 __init__.py:1134(__iter__)
       38    0.000    0.000    0.001    0.000 utils.py:378(disp_len)
       73    0.000    0.000    0.000    0.000 fromnumeric.py:72(<dictcomp>)
      666    0.000    0.000    0.000    0.000 inspect.py:3019(return_annotation)
      198    0.000    0.000    0.000    0.000 time.py:104(__getattr__)
      370    0.000    0.000    0.000    0.000 base.py:593(<listcomp>)
       37    0.000    0.000    0.000    0.000 {built-in method now}
      144    0.000    0.000    0.000    0.000 scenario.py:49(get)
       60    0.000    0.000    0.000    0.000 timer.py:83(inc)
      292    0.000    0.000    0.000    0.000 {method 'endswith' of 'str' objects}
      370    0.000    0.000    0.000    0.000 base.py:232(update_seed)
       38    0.000    0.000    0.000    0.000 {method 'sub' of 're.Pattern' objects}
       40    0.000    0.000    0.000    0.000 iostream.py:505(parent_header)
       41    0.000    0.000    0.000    0.000 {method 'release' of '_multiprocessing.SemLock' objects}
      148    0.000    0.000    0.001    0.000 copy.py:264(<genexpr>)
       40    0.000    0.000    0.000    0.000 iostream.py:550(_is_master_process)
      370    0.000    0.000    0.000    0.000 base.py:527(init_block)
      115    0.000    0.000    0.000    0.000 threading.py:1168(ident)
       74    0.000    0.000    0.001    0.000 function.py:617(<listcomp>)
      147    0.000    0.000    0.000    0.000 {built-in method fromkeys}
       38    0.000    0.000    0.001    0.000 utils.py:374(_text_width)
       40    0.000    0.000    0.000    0.000 threading.py:1453(current_thread)
       73    0.000    0.000    0.000    0.000 propagate.py:1167(<listcomp>)
       10    0.000    0.000    0.000    0.000 ipkernel.py:775(_clean_thread_parent_frames)
       74    0.000    0.000    0.000    0.000 base.py:295(update_seed)
      798    0.000    0.000    0.000    0.000 {built-in method builtins.ord}
       74    0.000    0.000    0.000    0.000 graph.py:37(__set__)
      188    0.000    0.000    0.000    0.000 {built-in method builtins.divmod}
       39    0.000    0.000    0.000    0.000 threading.py:283(_acquire_restore)
      444    0.000    0.000    0.000    0.000 inspect.py:2726(default)
        1    0.000    0.000    6.727    6.727 propagate.py:590(fault_sample)
      313    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
      160    0.000    0.000    0.000    0.000 threading.py:575(is_set)
       77    0.000    0.000    0.000    0.000 {method 'pop' of 'dict' objects}
        1    0.000    0.000    6.728    6.728 {built-in method builtins.exec}
       41    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.RLock' objects}
      147    0.000    0.000    0.000    0.000 {built-in method time.time}
       40    0.000    0.000    0.000    0.000 threading.py:274(__exit__)
       73    0.000    0.000    0.000    0.000 propagate.py:1191(<listcomp>)
        5    0.000    0.000    0.000    0.000 ipkernel.py:790(<setcomp>)
       74    0.000    0.000    0.000    0.000 reportviews.py:426(__call__)
        1    0.000    0.000    0.000    0.000 __init__.py:48(create_string_buffer)
        1    0.000    0.000    0.001    0.001 std.py:952(__init__)
      119    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.RLock' objects}
       74    0.000    0.000    0.000    0.000 parameter.py:105(keys)
       74    0.000    0.000    0.000    0.000 {method 'get' of 'mappingproxy' objects}
       40    0.000    0.000    0.000    0.000 {built-in method nt.getpid}
        1    0.000    0.000    0.000    0.000 utils.py:297(_screen_shape_windows)
       38    0.000    0.000    0.000    0.000 utils.py:108(__init__)
       40    0.000    0.000    0.000    0.000 threading.py:271(__enter__)
       39    0.000    0.000    0.000    0.000 threading.py:286(_is_owned)
      158    0.000    0.000    0.000    0.000 {method 'append' of 'collections.deque' objects}
        5    0.000    0.000    0.000    0.000 threading.py:1501(enumerate)
        1    0.000    0.000    0.097    0.097 propagate.py:501(nom_helper)
       39    0.000    0.000    0.000    0.000 threading.py:280(_release_save)
       38    0.000    0.000    0.000    0.000 std.py:167(colour)
       38    0.000    0.000    0.000    0.000 utils.py:112(__format__)
       38    0.000    0.000    0.000    0.000 {built-in method builtins.max}
       40    0.000    0.000    0.000    0.000 {method 'write' of '_io.StringIO' objects}
       40    0.000    0.000    0.000    0.000 {built-in method builtins.abs}
       40    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
       73    0.000    0.000    0.000    0.000 fromnumeric.py:2831(_min_dispatcher)
       41    0.000    0.000    0.000    0.000 {method 'release' of '_thread.RLock' objects}
        1    0.000    0.000    0.000    0.000 result.py:639(get_memory)
       40    0.000    0.000    0.000    0.000 {method 'get' of '_contextvars.ContextVar' objects}
        1    0.000    0.000    0.000    0.000 std.py:663(__new__)
        1    0.000    0.000    0.001    0.001 std.py:438(status_printer)
        2    0.000    0.000    0.001    0.000 std.py:1265(close)
       38    0.000    0.000    0.000    0.000 std.py:163(colour)
       40    0.000    0.000    0.000    0.000 {method '__enter__' of '_thread.lock' objects}
        3    0.000    0.000    0.000    0.000 _weakrefset.py:63(__iter__)
        1    0.000    0.000    0.000    0.000 std.py:686(_decr_instances)
       40    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.lock' objects}
        1    0.000    0.000    0.000    0.000 propagate.py:708(process_nominal)
        1    0.000    0.000    0.000    0.000 std.py:679(_get_free_pos)
        1    0.000    0.000    0.000    0.000 propagate.py:170(<dictcomp>)
       39    0.000    0.000    0.000    0.000 {method 'release' of '_thread.lock' objects}
        1    0.000    0.000    0.000    0.000 utils.py:213(__init__)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:53(_commit_removals)
        1    0.000    0.000    0.000    0.000 propagate.py:168(pack_run_kwargs)
        1    0.000    0.000    0.000    0.000 _weakrefset.py:85(add)
        1    0.000    0.000    0.000    0.000 functools.py:393(__get__)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:27(__exit__)
        4    0.000    0.000    0.000    0.000 std.py:110(__enter__)
        1    0.000    0.000    0.000    0.000 {built-in method fromtimestamp}
        2    0.000    0.000    0.000    0.000 std.py:1286(fp_write)
        4    0.000    0.000    0.000    0.000 std.py:113(__exit__)
        1    0.000    0.000    0.000    0.000 scenario.py:136(__init__)
        1    0.000    0.000    0.000    0.000 _weakrefset.py:110(remove)
        5    0.000    0.000    0.000    0.000 propagate.py:203(<genexpr>)
        1    0.000    0.000    0.000    0.000 utils.py:266(_supports_unicode)
        3    0.000    0.000    0.000    0.000 {method 'remove' of 'set' objects}
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1207(_handle_fromlist)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:21(__enter__)
        2    0.000    0.000    0.000    0.000 utils.py:187(disable_on_exception)
        1    0.000    0.000    0.000    0.000 sample.py:812(scenarios)
        1    0.000    0.000    0.000    0.000 _monitor.py:94(report)
        1    0.000    0.000    0.000    0.000 sample.py:808(times)
        3    0.000    0.000    0.000    0.000 utils.py:152(wrapper_setattr)
        4    0.000    0.000    0.000    0.000 utils.py:222(__eq__)
        1    0.000    0.000    0.000    0.000 utils.py:125(__eq__)
        1    0.000    0.000    0.000    0.000 {method 'encode' of 'str' objects}
        3    0.000    0.000    0.000    0.000 std.py:226(__init__)
        3    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}
        1    0.000    0.000    0.000    0.000 utils.py:156(__init__)
        1    0.000    0.000    0.000    0.000 utils.py:252(_is_utf)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:17(__init__)
        2    0.000    0.000    0.000    0.000 std.py:1157(__hash__)
        1    0.000    0.000    0.000    0.000 propagate.py:201(unpack_mult_kwargs)
        1    0.000    0.000    0.000    0.000 std.py:682(<setcomp>)
        2    0.000    0.000    0.000    0.000 std.py:1153(_comparable)
        1    0.000    0.000    0.000    0.000 propagate.py:879(check_overwrite)
        1    0.000    0.000    0.000    0.000 std.py:1147(__del__)
        1    0.000    0.000    0.000    0.000 std.py:760(get_lock)
        1    0.000    0.000    0.000    0.000 utils.py:282(_screen_shape_wrapper)
        1    0.000    0.000    0.000    0.000 {method 'difference' of 'set' objects}
        1    0.000    0.000    0.000    0.000 tz.py:74(utcoffset)
        1    0.000    0.000    0.000    0.000 propagate.py:815(close_pool)
        1    0.000    0.000    0.000    0.000 utils.py:139(__getattr__)
        2    0.000    0.000    0.000    0.000 {method 'pop' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {built-in method __new__ of type object at 0x00007FFE5984C4C0}
        2    0.000    0.000    0.000    0.000 {built-in method _weakref.proxy}
        1    0.000    0.000    0.000    0.000 scenario.py:138(<dictcomp>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {built-in method sys.audit}
        1    0.000    0.000    0.000    0.000 std.py:1301(<lambda>)


[38]:
prof = cProfile.run('propagate.fault_sample(mdl, fs)', sort='cumtime')
SCENARIOS COMPLETE: 100%|██████████| 72/72 [00:06<00:00, 10.92it/s]
         10942532 function calls (10630070 primitive calls) in 6.693 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    6.693    6.693 {built-in method builtins.exec}
        1    0.000    0.000    6.693    6.693 <string>:1(<module>)
        1    0.000    0.000    6.693    6.693 propagate.py:590(fault_sample)
        1    0.001    0.001    6.595    6.595 propagate.py:779(scenlist_helper)
       73    0.019    0.000    6.266    0.086 propagate.py:1051(prop_one_scen)
       72    0.000    0.000    6.184    0.086 propagate.py:828(exec_scen)
     4088    0.014    0.000    5.986    0.001 function.py:682(propagate)
     4088    0.214    0.000    5.511    0.001 function.py:722(prop_static)
280338/148582    0.249    0.000    4.449    0.000 base.py:678(return_mutables)
   280338    0.330    0.000    3.417    0.000 base.py:673(find_mutables)
   284498    1.057    0.000    2.702    0.000 base.py:490(get_roles_as_dict)
280338/148582    0.376    0.000    2.258    0.000 base.py:689(<listcomp>)
   392880    0.409    0.000    1.182    0.000 base.py:462(get_roles)
    41077    0.120    0.000    0.799    0.000 function.py:129(__call__)
    45165    0.048    0.000    0.626    0.000 base.py:404(set_sub_faults)
   392880    0.528    0.000    0.621    0.000 base.py:465(<listcomp>)
66049/45239    0.190    0.000    0.584    0.000 base.py:410(get_faults)
   280338    0.259    0.000    0.433    0.000 base.py:675(<listcomp>)
       74    0.000    0.000    0.392    0.005 base.py:298(new)
       74    0.000    0.000    0.363    0.005 function.py:510(__init__)
       74    0.001    0.000    0.363    0.005 base.py:84(__init__)
       74    0.001    0.000    0.311    0.004 ex_pump.py:471(init_architecture)
      666    0.005    0.000    0.304    0.000 base.py:135(add_flex_role_obj)
      666    0.002    0.000    0.265    0.000 base.py:980(init_obj)
   677378    0.256    0.000    0.256    0.000 base.py:453(get_default_roletypes)
      370    0.001    0.000    0.254    0.001 function.py:543(add_fxn)
      370    0.002    0.000    0.252    0.001 base.py:226(add_sim)
      370    0.001    0.000    0.234    0.001 function.py:77(__init__)
      370    0.004    0.000    0.233    0.001 base.py:497(__init__)
     4088    0.008    0.000    0.226    0.000 base.py:226(log_hist)
   284498    0.178    0.000    0.223    0.000 base.py:508(<dictcomp>)
     4088    0.068    0.000    0.216    0.000 history.py:205(log)
  814/740    0.003    0.000    0.215    0.000 base.py:155(__init__)
1184/1110    0.002    0.000    0.193    0.000 base.py:238(init_roletypes)
     1480    0.015    0.000    0.191    0.000 base.py:269(init_roles)
      444    0.002    0.000    0.190    0.000 base.py:195(__init__)
     8267    0.040    0.000    0.185    0.000 ex_pump.py:423(static_behavior)
     2902    0.015    0.000    0.183    0.000 mode.py:223(get_fault)
     2584    0.002    0.000    0.182    0.000 mode.py:259(get_faults)
     2584    0.002    0.000    0.180    0.000 mode.py:263(<dictcomp>)
   527310    0.127    0.000    0.174    0.000 inspect.py:300(ismethod)
   350917    0.156    0.000    0.167    0.000 base.py:469(get_flex_role_objs)
  1214358    0.155    0.000    0.155    0.000 {built-in method builtins.getattr}
    82154    0.127    0.000    0.153    0.000 time.py:110(return_mutables)
   284498    0.131    0.000    0.131    0.000 base.py:501(<listcomp>)
   284498    0.130    0.000    0.130    0.000 base.py:495(<listcomp>)
     2902    0.005    0.000    0.130    0.000 base.py:428(get_pref_attrs)
    41077    0.028    0.000    0.121    0.000 function.py:115(prop_arch_behaviors)
     1850    0.002    0.000    0.119    0.000 base.py:258(find_roletype_initiators)
     8267    0.024    0.000    0.116    0.000 base.py:230(assign)
    82154    0.046    0.000    0.113    0.000 mode.py:220(return_mutables)
   831538    0.107    0.000    0.107    0.000 {built-in method builtins.hasattr}
40880/16352    0.077    0.000    0.107    0.000 base.py:54(get_var)
     5566    0.097    0.000    0.097    0.000 {built-in method builtins.dir}
   856316    0.083    0.000    0.096    0.000 {built-in method builtins.isinstance}
        1    0.000    0.000    0.093    0.093 propagate.py:501(nom_helper)
     1850    0.065    0.000    0.083    0.000 base.py:259(<listcomp>)
   231246    0.057    0.000    0.082    0.000 base.py:409(return_mutables)
    97552    0.060    0.000    0.080    0.000 copy.py:66(copy)
     4088    0.008    0.000    0.077    0.000 base.py:560(set_vars)
     2902    0.058    0.000    0.077    0.000 base.py:431(<dictcomp>)
      666    0.007    0.000    0.074    0.000 parameter.py:62(__init__)
      518    0.002    0.000    0.067    0.000 base.py:79(__init__)
    63249    0.046    0.000    0.063    0.000 mode.py:297(has_fault)
    16534    0.027    0.000    0.062    0.000 base.py:267(set_field)
      296    0.001    0.000    0.056    0.000 base.py:186(add_flow)
   582574    0.048    0.000    0.048    0.000 {method 'startswith' of 'str' objects}
      814    0.001    0.000    0.046    0.000 base.py:387(init_indicators)
      666    0.002    0.000    0.045    0.000 parameter.py:180(check_pickle)
      814    0.001    0.000    0.044    0.000 inspect.py:3261(signature)
      814    0.001    0.000    0.043    0.000 inspect.py:3007(from_callable)
 1628/814    0.007    0.000    0.042    0.000 inspect.py:2435(_signature_from_callable)
     1110    0.004    0.000    0.037    0.000 base.py:633(create_hist)
     2902    0.006    0.000    0.036    0.000 mode.py:64(__init__)
     4088    0.003    0.000    0.035    0.000 __init__.py:130(copy)
17794/16758    0.025    0.000    0.035    0.000 copy.py:128(deepcopy)
     8264    0.014    0.000    0.033    0.000 ex_pump.py:237(static_behavior)
     4310    0.004    0.000    0.033    0.000 __init__.py:65(__init__)
     3346    0.013    0.000    0.033    0.000 base.py:98(get_true_fields)
     8267    0.018    0.000    0.029    0.000 base.py:169(get_field_dict)
     4236    0.008    0.000    0.029    0.000 _collections_abc.py:717(__ior__)
      814    0.021    0.000    0.029    0.000 base.py:389(<listcomp>)
   363610    0.028    0.000    0.028    0.000 {method 'values' of 'dict' objects}
       74    0.001    0.000    0.028    0.000 base.py:264(new_params)
       73    0.001    0.000    0.027    0.000 propagate.py:1151(get_result)
       73    0.000    0.000    0.027    0.000 std.py:1160(__iter__)
     8185    0.010    0.000    0.026    0.000 ex_pump.py:270(static_behavior)
       36    0.000    0.000    0.026    0.001 std.py:1198(update)
      814    0.009    0.000    0.026    0.000 inspect.py:2331(_signature_from_function)
      370    0.001    0.000    0.026    0.000 base.py:531(create_arch_kwargs)
       37    0.000    0.000    0.025    0.001 std.py:1325(refresh)
       38    0.000    0.000    0.025    0.001 std.py:1464(display)
   231246    0.025    0.000    0.025    0.000 {built-in method recordclass._dataobject.astuple}
       73    0.002    0.000    0.023    0.000 ex_pump.py:522(find_classification)
      148    0.001    0.000    0.023    0.000 parameter.py:176(copy_with_vals)
       38    0.000    0.000    0.023    0.001 std.py:457(print_status)
1776/1187    0.006    0.000    0.022    0.000 result.py:575(flatten)
       38    0.000    0.000    0.021    0.001 std.py:451(fp_write)
       78    0.000    0.000    0.021    0.000 utils.py:194(inner)
      444    0.001    0.000    0.020    0.000 base.py:212(init_hist)
    21180    0.016    0.000    0.019    0.000 __init__.py:180(add)
      296    0.000    0.000    0.019    0.000 base.py:92(create_hist)
     3346    0.006    0.000    0.019    0.000 base.py:105(<listcomp>)
    98688    0.019    0.000    0.019    0.000 time.py:111(<genexpr>)
       40    0.000    0.000    0.019    0.000 iostream.py:592(flush)
     8176    0.009    0.000    0.017    0.000 ex_pump.py:317(static_behavior)
       40    0.000    0.000    0.017    0.000 threading.py:611(wait)
       40    0.000    0.000    0.017    0.000 threading.py:295(wait)
      319    0.016    0.000    0.016    0.000 {method 'acquire' of '_thread.lock' objects}
     3251    0.004    0.000    0.016    0.000 result.py:167(__init__)
     1329    0.001    0.000    0.015    0.000 base.py:104(get_timerange)
       74    0.001    0.000    0.015    0.000 function.py:597(build)
     1183    0.001    0.000    0.015    0.000 base.py:119(get_histrange)
   151272    0.014    0.000    0.014    0.000 {method 'get' of 'dict' objects}
     1329    0.002    0.000    0.014    0.000 base.py:336(gen_timerange)
     8185    0.005    0.000    0.013    0.000 ex_pump.py:296(static_behavior)
    25758    0.007    0.000    0.013    0.000 abc.py:117(__instancecheck__)
       73    0.001    0.000    0.012    0.000 function.py:621(calc_repaircost)
     3251    0.003    0.000    0.012    0.000 __init__.py:1111(__init__)
      518    0.004    0.000    0.011    0.000 base.py:90(find_any_phase_overlap)
    90865    0.011    0.000    0.011    0.000 {method 'copy' of 'set' objects}
     8267    0.006    0.000    0.009    0.000 ex_pump.py:390(set_faults)
       74    0.000    0.000    0.009    0.000 base.py:453(return_faultmodes)
    63249    0.009    0.000    0.009    0.000 {method 'intersection' of 'set' objects}
     3330    0.006    0.000    0.009    0.000 inspect.py:2669(__init__)
   144/72    0.001    0.000    0.009    0.000 base.py:366(inject_faults)
      444    0.001    0.000    0.009    0.000 time.py:92(__init__)
      584    0.001    0.000    0.009    0.000 result.py:336(__getattr__)
125970/125239    0.008    0.000    0.009    0.000 {built-in method builtins.len}
     1628    0.006    0.000    0.009    0.000 inspect.py:2955(__init__)
    85990    0.008    0.000    0.008    0.000 {method 'items' of 'dict' objects}
     1329    0.001    0.000    0.008    0.000 fromnumeric.py:3269(round)
     8267    0.007    0.000    0.008    0.000 base.py:217(<dictcomp>)
    63916    0.008    0.000    0.008    0.000 {built-in method builtins.any}
    39859    0.008    0.000    0.008    0.000 {method 'update' of 'dict' objects}
      814    0.003    0.000    0.008    0.000 inspect.py:2037(_signature_bound_method)
      666    0.004    0.000    0.007    0.000 inspect.py:3215(__str__)
    20440    0.007    0.000    0.007    0.000 base.py:260(is_known_mutable)
      666    0.005    0.000    0.007    0.000 base.py:125(set_arg_type)
     1329    0.001    0.000    0.007    0.000 fromnumeric.py:53(_wrapfunc)
      438    0.003    0.000    0.007    0.000 result.py:400(all_with)
     3324    0.003    0.000    0.007    0.000 _collections_abc.py:941(update)
      666    0.005    0.000    0.007    0.000 parameter.py:136(check_immutable)
     1770    0.002    0.000    0.006    0.000 base.py:213(is_numeric)
     1329    0.006    0.000    0.006    0.000 {method 'round' of 'numpy.ndarray' objects}
       72    0.000    0.000    0.006    0.000 base.py:395(set_fault_disturbances)
    25758    0.006    0.000    0.006    0.000 {built-in method _abc._abc_instancecheck}
       72    0.000    0.000    0.006    0.000 mode.py:419(get_fault_disturbances)
     1036    0.001    0.000    0.005    0.000 fromnumeric.py:865(sort)
    12264    0.004    0.000    0.005    0.000 __init__.py:304(__iter__)
       74    0.000    0.000    0.005    0.000 base.py:257(build)
       74    0.001    0.000    0.005    0.000 function.py:609(construct_graph)
    25256    0.005    0.000    0.005    0.000 {method 'split' of 'str' objects}
     4366    0.003    0.000    0.005    0.000 parameter.py:108(check_lim)
      814    0.001    0.000    0.005    0.000 inspect.py:3023(replace)
    21506    0.004    0.000    0.004    0.000 {method 'update' of 'set' objects}
       74    0.000    0.000    0.004    0.000 timer.py:61(__init__)
    33370    0.004    0.000    0.004    0.000 {method 'join' of 'str' objects}
     1779    0.002    0.000    0.004    0.000 numerictypes.py:357(issubdtype)
      444    0.001    0.000    0.004    0.000 mode.py:199(__init__)
  372/150    0.001    0.000    0.004    0.000 copy.py:227(_deepcopy_dict)
     8264    0.004    0.000    0.004    0.000 ex_pump.py:220(set_faults)
    15123    0.004    0.000    0.004    0.000 {built-in method builtins.min}
      444    0.004    0.000    0.004    0.000 time.py:117(set_timestep)
     6377    0.003    0.000    0.003    0.000 result.py:324(items)
     1329    0.003    0.000    0.003    0.000 {built-in method numpy.arange}
      666    0.003    0.000    0.003    0.000 parameter.py:157(check_type)
     8267    0.003    0.000    0.003    0.000 ex_pump.py:414(indicate_over_pressure)
    20678    0.003    0.000    0.003    0.000 {built-in method builtins.setattr}
       40    0.000    0.000    0.003    0.000 iostream.py:655(write)
     8176    0.002    0.000    0.003    0.000 __init__.py:74(__len__)
      148    0.000    0.000    0.003    0.000 base.py:361(create_hist)
       38    0.000    0.000    0.003    0.000 std.py:1150(__str__)
     3330    0.002    0.000    0.003    0.000 enum.py:688(__call__)
     2072    0.002    0.000    0.003    0.000 inspect.py:2756(__str__)
      119    0.000    0.000    0.002    0.000 iostream.py:259(schedule)
      222    0.001    0.000    0.002    0.000 base.py:421(init_indicator_hist)
    28432    0.002    0.000    0.002    0.000 {method 'append' of 'list' objects}
     2587    0.002    0.000    0.002    0.000 common.py:48(get_sub_include)
       73    0.000    0.000    0.002    0.000 fromnumeric.py:2836(min)
     4599    0.002    0.000    0.002    0.000 __init__.py:1138(__contains__)
     4088    0.002    0.000    0.002    0.000 ex_pump.py:518(indicate_on)
       40    0.000    0.000    0.002    0.000 iostream.py:577(_schedule_flush)
     3251    0.002    0.000    0.002    0.000 result.py:347(__setattr__)
     4144    0.002    0.000    0.002    0.000 inspect.py:3002(<genexpr>)
       38    0.001    0.000    0.002    0.000 std.py:464(format_meter)
     4088    0.002    0.000    0.002    0.000 ex_pump.py:499(indicate_finished)
       73    0.000    0.000    0.002    0.000 fromnumeric.py:71(_wrapreduction)
       74    0.000    0.000    0.002    0.000 function.py:602(<listcomp>)
    17274    0.002    0.000    0.002    0.000 copy.py:182(_deepcopy_atomic)
    19800    0.002    0.000    0.002    0.000 {built-in method builtins.id}
     1036    0.002    0.000    0.002    0.000 {method 'copy' of 'numpy.ndarray' objects}
     3558    0.001    0.000    0.002    0.000 numerictypes.py:283(issubclass_)
     4088    0.002    0.000    0.002    0.000 base.py:150(get_hist_ind)
     4088    0.002    0.000    0.002    0.000 propagate.py:1023(check_end_condition)
      370    0.001    0.000    0.002    0.000 function.py:98(update_seed)
      370    0.001    0.000    0.002    0.000 base.py:590(is_dynamic)
      119    0.002    0.000    0.002    0.000 socket.py:621(send)
      873    0.001    0.000    0.002    0.000 function.py:767(<listcomp>)
      370    0.001    0.000    0.002    0.000 base.py:550(check_flows)
      814    0.001    0.000    0.002    0.000 inspect.py:167(get_annotations)
       72    0.000    0.000    0.002    0.000 base.py:529(get_vars)
      296    0.001    0.000    0.002    0.000 history.py:132(init_att)
     1776    0.001    0.000    0.002    0.000 result.py:112(check_include_errors)
      184    0.001    0.000    0.002    0.000 {built-in method builtins.sum}
       73    0.001    0.000    0.001    0.000 {method 'reduce' of 'numpy.ufunc' objects}
      814    0.001    0.000    0.001    0.000 inspect.py:735(unwrap)
    14954    0.001    0.000    0.001    0.000 copy.py:107(_copy_immutable)
       74    0.000    0.000    0.001    0.000 <class 'networkx.utils.decorators.argmap'> compilation 4:1(argmap_isolates_1)
    13579    0.001    0.000    0.001    0.000 {built-in method builtins.iter}
      148    0.000    0.000    0.001    0.000 state.py:345(init_hist_att)
       38    0.000    0.000    0.001    0.000 utils.py:378(disp_len)
      814    0.001    0.000    0.001    0.000 base.py:213(init_track)
       38    0.000    0.000    0.001    0.000 utils.py:374(_text_width)
     4366    0.001    0.000    0.001    0.000 base.py:173(set_arg_as_type)
     8267    0.001    0.000    0.001    0.000 {method 'clear' of 'set' objects}
        1    0.000    0.000    0.001    0.001 std.py:952(__init__)
       74    0.000    0.000    0.001    0.000 backends.py:627(__call__)
       74    0.001    0.000    0.001    0.000 graph.py:968(add_edges_from)
     1036    0.001    0.000    0.001    0.000 {built-in method numpy.asanyarray}
      148    0.000    0.000    0.001    0.000 base.py:348(init_hist_att)
     8176    0.001    0.000    0.001    0.000 {method 'index' of 'list' objects}
     1036    0.001    0.000    0.001    0.000 {method 'sort' of 'numpy.ndarray' objects}
       74    0.001    0.000    0.001    0.000 history.py:271(cut)
     2357    0.001    0.000    0.001    0.000 __init__.py:1118(__len__)
     8267    0.001    0.000    0.001    0.000 {method 'copy' of 'list' objects}
       74    0.000    0.000    0.001    0.000 function.py:605(<listcomp>)
       74    0.000    0.000    0.001    0.000 isolate.py:42(isolates)
     1770    0.001    0.000    0.001    0.000 {built-in method numpy.array}
     3531    0.001    0.000    0.001    0.000 __init__.py:1128(__setitem__)
       73    0.000    0.000    0.001    0.000 base.py:220(init_time_hist)
       73    0.000    0.000    0.001    0.000 base.py:130(get_shift)
      148    0.001    0.000    0.001    0.000 graph.py:566(add_nodes_from)
     8288    0.001    0.000    0.001    0.000 inspect.py:2734(kind)
     1482    0.001    0.000    0.001    0.000 {method 'format' of 'str' objects}
     7261    0.001    0.000    0.001    0.000 {built-in method builtins.issubclass}
     2571    0.001    0.000    0.001    0.000 utils.py:375(<genexpr>)
     1924    0.001    0.000    0.001    0.000 base.py:51(check_role)
     1169    0.001    0.000    0.001    0.000 graph.py:1318(neighbors)
      518    0.000    0.000    0.001    0.000 base.py:413(asdict)
      370    0.000    0.000    0.001    0.000 __init__.py:201(update)
      518    0.001    0.000    0.001    0.000 base.py:95(<listcomp>)
       74    0.000    0.000    0.001    0.000 copy.py:259(_reconstruct)
     3330    0.001    0.000    0.001    0.000 enum.py:1095(__new__)
       74    0.000    0.000    0.001    0.000 functools.py:981(__get__)
     5846    0.001    0.000    0.001    0.000 inspect.py:2722(name)
        2    0.000    0.000    0.001    0.000 std.py:1265(close)
       74    0.000    0.000    0.001    0.000 function.py:617(<listcomp>)
     1184    0.000    0.000    0.001    0.000 base.py:207(check_slots)
      518    0.001    0.000    0.001    0.000 base.py:92(<dictcomp>)
       74    0.000    0.000    0.001    0.000 function.py:600(<listcomp>)
      370    0.001    0.000    0.001    0.000 base.py:570(<listcomp>)
      370    0.000    0.000    0.001    0.000 base.py:279(get_flows)
       74    0.000    0.000    0.001    0.000 isolate.py:85(<genexpr>)
       74    0.000    0.000    0.001    0.000 {method '__reduce_ex__' of 'object' objects}
      518    0.001    0.000    0.001    0.000 {built-in method recordclass._dataobject.asdict}
        1    0.000    0.000    0.001    0.001 std.py:438(status_printer)
     1628    0.000    0.000    0.001    0.000 inspect.py:378(isfunction)
      584    0.000    0.000    0.001    0.000 result.py:93(get_dict_attr)
      148    0.000    0.000    0.000    0.000 copy.py:264(<genexpr>)
       40    0.000    0.000    0.000    0.000 threading.py:562(__init__)
      520    0.000    0.000    0.000    0.000 copy.py:243(_keep_alive)
      370    0.000    0.000    0.000    0.000 base.py:512(<dictcomp>)
     2338    0.000    0.000    0.000    0.000 __init__.py:165(__contains__)
       74    0.000    0.000    0.000    0.000 graph.py:332(__init__)
      159    0.000    0.000    0.000    0.000 threading.py:1192(is_alive)
      296    0.000    0.000    0.000    0.000 function.py:606(<listcomp>)
      370    0.000    0.000    0.000    0.000 base.py:538(<dictcomp>)
     3330    0.000    0.000    0.000    0.000 {method '__contains__' of 'frozenset' objects}
      810    0.000    0.000    0.000    0.000 base.py:262(get_full_name)
     3330    0.000    0.000    0.000    0.000 {method 'isidentifier' of 'str' objects}
     1776    0.000    0.000    0.000    0.000 result.py:121(check_include_error)
       41    0.000    0.000    0.000    0.000 std.py:102(acquire)
      740    0.000    0.000    0.000    0.000 reportviews.py:529(__iter__)
       74    0.000    0.000    0.000    0.000 graph.py:1484(degree)
      444    0.000    0.000    0.000    0.000 base.py:208(<dictcomp>)
      518    0.000    0.000    0.000    0.000 base.py:94(<listcomp>)
      370    0.000    0.000    0.000    0.000 base.py:565(<listcomp>)
      370    0.000    0.000    0.000    0.000 base.py:584(is_static)
     1480    0.000    0.000    0.000    0.000 {method 'values' of 'mappingproxy' objects}
      217    0.000    0.000    0.000    0.000 std.py:231(__call__)
       75    0.000    0.000    0.000    0.000 std.py:400(format_interval)
       72    0.000    0.000    0.000    0.000 base.py:600(_get_role_call)
       38    0.000    0.000    0.000    0.000 std.py:1446(format_dict)
       74    0.000    0.000    0.000    0.000 copyreg.py:113(_slotnames)
      656    0.000    0.000    0.000    0.000 __init__.py:1121(__getitem__)
      370    0.000    0.000    0.000    0.000 base.py:283(<dictcomp>)
      666    0.000    0.000    0.000    0.000 inspect.py:292(isclass)
       80    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
       76    0.000    0.000    0.000    0.000 utils.py:273(_is_ascii)
      148    0.000    0.000    0.000    0.000 base.py:272(<dictcomp>)
      511    0.000    0.000    0.000    0.000 propagate.py:121(<genexpr>)
       74    0.000    0.000    0.000    0.000 base.py:392(get_indicators)
     1329    0.000    0.000    0.000    0.000 fromnumeric.py:3265(_round_dispatcher)
     2533    0.000    0.000    0.000    0.000 {built-in method unicodedata.east_asian_width}
      296    0.000    0.000    0.000    0.000 {built-in method numpy.empty}
       74    0.000    0.000    0.000    0.000 reportviews.py:419(__init__)
       74    0.000    0.000    0.000    0.000 copy.py:201(_deepcopy_list)
       96    0.000    0.000    0.000    0.000 mode.py:337(add_fault)
       40    0.000    0.000    0.000    0.000 threading.py:243(__init__)
     2442    0.000    0.000    0.000    0.000 {built-in method builtins.callable}
     1628    0.000    0.000    0.000    0.000 inspect.py:3015(parameters)
       41    0.000    0.000    0.000    0.000 {method 'acquire' of '_multiprocessing.SemLock' objects}
      293    0.000    0.000    0.000    0.000 result.py:320(keys)
       41    0.000    0.000    0.000    0.000 std.py:106(release)
      814    0.000    0.000    0.000    0.000 base.py:191(create_name)
       74    0.000    0.000    0.000    0.000 base.py:455(<dictcomp>)
       74    0.000    0.000    0.000    0.000 base.py:114(init_flexible_roles)
       74    0.000    0.000    0.000    0.000 propagate.py:242(save_helper)
       74    0.000    0.000    0.000    0.000 base.py:401(<dictcomp>)
     1036    0.000    0.000    0.000    0.000 fromnumeric.py:861(_sort_dispatcher)
      159    0.000    0.000    0.000    0.000 threading.py:1125(_wait_for_tstate_lock)
      148    0.000    0.000    0.000    0.000 base.py:69(get_track)
       38    0.000    0.000    0.000    0.000 std.py:186(__format__)
      222    0.000    0.000    0.000    0.000 misc.py:595(_clear_cache)
      144    0.000    0.000    0.000    0.000 scenario.py:49(get)
      592    0.000    0.000    0.000    0.000 base.py:65(check_role)
      222    0.000    0.000    0.000    0.000 base.py:654(<listcomp>)
       10    0.000    0.000    0.000    0.000 ipkernel.py:775(_clean_thread_parent_frames)
      814    0.000    0.000    0.000    0.000 {built-in method sys.getrecursionlimit}
      146    0.000    0.000    0.000    0.000 __init__.py:1134(__iter__)
       74    0.000    0.000    0.000    0.000 graph.py:59(__set__)
       73    0.000    0.000    0.000    0.000 propagate.py:119(unpack_sim_kwargs)
       38    0.000    0.000    0.000    0.000 std.py:153(__init__)
       73    0.000    0.000    0.000    0.000 function.py:643(<listcomp>)
      740    0.000    0.000    0.000    0.000 {built-in method builtins.repr}
       74    0.000    0.000    0.000    0.000 base.py:295(update_seed)
       40    0.000    0.000    0.000    0.000 iostream.py:550(_is_master_process)
      119    0.000    0.000    0.000    0.000 iostream.py:138(_event_pipe)
       73    0.000    0.000    0.000    0.000 fromnumeric.py:72(<dictcomp>)
      370    0.000    0.000    0.000    0.000 base.py:593(<listcomp>)
      666    0.000    0.000    0.000    0.000 inspect.py:3019(return_annotation)
      198    0.000    0.000    0.000    0.000 time.py:104(__getattr__)
      292    0.000    0.000    0.000    0.000 {method 'endswith' of 'str' objects}
      370    0.000    0.000    0.000    0.000 base.py:232(update_seed)
       37    0.000    0.000    0.000    0.000 {built-in method now}
       40    0.000    0.000    0.000    0.000 iostream.py:505(parent_header)
       60    0.000    0.000    0.000    0.000 timer.py:83(inc)
        1    0.000    0.000    0.000    0.000 result.py:639(get_memory)
       38    0.000    0.000    0.000    0.000 {method 'sub' of 're.Pattern' objects}
       40    0.000    0.000    0.000    0.000 threading.py:1453(current_thread)
       41    0.000    0.000    0.000    0.000 {method 'release' of '_multiprocessing.SemLock' objects}
        2    0.000    0.000    0.000    0.000 std.py:1286(fp_write)
      370    0.000    0.000    0.000    0.000 base.py:527(init_block)
        1    0.000    0.000    0.000    0.000 utils.py:297(_screen_shape_windows)
       40    0.000    0.000    0.000    0.000 threading.py:283(_acquire_restore)
      147    0.000    0.000    0.000    0.000 {built-in method fromkeys}
       73    0.000    0.000    0.000    0.000 propagate.py:1167(<listcomp>)
       74    0.000    0.000    0.000    0.000 graph.py:37(__set__)
      115    0.000    0.000    0.000    0.000 threading.py:1168(ident)
      444    0.000    0.000    0.000    0.000 inspect.py:2726(default)
       72    0.000    0.000    0.000    0.000 base.py:606(<listcomp>)
      798    0.000    0.000    0.000    0.000 {built-in method builtins.ord}
        5    0.000    0.000    0.000    0.000 ipkernel.py:790(<setcomp>)
      313    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
       41    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.RLock' objects}
      160    0.000    0.000    0.000    0.000 threading.py:575(is_set)
      188    0.000    0.000    0.000    0.000 {built-in method builtins.divmod}
      147    0.000    0.000    0.000    0.000 {built-in method time.time}
        1    0.000    0.000    0.000    0.000 propagate.py:708(process_nominal)
       77    0.000    0.000    0.000    0.000 {method 'pop' of 'dict' objects}
        1    0.000    0.000    0.000    0.000 std.py:686(_decr_instances)
       40    0.000    0.000    0.000    0.000 threading.py:274(__exit__)
        1    0.000    0.000    0.000    0.000 std.py:663(__new__)
        1    0.000    0.000    0.000    0.000 __init__.py:48(create_string_buffer)
       40    0.000    0.000    0.000    0.000 threading.py:286(_is_owned)
       73    0.000    0.000    0.000    0.000 propagate.py:1191(<listcomp>)
       40    0.000    0.000    0.000    0.000 threading.py:271(__enter__)
       74    0.000    0.000    0.000    0.000 reportviews.py:426(__call__)
      119    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.RLock' objects}
       40    0.000    0.000    0.000    0.000 {built-in method nt.getpid}
       74    0.000    0.000    0.000    0.000 {method 'get' of 'mappingproxy' objects}
       74    0.000    0.000    0.000    0.000 parameter.py:105(keys)
       40    0.000    0.000    0.000    0.000 threading.py:280(_release_save)
       38    0.000    0.000    0.000    0.000 utils.py:108(__init__)
        4    0.000    0.000    0.000    0.000 std.py:110(__enter__)
        3    0.000    0.000    0.000    0.000 _weakrefset.py:63(__iter__)
        1    0.000    0.000    0.000    0.000 propagate.py:168(pack_run_kwargs)
      159    0.000    0.000    0.000    0.000 {method 'append' of 'collections.deque' objects}
        5    0.000    0.000    0.000    0.000 threading.py:1501(enumerate)
        1    0.000    0.000    0.000    0.000 std.py:679(_get_free_pos)
       38    0.000    0.000    0.000    0.000 std.py:167(colour)
        1    0.000    0.000    0.000    0.000 propagate.py:170(<dictcomp>)
       38    0.000    0.000    0.000    0.000 {built-in method builtins.max}
        4    0.000    0.000    0.000    0.000 std.py:113(__exit__)
       38    0.000    0.000    0.000    0.000 utils.py:112(__format__)
       40    0.000    0.000    0.000    0.000 {built-in method builtins.abs}
       40    0.000    0.000    0.000    0.000 {method 'write' of '_io.StringIO' objects}
       40    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
       73    0.000    0.000    0.000    0.000 fromnumeric.py:2831(_min_dispatcher)
       38    0.000    0.000    0.000    0.000 std.py:163(colour)
       41    0.000    0.000    0.000    0.000 {method 'release' of '_thread.RLock' objects}
       40    0.000    0.000    0.000    0.000 {method 'get' of '_contextvars.ContextVar' objects}
        1    0.000    0.000    0.000    0.000 std.py:682(<setcomp>)
        1    0.000    0.000    0.000    0.000 utils.py:213(__init__)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:27(__exit__)
        1    0.000    0.000    0.000    0.000 _weakrefset.py:110(remove)
       40    0.000    0.000    0.000    0.000 {method '__enter__' of '_thread.lock' objects}
       40    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.lock' objects}
        3    0.000    0.000    0.000    0.000 {method 'remove' of 'set' objects}
        1    0.000    0.000    0.000    0.000 utils.py:266(_supports_unicode)
       40    0.000    0.000    0.000    0.000 {method 'release' of '_thread.lock' objects}
        2    0.000    0.000    0.000    0.000 _weakrefset.py:53(_commit_removals)
        1    0.000    0.000    0.000    0.000 _weakrefset.py:85(add)
        1    0.000    0.000    0.000    0.000 functools.py:393(__get__)
        4    0.000    0.000    0.000    0.000 utils.py:222(__eq__)
        1    0.000    0.000    0.000    0.000 utils.py:252(_is_utf)
        1    0.000    0.000    0.000    0.000 {built-in method fromtimestamp}
        1    0.000    0.000    0.000    0.000 utils.py:125(__eq__)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:21(__enter__)
        2    0.000    0.000    0.000    0.000 utils.py:187(disable_on_exception)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1207(_handle_fromlist)
        5    0.000    0.000    0.000    0.000 propagate.py:203(<genexpr>)
        1    0.000    0.000    0.000    0.000 scenario.py:136(__init__)
        3    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}
        1    0.000    0.000    0.000    0.000 sample.py:812(scenarios)
        1    0.000    0.000    0.000    0.000 _monitor.py:94(report)
        1    0.000    0.000    0.000    0.000 sample.py:808(times)
        2    0.000    0.000    0.000    0.000 std.py:1157(__hash__)
        1    0.000    0.000    0.000    0.000 {method 'encode' of 'str' objects}
        3    0.000    0.000    0.000    0.000 utils.py:152(wrapper_setattr)
        1    0.000    0.000    0.000    0.000 utils.py:156(__init__)
        2    0.000    0.000    0.000    0.000 std.py:1153(_comparable)
        3    0.000    0.000    0.000    0.000 std.py:226(__init__)
        1    0.000    0.000    0.000    0.000 std.py:1147(__del__)
        2    0.000    0.000    0.000    0.000 _weakrefset.py:17(__init__)
        1    0.000    0.000    0.000    0.000 propagate.py:201(unpack_mult_kwargs)
        1    0.000    0.000    0.000    0.000 propagate.py:815(close_pool)
        1    0.000    0.000    0.000    0.000 std.py:760(get_lock)
        1    0.000    0.000    0.000    0.000 propagate.py:879(check_overwrite)
        1    0.000    0.000    0.000    0.000 utils.py:282(_screen_shape_wrapper)
        2    0.000    0.000    0.000    0.000 {method 'pop' of 'list' objects}
        1    0.000    0.000    0.000    0.000 tz.py:74(utcoffset)
        1    0.000    0.000    0.000    0.000 utils.py:139(__getattr__)
        1    0.000    0.000    0.000    0.000 {method 'difference' of 'set' objects}
        1    0.000    0.000    0.000    0.000 {built-in method __new__ of type object at 0x00007FFE5984C4C0}
        2    0.000    0.000    0.000    0.000 {built-in method _weakref.proxy}
        1    0.000    0.000    0.000    0.000 scenario.py:138(<dictcomp>)
        1    0.000    0.000    0.000    0.000 std.py:1301(<lambda>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {built-in method sys.audit}


[39]:
prof = cProfile.run('Pump()', sort='tottime')
         8373 function calls (8356 primitive calls) in 0.005 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       25    0.001    0.000    0.001    0.000 base.py:259(<listcomp>)
       36    0.001    0.000    0.001    0.000 {built-in method builtins.dir}
     4447    0.000    0.000    0.000    0.000 {method 'startswith' of 'str' objects}
       11    0.000    0.000    0.000    0.000 base.py:389(<listcomp>)
       20    0.000    0.000    0.003    0.000 base.py:269(init_roles)
       10    0.000    0.000    0.000    0.000 inspect.py:2331(_signature_from_function)
        1    0.000    0.000    0.005    0.005 {built-in method builtins.exec}
    20/10    0.000    0.000    0.001    0.000 inspect.py:2435(_signature_from_callable)
        8    0.000    0.000    0.001    0.000 parameter.py:62(__init__)
       42    0.000    0.000    0.000    0.000 inspect.py:2669(__init__)
       20    0.000    0.000    0.000    0.000 inspect.py:2955(__init__)
    21/16    0.000    0.000    0.000    0.000 result.py:575(flatten)
      338    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
        9    0.000    0.000    0.004    0.000 base.py:135(add_flex_role_obj)
      520    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
       15    0.000    0.000    0.000    0.000 {method 'round' of 'numpy.ndarray' objects}
        8    0.000    0.000    0.000    0.000 base.py:125(set_arg_type)
        8    0.000    0.000    0.000    0.000 parameter.py:136(check_immutable)
        5    0.000    0.000    0.003    0.001 base.py:497(__init__)
        6    0.000    0.000    0.000    0.000 base.py:90(find_any_phase_overlap)
       15    0.000    0.000    0.001    0.000 base.py:633(create_hist)
        8    0.000    0.000    0.000    0.000 inspect.py:3215(__str__)
    11/10    0.000    0.000    0.003    0.000 base.py:155(__init__)
        6    0.000    0.000    0.000    0.000 time.py:117(set_timestep)
       34    0.000    0.000    0.000    0.000 result.py:167(__init__)
    16/15    0.000    0.000    0.003    0.000 base.py:238(init_roletypes)
       34    0.000    0.000    0.000    0.000 __init__.py:1111(__init__)
       10    0.000    0.000    0.000    0.000 inspect.py:2037(_signature_bound_method)
        8    0.000    0.000    0.000    0.000 parameter.py:157(check_type)
       45    0.000    0.000    0.000    0.000 parameter.py:108(check_lim)
       25    0.000    0.000    0.002    0.000 base.py:258(find_roletype_initiators)
       32    0.000    0.000    0.000    0.000 common.py:48(get_sub_include)
        6    0.000    0.000    0.003    0.000 base.py:195(__init__)
       34    0.000    0.000    0.000    0.000 _collections_abc.py:941(update)
       15    0.000    0.000    0.000    0.000 base.py:336(gen_timerange)
       26    0.000    0.000    0.000    0.000 inspect.py:2756(__str__)
        5    0.000    0.000    0.003    0.001 base.py:226(add_sim)
       42    0.000    0.000    0.000    0.000 enum.py:688(__call__)
       16    0.000    0.000    0.000    0.000 base.py:462(get_roles)
       16    0.000    0.000    0.000    0.000 base.py:465(<listcomp>)
        9    0.000    0.000    0.004    0.000 base.py:980(init_obj)
       99    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
       34    0.000    0.000    0.000    0.000 result.py:347(__setattr__)
        6    0.000    0.000    0.001    0.000 base.py:79(__init__)
       52    0.000    0.000    0.000    0.000 inspect.py:3002(<genexpr>)
       56    0.000    0.000    0.000    0.000 {built-in method builtins.setattr}
      228    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
        3    0.000    0.000    0.000    0.000 base.py:421(init_indicator_hist)
        8    0.000    0.000    0.001    0.000 parameter.py:180(check_pickle)
        6    0.000    0.000    0.000    0.000 mode.py:199(__init__)
        6    0.000    0.000    0.000    0.000 base.py:98(get_true_fields)
       13    0.000    0.000    0.000    0.000 numerictypes.py:357(issubdtype)
       11    0.000    0.000    0.001    0.000 base.py:387(init_indicators)
      246    0.000    0.000    0.000    0.000 {built-in method builtins.len}
       12    0.000    0.000    0.000    0.000 {built-in method numpy.asanyarray}
        5    0.000    0.000    0.003    0.001 function.py:543(add_fxn)
       13    0.000    0.000    0.000    0.000 base.py:213(is_numeric)
       15    0.000    0.000    0.000    0.000 {built-in method numpy.arange}
       12    0.000    0.000    0.000    0.000 fromnumeric.py:865(sort)
       10    0.000    0.000    0.000    0.000 inspect.py:735(unwrap)
       10    0.000    0.000    0.000    0.000 inspect.py:167(get_annotations)
        4    0.000    0.000    0.000    0.000 history.py:132(init_att)
       47    0.000    0.000    0.000    0.000 abc.py:117(__instancecheck__)
       42    0.000    0.000    0.000    0.000 {method 'isidentifier' of 'str' objects}
       11    0.000    0.000    0.000    0.000 base.py:213(init_track)
        6    0.000    0.000    0.000    0.000 time.py:92(__init__)
        5    0.000    0.000    0.003    0.001 function.py:77(__init__)
       21    0.000    0.000    0.000    0.000 result.py:112(check_include_errors)
       15    0.000    0.000    0.000    0.000 base.py:119(get_histrange)
       26    0.000    0.000    0.000    0.000 numerictypes.py:283(issubclass_)
       15    0.000    0.000    0.000    0.000 base.py:104(get_timerange)
       12    0.000    0.000    0.000    0.000 copy.py:66(copy)
       15    0.000    0.000    0.000    0.000 fromnumeric.py:53(_wrapfunc)
       15    0.000    0.000    0.000    0.000 fromnumeric.py:3269(round)
       45    0.000    0.000    0.000    0.000 base.py:173(set_arg_as_type)
       10    0.000    0.000    0.001    0.000 inspect.py:3007(from_callable)
        1    0.000    0.000    0.000    0.000 graph.py:968(add_edges_from)
       26    0.000    0.000    0.000    0.000 base.py:51(check_role)
        1    0.000    0.000    0.005    0.005 base.py:84(__init__)
        1    0.000    0.000    0.005    0.005 <string>:1(<module>)
       10    0.000    0.000    0.000    0.000 inspect.py:3023(replace)
       12    0.000    0.000    0.000    0.000 {method 'copy' of 'numpy.ndarray' objects}
        6    0.000    0.000    0.000    0.000 base.py:212(init_hist)
       47    0.000    0.000    0.000    0.000 {built-in method _abc._abc_instancecheck}
      104    0.000    0.000    0.000    0.000 inspect.py:2734(kind)
        5    0.000    0.000    0.000    0.000 base.py:531(create_arch_kwargs)
       10    0.000    0.000    0.000    0.000 __init__.py:180(add)
       13    0.000    0.000    0.000    0.000 {built-in method numpy.array}
       97    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
       42    0.000    0.000    0.000    0.000 enum.py:1095(__new__)
        6    0.000    0.000    0.000    0.000 base.py:105(<listcomp>)
        5    0.000    0.000    0.000    0.000 base.py:550(check_flows)
        2    0.000    0.000    0.000    0.000 graph.py:566(add_nodes_from)
        5    0.000    0.000    0.000    0.000 base.py:469(get_flex_role_objs)
       21    0.000    0.000    0.000    0.000 result.py:324(items)
        1    0.000    0.000    0.000    0.000 function.py:609(construct_graph)
       12    0.000    0.000    0.000    0.000 {method 'sort' of 'numpy.ndarray' objects}
       65    0.000    0.000    0.000    0.000 {built-in method builtins.issubclass}
       74    0.000    0.000    0.000    0.000 inspect.py:2722(name)
        5    0.000    0.000    0.000    0.000 function.py:98(update_seed)
       10    0.000    0.000    0.001    0.000 inspect.py:3261(signature)
        1    0.000    0.000    0.004    0.004 ex_pump.py:471(init_architecture)
        5    0.000    0.000    0.000    0.000 base.py:590(is_dynamic)
        1    0.000    0.000    0.005    0.005 function.py:510(__init__)
       16    0.000    0.000    0.000    0.000 base.py:453(get_default_roletypes)
        4    0.000    0.000    0.001    0.000 base.py:186(add_flow)
        1    0.000    0.000    0.000    0.000 function.py:597(build)
       18    0.000    0.000    0.000    0.000 {method 'format' of 'str' objects}
       21    0.000    0.000    0.000    0.000 __init__.py:1118(__len__)
        6    0.000    0.000    0.000    0.000 base.py:95(<listcomp>)
        5    0.000    0.000    0.000    0.000 base.py:570(<listcomp>)
        6    0.000    0.000    0.000    0.000 base.py:92(<dictcomp>)
       20    0.000    0.000    0.000    0.000 inspect.py:378(isfunction)
       42    0.000    0.000    0.000    0.000 {method '__contains__' of 'frozenset' objects}
       16    0.000    0.000    0.000    0.000 base.py:207(check_slots)
        2    0.000    0.000    0.000    0.000 base.py:361(create_hist)
       70    0.000    0.000    0.000    0.000 {method 'items' of 'dict' objects}
       11    0.000    0.000    0.000    0.000 base.py:191(create_name)
        1    0.000    0.000    0.000    0.000 function.py:605(<listcomp>)
       21    0.000    0.000    0.000    0.000 result.py:121(check_include_error)
       17    0.000    0.000    0.000    0.000 __init__.py:1128(__setitem__)
        1    0.000    0.000    0.000    0.000 base.py:257(build)
        5    0.000    0.000    0.000    0.000 base.py:512(<dictcomp>)
        5    0.000    0.000    0.000    0.000 {built-in method recordclass._dataobject.asdict}
        1    0.000    0.000    0.000    0.000 functools.py:981(__get__)
        5    0.000    0.000    0.000    0.000 base.py:279(get_flows)
        1    0.000    0.000    0.000    0.000 graph.py:332(__init__)
        5    0.000    0.000    0.000    0.000 __init__.py:201(update)
        2    0.000    0.000    0.000    0.000 base.py:348(init_hist_att)
        4    0.000    0.000    0.000    0.000 function.py:606(<listcomp>)
        6    0.000    0.000    0.000    0.000 base.py:208(<dictcomp>)
        4    0.000    0.000    0.000    0.000 base.py:92(create_hist)
        6    0.000    0.000    0.000    0.000 base.py:94(<listcomp>)
       10    0.000    0.000    0.000    0.000 reportviews.py:529(__iter__)
        1    0.000    0.000    0.000    0.000 function.py:600(<listcomp>)
        5    0.000    0.000    0.000    0.000 base.py:538(<dictcomp>)
        2    0.000    0.000    0.000    0.000 state.py:345(init_hist_att)
       18    0.000    0.000    0.000    0.000 {method 'values' of 'mappingproxy' objects}
        5    0.000    0.000    0.000    0.000 base.py:565(<listcomp>)
        1    0.000    0.000    0.000    0.000 isolate.py:42(isolates)
        2    0.000    0.000    0.000    0.000 base.py:272(<dictcomp>)
        9    0.000    0.000    0.000    0.000 base.py:262(get_full_name)
        5    0.000    0.000    0.000    0.000 base.py:283(<dictcomp>)
        3    0.000    0.000    0.000    0.000 __init__.py:65(__init__)
       31    0.000    0.000    0.000    0.000 {method 'update' of 'dict' objects}
       30    0.000    0.000    0.000    0.000 {built-in method builtins.callable}
        1    0.000    0.000    0.000    0.000 function.py:602(<listcomp>)
        9    0.000    0.000    0.000    0.000 inspect.py:292(isclass)
        5    0.000    0.000    0.000    0.000 base.py:413(asdict)
       15    0.000    0.000    0.000    0.000 fromnumeric.py:3265(_round_dispatcher)
        5    0.000    0.000    0.000    0.000 base.py:584(is_static)
        1    0.000    0.000    0.000    0.000 <class 'networkx.utils.decorators.argmap'> compilation 4:1(argmap_isolates_1)
        4    0.000    0.000    0.000    0.000 {built-in method numpy.empty}
        1    0.000    0.000    0.000    0.000 base.py:114(init_flexible_roles)
        1    0.000    0.000    0.000    0.000 isolate.py:85(<genexpr>)
       20    0.000    0.000    0.000    0.000 inspect.py:3015(parameters)
        2    0.000    0.000    0.000    0.000 _collections_abc.py:717(__ior__)
        3    0.000    0.000    0.000    0.000 base.py:654(<listcomp>)
        8    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
        4    0.000    0.000    0.000    0.000 graph.py:1318(neighbors)
        1    0.000    0.000    0.000    0.000 base.py:401(<dictcomp>)
        1    0.000    0.000    0.000    0.000 backends.py:627(__call__)
        1    0.000    0.000    0.000    0.000 reportviews.py:419(__init__)
        1    0.000    0.000    0.000    0.000 timer.py:61(__init__)
       12    0.000    0.000    0.000    0.000 fromnumeric.py:861(_sort_dispatcher)
        1    0.000    0.000    0.000    0.000 graph.py:1484(degree)
        2    0.000    0.000    0.000    0.000 base.py:69(get_track)
        8    0.000    0.000    0.000    0.000 base.py:65(check_role)
        8    0.000    0.000    0.000    0.000 __init__.py:165(__contains__)
        1    0.000    0.000    0.000    0.000 base.py:392(get_indicators)
       12    0.000    0.000    0.000    0.000 {method 'values' of 'dict' objects}
       10    0.000    0.000    0.000    0.000 {built-in method builtins.id}
       10    0.000    0.000    0.000    0.000 {built-in method builtins.repr}
        3    0.000    0.000    0.000    0.000 misc.py:595(_clear_cache)
        5    0.000    0.000    0.000    0.000 base.py:593(<listcomp>)
        9    0.000    0.000    0.000    0.000 {built-in method builtins.any}
       10    0.000    0.000    0.000    0.000 {built-in method sys.getrecursionlimit}
        2    0.000    0.000    0.000    0.000 __init__.py:1121(__getitem__)
        8    0.000    0.000    0.000    0.000 inspect.py:3019(return_annotation)
        5    0.000    0.000    0.000    0.000 base.py:527(init_block)
        1    0.000    0.000    0.000    0.000 graph.py:59(__set__)
        6    0.000    0.000    0.000    0.000 {method 'copy' of 'set' objects}
        1    0.000    0.000    0.000    0.000 function.py:617(<listcomp>)
        5    0.000    0.000    0.000    0.000 base.py:232(update_seed)
        6    0.000    0.000    0.000    0.000 copy.py:107(_copy_immutable)
        6    0.000    0.000    0.000    0.000 inspect.py:2726(default)
        1    0.000    0.000    0.000    0.000 base.py:295(update_seed)
        1    0.000    0.000    0.000    0.000 graph.py:37(__set__)
        4    0.000    0.000    0.000    0.000 {built-in method builtins.iter}
        1    0.000    0.000    0.000    0.000 reportviews.py:426(__call__)
        1    0.000    0.000    0.000    0.000 {method 'lower' of 'str' objects}
        1    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.RLock' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


As shown, running this model is not particularly computationally expensive. As a result, the majority of the computational expense is not actually because of the simulation itself, but because of the way the model is simulated:

  • the majority is spent simulating the model

  • a certain amount is spent re-initalizing the model at first so that the model object can be re-used without worrying about it being modified by any previous executions

  • another amount is spent recording the model history, wich can increase or decrease depending on tracking options (note the low number of values tracked in the pump model by default)

This is mostly because the model itself is computationally inexpensive. However, this example shows how one might easily speed up simulation for optimization or large-n simulations–avoiding unnecessary re-initialization, tracking fewer model states, or speeding up model execution. This can be done in the following ways:

  • using the options for track (as mentioned above) to track fewer states (reducing time spent recording the history)

  • using protect options, which specifies whether the model used is re-instantiated for the simulation (True) or used directly (False)

  • speeding up the model by using dynamic_behavior() methods instead of static_behavior() or behavior() methods (which can halve the simulation time at the expense of undirected propagation)

  • speeding up the model by using a longer global timestep ('tstep' in modelparams) or by speeding up paricularly expensive Function dynamic behaviors by setting (dt=local_tstep) in the SimParam

[ ]: