pathsim 0.26.0__tar.gz → 0.27.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pathsim-0.26.0 → pathsim-0.27.1}/PKG-INFO +1 -1
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/_version.py +3 -3
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/dae.py +81 -24
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/simulation.py +4 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/graph.py +15 -11
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/PKG-INFO +1 -1
- pathsim-0.27.1/src/pathsim.egg-info/scm_version.json +8 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_dae.py +69 -4
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_simulation.py +157 -3
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_graph.py +67 -0
- pathsim-0.26.0/src/pathsim.egg-info/scm_version.json +0 -8
- {pathsim-0.26.0 → pathsim-0.27.1}/.codecov.yml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.github/FUNDING.yml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.github/pull_request_template.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/pypi_deployment.yml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/tests_codecov.yml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/urlchecker.yml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/.gitignore +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/CITATION.cff +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/CONTRIBUTING.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/LICENSE.txt +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/README.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/conftest.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/abs_braking.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/algebraic_loop.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/billards.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/bouncing_ball.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/bouncing_pendulum.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/cascade_controller.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/checkpoints.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/chemical_reactor.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/coupled_oscillators.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/BouncingBall_ME.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/CoupledClutches_CS_linux64.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/CoupledClutches_CS_win64.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/Dahlquist.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/VanDerPol_ME.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/dcmotor_control.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/delta_sigma_adc.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/diode_circuit.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/elastic_pendulum.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/algebraicloop_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/billard_circle_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_both_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_events_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_timesteps_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_pendulum_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/cascade_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/coupled_oscillators_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/coupled_oscillators_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/delta_sigma_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/diode_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/elastic_pendulum_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/fmcw_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/fmcw_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/harmonic_oscillator_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/harmonic_oscillator_result_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/kalman_filter_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_result_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_result_sensitivity_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/miller_frequency_divider_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/nonlinear_noisy_amplifier_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/ode_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/pendulum_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/pid_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/sar_adc_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_slip_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_stick_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/thermostat_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_result_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl1_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl2_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl3_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/volterralotka_blockdiagram_g.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/ode_blockdiagram_2.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/stick_slip_blockdiagram_slip.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/stick_slip_blockdiagram_stick.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmcw_radar.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_cosimulation.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_model_exchange_bouncing_ball.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_model_exchange_vanderpol.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/harmonic_oscillator.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/kalman_filter.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/linear_feedback.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/lorenz_attractor.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/nested_subsystems.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/noisy_amplifier.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/pendulum.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/pid_controller.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/poincare_maps.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/rf_network_oneport.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/sar_adc.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/spectrum_analysis.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/stick_slip.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/switched_bouncing_ball.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/thermostat.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/transfer_function.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/vanderpol.ipynb +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_icon.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_logo.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_simplistic_logo.png +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/pathsim_docs.mplstyle +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_abs_braking.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_adc.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_algebraicchain.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_algebraicloop.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_cascade.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_dcmotor.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_deltasigma.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_derivative.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_diode.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_dualslope.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_elastic_pendulum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_feedback.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_filters.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_harmonic_oscillator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_kalman_filter.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_nested_subsystems.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_noise.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pendulum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_phasenoise.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid_antiwindup.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid_vs_discretePID.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_radar.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_reactor.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_sar.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_solar.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_solver_hotswap.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_spectrum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_spectrum_rf_oneport.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_steadystate.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_stickslip.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_transferfunction.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_vanderpol_subsystem.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_billards_sphere.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncing_pendulum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball_friction.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball_switched.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_integrator_reset.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_pulse.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_stickslip_event.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_thermostat.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_volterralotka_event.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_bonhoeffer_vanderpol.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_brusselator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_chemical.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_duffing.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_fairen_velarde.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_fitzhughnagumo.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_flame.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_glycolysis.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_lorenz.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_morse.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_robertson.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_roessler.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_thomas_cyclic.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_vanderpol.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_volterralotka.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/git +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/pyproject.toml +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/setup.cfg +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/_constants.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/README.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/_block.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/adder.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/amplifier.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/bvp.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/comparator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/constraint.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/converters.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/counter.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/ctrl.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/delay.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/differentiator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/discrete.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/divider.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/dynsys.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/filters.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/fmu.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/function.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/integrator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/kalman.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/logic.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/lti.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/math.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/multiplier.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/noise.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/ode.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/relay.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/rf.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/rng.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/scope.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/sources.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/spectrum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/switch.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/table.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/wrapper.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/connection.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/_event.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/condition.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/schedule.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/zerocrossing.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/exceptions.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/anderson.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/booster.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/linearization.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/newton.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/numerical.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/operator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/README.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/_rungekutta.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/_solver.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/bdf.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/dirk2.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/dirk3.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk32.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk4.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk43.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk85.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/euler.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/gear.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rk4.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkbs32.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkck54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkdp54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkdp87.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf21.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf45.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf78.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkv65.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk22.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk33.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk34.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/steadystate.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/subsystem.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/adaptivebuffer.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/analysis.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/deprecation.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/diagnostics.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/fmuwrapper.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/gilbert.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/logger.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/mutable.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/portreference.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/progresstracker.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/realtimeplotter.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/register.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/SOURCES.txt +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/dependency_links.txt +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/requires.txt +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/scm_file_list.json +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/top_level.txt +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/README.md +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/CoupledClutches_CS.fmu +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/conftest.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_algebraic_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_bouncingball_friction_event_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_bouncingball_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_brusselator_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_cosim_fmu_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_counter_comparator_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_dynamical_system_ivp.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_fitzhughnagumo_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_harmonic_oscillator_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_linear_feedback_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_logic_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_lorenz_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_me_analytical.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_model_exchange_fmu_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_pid_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_relay_thermostat_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_rescale_delay_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_robertson_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_roessler_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_signal_processing_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_steadystate_transient_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_switch_lti_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_vanderpol_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_volterralotka_system.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/_embedding.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/ring_slot.s2p +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/ring_slot_meas.s1p +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/test_rf.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_adder.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_amplifier.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_block.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_bvp.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_comparator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_constraint.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_converters.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_counter.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_ctrl.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_delay.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_differentiator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_discrete.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_divider.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_dynsys.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_filters.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_fmu.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_function.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_integrator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_kalman.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_logic.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_lti.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_math.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_multiplier.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_noise.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_ode.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_relay.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_rng.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_scope.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_sources.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_spectrum.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_switch.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_table.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_wrapper.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_condition.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_event.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_schedule.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_zerocrossing.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_anderson.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_linearization.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_newton.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_numerical.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_operator.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/_referenceproblems.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_bdf.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_dirk2.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_dirk3.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk32.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk4.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk43.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk85.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_euler.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_gear.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rfk21.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rk4.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkbs32.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkck54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkdp54.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkdp87.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkf45.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkf78.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkv65.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_solver.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk22.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk33.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk34.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_steadystate.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_auto_initial_step.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_checkpoint.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_connection.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_diagnostics.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_simulation_pss.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_subsystem.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/__init__.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_adaptivebuffer.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_analysis.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_fmuwrapper.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_gilbert.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_logger.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_mutable.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_portreference.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_progresstracker.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_realtimeplotter.py +0 -0
- {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_register.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.27.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 27, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'ga4e824de2'
|
|
@@ -51,7 +51,10 @@ class SemiExplicitDAE(Block):
|
|
|
51
51
|
\\dot{x} = f_\\mathrm{dyn}(x, z(x, u, t), u, t)
|
|
52
52
|
|
|
53
53
|
to the integration engine, so the DAE integrates with any solver, explicit
|
|
54
|
-
or implicit. The block output is the stacked state :math:`[x, z]
|
|
54
|
+
or implicit. The block output is the stacked state :math:`[x, z]`, or
|
|
55
|
+
:math:`y = f_\\mathrm{out}(x, z, u, t)` if an output function is supplied.
|
|
56
|
+
Without algebraic states (empty `z0`) the block reduces to a plain ODE and
|
|
57
|
+
the constraint solve is skipped.
|
|
55
58
|
|
|
56
59
|
Note
|
|
57
60
|
----
|
|
@@ -126,6 +129,9 @@ class SemiExplicitDAE(Block):
|
|
|
126
129
|
convergence tolerance on the residual norm of the algebraic constraint
|
|
127
130
|
solve, loosen it for ill-conditioned constraints whose residual cannot
|
|
128
131
|
reach the default due to roundoff
|
|
132
|
+
func_out : callable, None
|
|
133
|
+
optional output function with signature `func_out(x, z, u, t)`, the
|
|
134
|
+
block output is the stacked state `[x, z]` if `None`
|
|
129
135
|
|
|
130
136
|
Attributes
|
|
131
137
|
----------
|
|
@@ -148,7 +154,8 @@ class SemiExplicitDAE(Block):
|
|
|
148
154
|
jac_dyn_x=None,
|
|
149
155
|
jac_dyn_z=None,
|
|
150
156
|
jac_alg_x=None,
|
|
151
|
-
tolerance=SOL_TOLERANCE_FPI
|
|
157
|
+
tolerance=SOL_TOLERANCE_FPI,
|
|
158
|
+
func_out=None
|
|
152
159
|
):
|
|
153
160
|
|
|
154
161
|
super().__init__()
|
|
@@ -157,6 +164,9 @@ class SemiExplicitDAE(Block):
|
|
|
157
164
|
self.func_dyn = func_dyn
|
|
158
165
|
self.func_alg = func_alg
|
|
159
166
|
|
|
167
|
+
#optional output function, stacked state [x, z] if 'None'
|
|
168
|
+
self.func_out = func_out
|
|
169
|
+
|
|
160
170
|
#convergence tolerance of the algebraic constraint solve
|
|
161
171
|
self.tolerance = tolerance
|
|
162
172
|
|
|
@@ -187,9 +197,10 @@ class SemiExplicitDAE(Block):
|
|
|
187
197
|
self.op_dyn = DynamicOperator(func=self._rhs, jac_x=_jac_x)
|
|
188
198
|
|
|
189
199
|
#pre-size the output register to the stacked state [x, z]
|
|
190
|
-
self.
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
if self.func_out is None:
|
|
201
|
+
self.outputs.update_from_array(
|
|
202
|
+
np.concatenate([self.initial_value, self.z0])
|
|
203
|
+
)
|
|
193
204
|
|
|
194
205
|
|
|
195
206
|
def __len__(self):
|
|
@@ -204,10 +215,11 @@ class SemiExplicitDAE(Block):
|
|
|
204
215
|
"""
|
|
205
216
|
super().reset()
|
|
206
217
|
self._z = self.z0.copy()
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
218
|
+
if self.func_out is None:
|
|
219
|
+
x = self.engine.state if self.engine else self.initial_value
|
|
220
|
+
self.outputs.update_from_array(
|
|
221
|
+
np.concatenate([np.atleast_1d(x), self._z])
|
|
222
|
+
)
|
|
211
223
|
|
|
212
224
|
|
|
213
225
|
def _solve_z(self, x, u, t):
|
|
@@ -229,6 +241,10 @@ class SemiExplicitDAE(Block):
|
|
|
229
241
|
z : array[float]
|
|
230
242
|
algebraic states satisfying the constraint
|
|
231
243
|
"""
|
|
244
|
+
#nothing to solve without algebraic states
|
|
245
|
+
if self._z.size == 0:
|
|
246
|
+
return self._z
|
|
247
|
+
|
|
232
248
|
_func = lambda z: self.func_alg(x, z, u, t)
|
|
233
249
|
_jac = None if self.jac_z is None else (lambda z: self.jac_z(x, z, u, t))
|
|
234
250
|
z, _, _ = solve_root(self.opt, _func, self._z, _jac, tolerance=self.tolerance)
|
|
@@ -277,6 +293,8 @@ class SemiExplicitDAE(Block):
|
|
|
277
293
|
"""
|
|
278
294
|
z = self._solve_z(x, u, t)
|
|
279
295
|
fx = np.atleast_2d(self.jac_dyn_x(x, z, u, t))
|
|
296
|
+
if z.size == 0:
|
|
297
|
+
return fx
|
|
280
298
|
fz = np.atleast_2d(self.jac_dyn_z(x, z, u, t))
|
|
281
299
|
gx = np.atleast_2d(self.jac_alg_x(x, z, u, t))
|
|
282
300
|
gz = np.atleast_2d(self.jac_z(x, z, u, t))
|
|
@@ -285,7 +303,7 @@ class SemiExplicitDAE(Block):
|
|
|
285
303
|
|
|
286
304
|
def update(self, t):
|
|
287
305
|
"""Eliminate the algebraic states for the current input and expose the
|
|
288
|
-
stacked state [x, z] at the output.
|
|
306
|
+
output function, or the stacked state [x, z], at the output.
|
|
289
307
|
|
|
290
308
|
Parameters
|
|
291
309
|
----------
|
|
@@ -294,9 +312,11 @@ class SemiExplicitDAE(Block):
|
|
|
294
312
|
"""
|
|
295
313
|
x, u = self.engine.state, self.inputs.to_array()
|
|
296
314
|
self._z = self._solve_z(x, u, t)
|
|
297
|
-
self.
|
|
298
|
-
np.concatenate([np.atleast_1d(x), self._z])
|
|
299
|
-
|
|
315
|
+
if self.func_out is None:
|
|
316
|
+
y = np.concatenate([np.atleast_1d(x), self._z])
|
|
317
|
+
else:
|
|
318
|
+
y = self.func_out(x, self._z, u, t)
|
|
319
|
+
self.outputs.update_from_array(y)
|
|
300
320
|
|
|
301
321
|
|
|
302
322
|
def solve(self, t, dt):
|
|
@@ -474,20 +494,54 @@ class MassMatrixDAE(Block):
|
|
|
474
494
|
)
|
|
475
495
|
self._x0 = x0
|
|
476
496
|
|
|
477
|
-
#partition into differential (nonzero
|
|
478
|
-
|
|
479
|
-
self._d = np.flatnonzero(
|
|
480
|
-
self._a = np.flatnonzero(~
|
|
497
|
+
#partition into differential (nonzero column) and algebraic (zero column) states
|
|
498
|
+
_nonzero_column = np.any(M != 0.0, axis=0)
|
|
499
|
+
self._d = np.flatnonzero(_nonzero_column)
|
|
500
|
+
self._a = np.flatnonzero(~_nonzero_column)
|
|
501
|
+
|
|
502
|
+
#partition into differential (nonzero row) and algebraic (zero row) equations
|
|
503
|
+
_non_zero_rows = np.any(M != 0.0, axis=1)
|
|
504
|
+
self._d_equations = np.flatnonzero(_non_zero_rows)
|
|
505
|
+
self._a_equations = np.flatnonzero(~_non_zero_rows)
|
|
481
506
|
|
|
482
507
|
#index-1 form: differential rows must not weight algebraic derivatives
|
|
483
|
-
if self._a.size and np.any(M[np.ix_(self.
|
|
508
|
+
if self._a.size and np.any(M[np.ix_(self._d_equations, self._a)] != 0.0):
|
|
484
509
|
raise ValueError(
|
|
485
510
|
"mass matrix is not in index-1 form: differential rows couple "
|
|
486
511
|
"to the derivatives of algebraic states"
|
|
487
512
|
)
|
|
488
513
|
|
|
489
|
-
#
|
|
490
|
-
|
|
514
|
+
#factorise the constant differential mass block when it is square; use
|
|
515
|
+
#the pseudoinverse for rectangular reduced systems so underdetermined
|
|
516
|
+
#differential blocks still admit a minimum-norm solution.
|
|
517
|
+
self._d_mass = M[np.ix_(self._d_equations, self._d)]
|
|
518
|
+
if self._d_mass.shape[0] == self._d_mass.shape[1]:
|
|
519
|
+
self._lu = lu_factor(self._d_mass)
|
|
520
|
+
self._solve_mass_rhs = lambda rhs: lu_solve(self._lu, rhs)
|
|
521
|
+
self._solve_mass_matrix = lambda mat: lu_solve(self._lu, mat)
|
|
522
|
+
else:
|
|
523
|
+
# Use SVD once and apply the pseudoinverse implicitly for stability
|
|
524
|
+
# and to avoid forming a dense pseudoinverse matrix.
|
|
525
|
+
U, s, Vt = np.linalg.svd(self._d_mass, full_matrices=False)
|
|
526
|
+
eps = np.finfo(float).eps
|
|
527
|
+
tol = max(self._d_mass.shape) * (s.max() if s.size else 0.0) * eps
|
|
528
|
+
s_inv = np.array([1.0/si if si > tol else 0.0 for si in s])
|
|
529
|
+
|
|
530
|
+
# store factors (optional) and set solver callables
|
|
531
|
+
self._svd_U = U
|
|
532
|
+
self._svd_s_inv = s_inv
|
|
533
|
+
self._svd_Vt = Vt
|
|
534
|
+
|
|
535
|
+
def _solve_mass_rhs(rhs):
|
|
536
|
+
# rhs can be vector or matrix; apply V * S_inv * (U.T @ rhs)
|
|
537
|
+
return (Vt.T * s_inv) @ (U.T @ rhs)
|
|
538
|
+
|
|
539
|
+
def _solve_mass_matrix(mat):
|
|
540
|
+
# mat: matrix of columns to be solved
|
|
541
|
+
return (Vt.T * s_inv) @ (U.T @ mat)
|
|
542
|
+
|
|
543
|
+
self._solve_mass_rhs = _solve_mass_rhs
|
|
544
|
+
self._solve_mass_matrix = _solve_mass_matrix
|
|
491
545
|
|
|
492
546
|
#the engine integrates only the differential states
|
|
493
547
|
self.initial_value = x0[self._d]
|
|
@@ -503,7 +557,9 @@ class MassMatrixDAE(Block):
|
|
|
503
557
|
#when 'jac' is given, otherwise the operator falls back to finite differences
|
|
504
558
|
_jac_x = None
|
|
505
559
|
if self._a.size == 0 and jac is not None:
|
|
506
|
-
_jac_x
|
|
560
|
+
def _jac_x(x, u, t):
|
|
561
|
+
J = np.atleast_2d(jac(x, u, t))[np.ix_(self._d_equations, self._d)]
|
|
562
|
+
return self._solve_mass_matrix(J)
|
|
507
563
|
self.op_dyn = DynamicOperator(func=self._rhs, jac_x=_jac_x)
|
|
508
564
|
|
|
509
565
|
#pre-size the output register to the full state
|
|
@@ -609,7 +665,7 @@ class MassMatrixDAE(Block):
|
|
|
609
665
|
xa = self._solve_xa(x_d, u, t)
|
|
610
666
|
x = np.empty(self.mass.shape[0])
|
|
611
667
|
x[self._d], x[self._a] = x_d, xa
|
|
612
|
-
return
|
|
668
|
+
return self._solve_mass_rhs(self.func(x, u, t)[self._d_equations])
|
|
613
669
|
|
|
614
670
|
|
|
615
671
|
def update(self, t):
|
|
@@ -646,7 +702,8 @@ class MassMatrixDAE(Block):
|
|
|
646
702
|
|
|
647
703
|
#commit the warm-start at the current state, then linearize around it
|
|
648
704
|
self._xa = self._solve_xa(x_d, u, t)
|
|
649
|
-
f =
|
|
705
|
+
f = self._solve_mass_rhs(self.func(self._full(x_d), u, t)[self._d_equations])
|
|
706
|
+
|
|
650
707
|
J = self.op_dyn.jac_x(x_d, u, t)
|
|
651
708
|
|
|
652
709
|
return self.engine.solve(f, J, dt)
|
|
@@ -673,7 +730,7 @@ class MassMatrixDAE(Block):
|
|
|
673
730
|
"""
|
|
674
731
|
x_d, u = self.engine.state, self.inputs.to_array()
|
|
675
732
|
self._xa = self._solve_xa(x_d, u, t)
|
|
676
|
-
f =
|
|
733
|
+
f = self._solve_mass_rhs(self.func(self._full(x_d), u, t)[self._d_equations])
|
|
677
734
|
return self.engine.step(f, dt)
|
|
678
735
|
|
|
679
736
|
|
|
@@ -2025,6 +2025,10 @@ class Simulation:
|
|
|
2025
2025
|
#main simulation loop
|
|
2026
2026
|
while self.time < end_time and self._active:
|
|
2027
2027
|
|
|
2028
|
+
if not _adaptive and np.isclose(
|
|
2029
|
+
self.time - start_time, duration, rtol=1e-12, atol=0.0):
|
|
2030
|
+
break
|
|
2031
|
+
|
|
2028
2032
|
#advance the simulation by one (effective) timestep '_dt'
|
|
2029
2033
|
try:
|
|
2030
2034
|
success, error_norm, scale, *_ = self.timestep(
|
|
@@ -331,19 +331,22 @@ class Graph:
|
|
|
331
331
|
"""Optimized loop processing with minimal overhead.
|
|
332
332
|
|
|
333
333
|
Finds strongly connected components (SCCs) within the loop blocks, determines
|
|
334
|
-
entry points for each SCC, and performs BFS to assign local depths.
|
|
334
|
+
entry points for each SCC, and performs BFS to assign local depths. Includes
|
|
335
|
+
acyclic descendants in dependency order alongside cycles. Identifies
|
|
335
336
|
loop-closing connections (back edges) that need special handling.
|
|
336
337
|
|
|
337
338
|
Parameters
|
|
338
339
|
----------
|
|
339
340
|
blocks_loop : set
|
|
340
|
-
set of blocks that are part of algebraic loops
|
|
341
|
+
set of blocks that are part of or depend on algebraic loops
|
|
341
342
|
"""
|
|
342
343
|
if not blocks_loop:
|
|
343
344
|
return
|
|
344
345
|
|
|
345
|
-
#
|
|
346
|
-
|
|
346
|
+
# Tarjan emits downstream components before their upstream dependencies.
|
|
347
|
+
# Reverse that order so each component receives updated upstream outputs
|
|
348
|
+
# before it is evaluated in the same loop-solver iteration.
|
|
349
|
+
sccs = reversed(self._find_strongly_connected_components(blocks_loop))
|
|
347
350
|
|
|
348
351
|
current_depth = 0
|
|
349
352
|
|
|
@@ -433,7 +436,7 @@ class Graph:
|
|
|
433
436
|
def _find_strongly_connected_components(self, blocks):
|
|
434
437
|
"""Iterative Tarjan's algorithm using cleaner state machine.
|
|
435
438
|
|
|
436
|
-
Finds strongly connected components
|
|
439
|
+
Finds all strongly connected components within the given blocks using
|
|
437
440
|
an iterative implementation of Tarjan's algorithm. Avoids recursion limits
|
|
438
441
|
that can occur with deep graphs.
|
|
439
442
|
|
|
@@ -445,7 +448,7 @@ class Graph:
|
|
|
445
448
|
Returns
|
|
446
449
|
-------
|
|
447
450
|
list
|
|
448
|
-
list of SCCs
|
|
451
|
+
list of SCCs in reverse topological order, including acyclic singletons
|
|
449
452
|
"""
|
|
450
453
|
if not blocks:
|
|
451
454
|
return []
|
|
@@ -508,11 +511,12 @@ class Graph:
|
|
|
508
511
|
if w == node:
|
|
509
512
|
break
|
|
510
513
|
|
|
511
|
-
#
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
514
|
+
# A block downstream of a loop can form a singleton SCC
|
|
515
|
+
# without being part of a cycle. Its loop dependency keeps
|
|
516
|
+
# it out of the ordinary DAG schedule, so discarding it here
|
|
517
|
+
# would leave it unevaluated. Keep it in the loop schedule;
|
|
518
|
+
# only actual cycle-closing connections receive acceleration.
|
|
519
|
+
result.append(scc)
|
|
516
520
|
|
|
517
521
|
# Update parent's lowlink if there is a parent
|
|
518
522
|
if work_stack:
|
|
@@ -141,10 +141,62 @@ class TestSemiExplicitDAE(unittest.TestCase):
|
|
|
141
141
|
info = SemiExplicitDAE.info()
|
|
142
142
|
self.assertEqual(info["type"], "SemiExplicitDAE")
|
|
143
143
|
for p in ("func_dyn", "func_alg", "initial_value", "z0", "jac_z",
|
|
144
|
-
"jac_dyn_x", "jac_dyn_z", "jac_alg_x", "tolerance"):
|
|
144
|
+
"jac_dyn_x", "jac_dyn_z", "jac_alg_x", "tolerance", "func_out"):
|
|
145
145
|
self.assertIn(p, info["parameters"])
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
def test_func_out(self):
|
|
149
|
+
#output function replaces the stacked state [x, z] at the output
|
|
150
|
+
dae = SemiExplicitDAE(
|
|
151
|
+
lambda x, z, u, t: -x + z, lambda x, z, u, t: z - x**2, 0.5, 0.25,
|
|
152
|
+
func_out=lambda x, z, u, t: np.array([x[0] + z[0]])
|
|
153
|
+
)
|
|
154
|
+
self.assertEqual(len(dae.outputs), 1)
|
|
155
|
+
|
|
156
|
+
dae.set_solver(ESDIRK43, None)
|
|
157
|
+
dae.update(0.0)
|
|
158
|
+
self.assertAlmostEqual(float(dae.outputs[0]), 0.5 + 0.25, places=8)
|
|
159
|
+
|
|
160
|
+
#reset keeps the output size of the output function
|
|
161
|
+
dae.reset()
|
|
162
|
+
self.assertEqual(len(dae.outputs), 1)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_no_algebraic_states(self):
|
|
166
|
+
#empty z reduces the block to a plain ODE without a constraint solve
|
|
167
|
+
calls = []
|
|
168
|
+
def f_alg(x, z, u, t):
|
|
169
|
+
calls.append(1)
|
|
170
|
+
return np.zeros(0)
|
|
171
|
+
|
|
172
|
+
dae = SemiExplicitDAE(
|
|
173
|
+
lambda x, z, u, t: -x, f_alg, initial_value=[1.0, 2.0], z0=np.zeros(0),
|
|
174
|
+
jac_z=lambda x, z, u, t: np.zeros((0, 0)),
|
|
175
|
+
jac_dyn_x=lambda x, z, u, t: -np.eye(2),
|
|
176
|
+
jac_dyn_z=lambda x, z, u, t: np.zeros((2, 0)),
|
|
177
|
+
jac_alg_x=lambda x, z, u, t: np.zeros((0, 2))
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
x, u = np.array([1.0, 2.0]), np.array([0.0])
|
|
181
|
+
self.assertEqual(dae._solve_z(x, u, 0.0).size, 0)
|
|
182
|
+
np.testing.assert_array_equal(dae.op_dyn.jac_x(x, u, 0.0), -np.eye(2))
|
|
183
|
+
self.assertEqual(len(calls), 0)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_simulation_no_algebraic_states(self):
|
|
187
|
+
#x' = -x with empty z integrates like the ODE block
|
|
188
|
+
from pathsim import Simulation
|
|
189
|
+
|
|
190
|
+
dae = SemiExplicitDAE(
|
|
191
|
+
lambda x, z, u, t: -x, lambda x, z, u, t: np.zeros(0),
|
|
192
|
+
initial_value=[1.0, 2.0], z0=np.zeros(0)
|
|
193
|
+
)
|
|
194
|
+
sim = Simulation(blocks=[dae], dt=0.01, Solver=ESDIRK43, log=False)
|
|
195
|
+
sim.run(1.0)
|
|
196
|
+
|
|
197
|
+
np.testing.assert_allclose(dae.engine.state, np.exp(-1.0)*np.array([1.0, 2.0]), rtol=1e-4)
|
|
198
|
+
|
|
199
|
+
|
|
148
200
|
def test_tolerance_default(self):
|
|
149
201
|
self.assertEqual(self._make_block().tolerance, SOL_TOLERANCE_FPI)
|
|
150
202
|
|
|
@@ -272,9 +324,6 @@ class TestMassMatrixDAE(unittest.TestCase):
|
|
|
272
324
|
MassMatrixDAE(func, np.ones((2, 3)), initial_value=[0.0, 0.0])
|
|
273
325
|
with self.assertRaises(ValueError):
|
|
274
326
|
MassMatrixDAE(func, np.eye(2), initial_value=[0.0])
|
|
275
|
-
M_bad = np.array([[1.0, 1.0], [0.0, 0.0]])
|
|
276
|
-
with self.assertRaises(ValueError):
|
|
277
|
-
MassMatrixDAE(func, M_bad, initial_value=[0.0, 0.0])
|
|
278
327
|
|
|
279
328
|
def test_passthrough(self):
|
|
280
329
|
dae_ns = MassMatrixDAE(lambda x, u, t: -x, np.eye(2), [1.0, 1.0])
|
|
@@ -293,6 +342,7 @@ class TestMassMatrixDAE(unittest.TestCase):
|
|
|
293
342
|
dae.reset()
|
|
294
343
|
np.testing.assert_array_equal(dae._xa, dae._x0[dae._a])
|
|
295
344
|
|
|
345
|
+
|
|
296
346
|
def test_info(self):
|
|
297
347
|
info = MassMatrixDAE.info()
|
|
298
348
|
self.assertEqual(info["type"], "MassMatrixDAE")
|
|
@@ -348,6 +398,21 @@ class TestMassMatrixDAE(unittest.TestCase):
|
|
|
348
398
|
sim.run(1.0)
|
|
349
399
|
self.assertAlmostEqual(float(dae.engine.state[0]), np.exp(-0.5), places=4)
|
|
350
400
|
|
|
401
|
+
def test_nonsymmetric_singular(self):
|
|
402
|
+
from pathsim import Simulation, Connection
|
|
403
|
+
from pathsim.blocks import Constant, Scope
|
|
404
|
+
M = np.array([[1.0, 1.0], [0.0, 0.0]])
|
|
405
|
+
func = lambda x, u, t: np.array([1., x[0] - x[1]])
|
|
406
|
+
dae = MassMatrixDAE(func, M, initial_value=[0.0, 0.0])
|
|
407
|
+
sco = Scope()
|
|
408
|
+
sim = Simulation(
|
|
409
|
+
blocks=[dae, sco],
|
|
410
|
+
connections=[Connection(dae[0], sco[0])],
|
|
411
|
+
dt=0.01, Solver=ESDIRK43, log=False
|
|
412
|
+
)
|
|
413
|
+
sim.run(1.0)
|
|
414
|
+
np.testing.assert_allclose(dae.outputs.to_array(), [0.5, 0.5], atol=1e-3)
|
|
415
|
+
|
|
351
416
|
def test_simulation_singular_with_input(self):
|
|
352
417
|
#x0' = -x0 + x1, 0 = x0 + x1 - u => steady state x -> u/2
|
|
353
418
|
from pathsim import Simulation, Connection
|
|
@@ -51,6 +51,78 @@ class TestSimulation(unittest.TestCase):
|
|
|
51
51
|
only very minimal functonality
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
+
def test_algebraic_loop_downstream_chain(self):
|
|
55
|
+
"""Evaluate acyclic descendants of a converged algebraic loop."""
|
|
56
|
+
a = Function(lambda b: 0.5 * b + 1)
|
|
57
|
+
b = Function(lambda a: 0.5 * a)
|
|
58
|
+
c = Function(lambda a: a + 10)
|
|
59
|
+
d = Function(lambda c: 2 * c)
|
|
60
|
+
simulation = Simulation(
|
|
61
|
+
blocks=[d, c, b, a],
|
|
62
|
+
connections=[
|
|
63
|
+
Connection(a, b), Connection(b, a),
|
|
64
|
+
Connection(a, c), Connection(c, d),
|
|
65
|
+
],
|
|
66
|
+
log=False,
|
|
67
|
+
)
|
|
68
|
+
simulation.run(0.01)
|
|
69
|
+
|
|
70
|
+
self.assertAlmostEqual(a.outputs[0], 4 / 3)
|
|
71
|
+
self.assertAlmostEqual(b.outputs[0], 2 / 3)
|
|
72
|
+
self.assertAlmostEqual(c.outputs[0], 4 / 3 + 10)
|
|
73
|
+
self.assertAlmostEqual(d.outputs[0], 2 * (4 / 3 + 10))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_algebraic_loop_downstream_merge(self):
|
|
77
|
+
"""Propagate both branches before evaluating their merged output."""
|
|
78
|
+
a = Function(lambda a: 0.5 * a + 1)
|
|
79
|
+
short = Function(lambda a: a + 10)
|
|
80
|
+
long = Function(lambda a: 3 * a)
|
|
81
|
+
end = Function(lambda value: value + 20)
|
|
82
|
+
merge = Adder()
|
|
83
|
+
simulation = Simulation(
|
|
84
|
+
blocks=[merge, end, long, short, a],
|
|
85
|
+
connections=[
|
|
86
|
+
Connection(a, a), Connection(a, short), Connection(a, long),
|
|
87
|
+
Connection(long, end),
|
|
88
|
+
Connection(short, merge[0]), Connection(end, merge[1]),
|
|
89
|
+
],
|
|
90
|
+
log=False,
|
|
91
|
+
)
|
|
92
|
+
simulation.run(0.01)
|
|
93
|
+
|
|
94
|
+
self.assertAlmostEqual(a.outputs[0], 2)
|
|
95
|
+
self.assertAlmostEqual(short.outputs[0], 12)
|
|
96
|
+
self.assertAlmostEqual(end.outputs[0], 26)
|
|
97
|
+
self.assertAlmostEqual(merge.outputs[0], 38)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_connected_algebraic_loops_with_downstream_blocks(self):
|
|
101
|
+
"""Evaluate a second feedback loop after its upstream loop and bridge."""
|
|
102
|
+
a = Function(lambda b: 0.5 * b + 1)
|
|
103
|
+
b = Function(lambda a: 0.5 * a)
|
|
104
|
+
bridge = Function(lambda a: a)
|
|
105
|
+
c = Function(lambda upstream, d: upstream + 0.5 * d)
|
|
106
|
+
d = Function(lambda c: 0.5 * c)
|
|
107
|
+
tail = Function(lambda c: c + 10)
|
|
108
|
+
simulation = Simulation(
|
|
109
|
+
blocks=[tail, d, c, bridge, b, a],
|
|
110
|
+
connections=[
|
|
111
|
+
Connection(a, b), Connection(b, a), Connection(a, bridge),
|
|
112
|
+
Connection(bridge, c[0]), Connection(c, d), Connection(d, c[1]),
|
|
113
|
+
Connection(c, tail),
|
|
114
|
+
],
|
|
115
|
+
log=False,
|
|
116
|
+
)
|
|
117
|
+
simulation.run(0.01)
|
|
118
|
+
|
|
119
|
+
self.assertAlmostEqual(a.outputs[0], 4 / 3)
|
|
120
|
+
self.assertAlmostEqual(bridge.outputs[0], 4 / 3)
|
|
121
|
+
self.assertAlmostEqual(c.outputs[0], 16 / 9)
|
|
122
|
+
self.assertAlmostEqual(d.outputs[0], 8 / 9)
|
|
123
|
+
self.assertAlmostEqual(tail.outputs[0], 16 / 9 + 10)
|
|
124
|
+
|
|
125
|
+
|
|
54
126
|
def test_init_default(self):
|
|
55
127
|
|
|
56
128
|
#test default initialization
|
|
@@ -324,10 +396,10 @@ class TestSimulation(unittest.TestCase):
|
|
|
324
396
|
stats = Sim.run(10)
|
|
325
397
|
|
|
326
398
|
#check stats
|
|
327
|
-
self.assertEqual(stats["total_steps"],
|
|
399
|
+
self.assertEqual(stats["total_steps"], 1000)
|
|
328
400
|
|
|
329
|
-
#check internal time progression
|
|
330
|
-
self.assertAlmostEqual(Sim.time, 10
|
|
401
|
+
#check internal time progression stops at the requested endpoint
|
|
402
|
+
self.assertAlmostEqual(Sim.time, 10.0)
|
|
331
403
|
|
|
332
404
|
|
|
333
405
|
|
|
@@ -480,6 +552,88 @@ class TestSimulationIVP(unittest.TestCase):
|
|
|
480
552
|
|
|
481
553
|
|
|
482
554
|
|
|
555
|
+
class TestSimulationRunBoundaries(unittest.TestCase):
|
|
556
|
+
|
|
557
|
+
def test_fixed_run_stops_at_aligned_endpoint(self):
|
|
558
|
+
for dt, duration, steps in [(0.1, 1.0, 10), (0.01, 10.0, 1000),
|
|
559
|
+
(0.2, 2.0, 10)]:
|
|
560
|
+
with self.subTest(dt=dt, duration=duration):
|
|
561
|
+
source = Constant(1.0)
|
|
562
|
+
integrator = Integrator()
|
|
563
|
+
scope = Scope()
|
|
564
|
+
simulation = Simulation(
|
|
565
|
+
[source, integrator, scope],
|
|
566
|
+
[Connection(source, integrator), Connection(integrator, scope)],
|
|
567
|
+
dt=dt, log=False
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
simulation.run(duration, adaptive=False)
|
|
571
|
+
|
|
572
|
+
self.assertAlmostEqual(simulation.time / duration, 1.0)
|
|
573
|
+
self.assertAlmostEqual(integrator.outputs[0] / duration, 1.0)
|
|
574
|
+
times, _ = scope.read()
|
|
575
|
+
self.assertEqual(len(times), steps + 1)
|
|
576
|
+
self.assertEqual(simulation.dt, dt)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def test_fixed_run_keeps_full_steps_for_non_aligned_endpoint(self):
|
|
580
|
+
for dt, duration, endpoint, steps in [(0.3, 1.0, 1.2, 4),
|
|
581
|
+
(2.0, 1.0, 2.0, 1),
|
|
582
|
+
(0.1, 0.05, 0.1, 1)]:
|
|
583
|
+
with self.subTest(dt=dt, duration=duration):
|
|
584
|
+
source = Constant(1.0)
|
|
585
|
+
integrator = Integrator()
|
|
586
|
+
scope = Scope()
|
|
587
|
+
simulation = Simulation(
|
|
588
|
+
[source, integrator, scope],
|
|
589
|
+
[Connection(source, integrator), Connection(integrator, scope)],
|
|
590
|
+
dt=dt, log=False
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
simulation.run(duration, adaptive=False)
|
|
594
|
+
|
|
595
|
+
self.assertAlmostEqual(simulation.time, endpoint)
|
|
596
|
+
self.assertAlmostEqual(integrator.outputs[0], endpoint)
|
|
597
|
+
times, _ = scope.read()
|
|
598
|
+
self.assertEqual(len(times), steps + 1)
|
|
599
|
+
self.assertEqual(simulation.dt, dt)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def test_streaming_run_stops_at_requested_endpoint(self):
|
|
603
|
+
simulation = Simulation(dt=0.1, log=False)
|
|
604
|
+
list(simulation.run_streaming(1.0, adaptive=False))
|
|
605
|
+
self.assertAlmostEqual(simulation.time, 1.0)
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def test_fixed_split_runs_match_single_run(self):
|
|
609
|
+
source = Constant(1.0)
|
|
610
|
+
integrator = Integrator()
|
|
611
|
+
ticks = []
|
|
612
|
+
|
|
613
|
+
def sample(time):
|
|
614
|
+
ticks.append(time)
|
|
615
|
+
source.value = 2.0 * integrator.outputs[0] + 1.0
|
|
616
|
+
|
|
617
|
+
simulation = Simulation(
|
|
618
|
+
[source, integrator], [Connection(source, integrator)],
|
|
619
|
+
events=[Schedule(t_start=0.0, t_period=1.0, func_act=sample)],
|
|
620
|
+
dt=0.1, log=False
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
simulation.run(1.0, adaptive=False)
|
|
624
|
+
self.assertAlmostEqual(simulation.time, 1.0)
|
|
625
|
+
simulation.run(1.0, adaptive=False)
|
|
626
|
+
self.assertAlmostEqual(simulation.time, 2.0)
|
|
627
|
+
self.assertEqual(ticks, [0.0, 1.0, 2.0])
|
|
628
|
+
split_output = integrator.outputs[0]
|
|
629
|
+
|
|
630
|
+
ticks.clear()
|
|
631
|
+
simulation.run(2.0, reset=True, adaptive=False)
|
|
632
|
+
self.assertAlmostEqual(simulation.time, 2.0)
|
|
633
|
+
self.assertEqual(ticks, [0.0, 1.0, 2.0])
|
|
634
|
+
self.assertAlmostEqual(integrator.outputs[0], split_output)
|
|
635
|
+
|
|
636
|
+
|
|
483
637
|
class TestSimulationEvents(unittest.TestCase):
|
|
484
638
|
"""Test event management and event handling during simulation"""
|
|
485
639
|
|