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.
Files changed (392) hide show
  1. {pathsim-0.26.0 → pathsim-0.27.1}/PKG-INFO +1 -1
  2. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/_version.py +3 -3
  3. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/dae.py +81 -24
  4. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/simulation.py +4 -0
  5. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/graph.py +15 -11
  6. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/PKG-INFO +1 -1
  7. pathsim-0.27.1/src/pathsim.egg-info/scm_version.json +8 -0
  8. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_dae.py +69 -4
  9. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_simulation.py +157 -3
  10. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_graph.py +67 -0
  11. pathsim-0.26.0/src/pathsim.egg-info/scm_version.json +0 -8
  12. {pathsim-0.26.0 → pathsim-0.27.1}/.codecov.yml +0 -0
  13. {pathsim-0.26.0 → pathsim-0.27.1}/.github/FUNDING.yml +0 -0
  14. {pathsim-0.26.0 → pathsim-0.27.1}/.github/pull_request_template.md +0 -0
  15. {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/pypi_deployment.yml +0 -0
  16. {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/tests_codecov.yml +0 -0
  17. {pathsim-0.26.0 → pathsim-0.27.1}/.github/workflows/urlchecker.yml +0 -0
  18. {pathsim-0.26.0 → pathsim-0.27.1}/.gitignore +0 -0
  19. {pathsim-0.26.0 → pathsim-0.27.1}/CITATION.cff +0 -0
  20. {pathsim-0.26.0 → pathsim-0.27.1}/CONTRIBUTING.md +0 -0
  21. {pathsim-0.26.0 → pathsim-0.27.1}/LICENSE.txt +0 -0
  22. {pathsim-0.26.0 → pathsim-0.27.1}/README.md +0 -0
  23. {pathsim-0.26.0 → pathsim-0.27.1}/conftest.py +0 -0
  24. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/abs_braking.ipynb +0 -0
  25. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/algebraic_loop.ipynb +0 -0
  26. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/billards.ipynb +0 -0
  27. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/bouncing_ball.ipynb +0 -0
  28. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/bouncing_pendulum.ipynb +0 -0
  29. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/cascade_controller.ipynb +0 -0
  30. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/checkpoints.ipynb +0 -0
  31. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/chemical_reactor.ipynb +0 -0
  32. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/coupled_oscillators.ipynb +0 -0
  33. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/BouncingBall_ME.fmu +0 -0
  34. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/CoupledClutches_CS_linux64.fmu +0 -0
  35. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/CoupledClutches_CS_win64.fmu +0 -0
  36. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/Dahlquist.fmu +0 -0
  37. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/data/VanDerPol_ME.fmu +0 -0
  38. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/dcmotor_control.ipynb +0 -0
  39. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/delta_sigma_adc.ipynb +0 -0
  40. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/diode_circuit.ipynb +0 -0
  41. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/elastic_pendulum.ipynb +0 -0
  42. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/algebraicloop_blockdiagram_g.png +0 -0
  43. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/billard_circle_g.png +0 -0
  44. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_blockdiagram_g.png +0 -0
  45. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_both_g.png +0 -0
  46. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_g.png +0 -0
  47. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_events_g.png +0 -0
  48. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_g.png +0 -0
  49. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_ball_result_timesteps_g.png +0 -0
  50. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/bouncing_pendulum_blockdiagram_g.png +0 -0
  51. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/cascade_blockdiagram_g.png +0 -0
  52. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/coupled_oscillators_blockdiagram_g.png +0 -0
  53. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/coupled_oscillators_g.png +0 -0
  54. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/delta_sigma_blockdiagram_g.png +0 -0
  55. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/diode_blockdiagram_g.png +0 -0
  56. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/elastic_pendulum_g.png +0 -0
  57. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/fmcw_blockdiagram_g.png +0 -0
  58. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/fmcw_g.png +0 -0
  59. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/harmonic_oscillator_g.png +0 -0
  60. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/harmonic_oscillator_result_g.png +0 -0
  61. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/kalman_filter_blockdiagram_g.png +0 -0
  62. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_blockdiagram_g.png +0 -0
  63. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_result_g.png +0 -0
  64. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/linear_feedback_result_sensitivity_g.png +0 -0
  65. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/miller_frequency_divider_blockdiagram_g.png +0 -0
  66. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/nonlinear_noisy_amplifier_blockdiagram_g.png +0 -0
  67. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/ode_blockdiagram_g.png +0 -0
  68. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/pendulum_blockdiagram_g.png +0 -0
  69. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/pid_blockdiagram_g.png +0 -0
  70. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/sar_adc_blockdiagram_g.png +0 -0
  71. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_g.png +0 -0
  72. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_slip_g.png +0 -0
  73. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_stick_g.png +0 -0
  74. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/stick_slip_g.png +0 -0
  75. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/thermostat_blockdiagram_g.png +0 -0
  76. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_blockdiagram_g.png +0 -0
  77. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_result_g.png +0 -0
  78. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_blockdiagram_g.png +0 -0
  79. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl1_g.png +0 -0
  80. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl2_g.png +0 -0
  81. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl3_g.png +0 -0
  82. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/figures_g/volterralotka_blockdiagram_g.png +0 -0
  83. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/ode_blockdiagram_2.png +0 -0
  84. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/stick_slip_blockdiagram_slip.png +0 -0
  85. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/figures/stick_slip_blockdiagram_stick.png +0 -0
  86. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmcw_radar.ipynb +0 -0
  87. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_cosimulation.ipynb +0 -0
  88. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_model_exchange_bouncing_ball.ipynb +0 -0
  89. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/fmu_model_exchange_vanderpol.ipynb +0 -0
  90. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/harmonic_oscillator.ipynb +0 -0
  91. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/kalman_filter.ipynb +0 -0
  92. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/linear_feedback.ipynb +0 -0
  93. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/lorenz_attractor.ipynb +0 -0
  94. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/nested_subsystems.ipynb +0 -0
  95. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/noisy_amplifier.ipynb +0 -0
  96. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/pendulum.ipynb +0 -0
  97. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/pid_controller.ipynb +0 -0
  98. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/poincare_maps.ipynb +0 -0
  99. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/rf_network_oneport.ipynb +0 -0
  100. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/sar_adc.ipynb +0 -0
  101. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/spectrum_analysis.ipynb +0 -0
  102. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/stick_slip.ipynb +0 -0
  103. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/switched_bouncing_ball.ipynb +0 -0
  104. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/thermostat.ipynb +0 -0
  105. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/transfer_function.ipynb +0 -0
  106. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/examples/vanderpol.ipynb +0 -0
  107. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_icon.png +0 -0
  108. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_logo.png +0 -0
  109. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/logos/pathsim_simplistic_logo.png +0 -0
  110. {pathsim-0.26.0 → pathsim-0.27.1}/docs/source/pathsim_docs.mplstyle +0 -0
  111. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_abs_braking.py +0 -0
  112. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_adc.py +0 -0
  113. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_algebraicchain.py +0 -0
  114. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_algebraicloop.py +0 -0
  115. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_cascade.py +0 -0
  116. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_dcmotor.py +0 -0
  117. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_deltasigma.py +0 -0
  118. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_derivative.py +0 -0
  119. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_diode.py +0 -0
  120. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_dualslope.py +0 -0
  121. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_elastic_pendulum.py +0 -0
  122. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_feedback.py +0 -0
  123. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_filters.py +0 -0
  124. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_harmonic_oscillator.py +0 -0
  125. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_kalman_filter.py +0 -0
  126. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_nested_subsystems.py +0 -0
  127. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_noise.py +0 -0
  128. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pendulum.py +0 -0
  129. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_phasenoise.py +0 -0
  130. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid.py +0 -0
  131. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid_antiwindup.py +0 -0
  132. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_pid_vs_discretePID.py +0 -0
  133. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_radar.py +0 -0
  134. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_reactor.py +0 -0
  135. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_sar.py +0 -0
  136. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_solar.py +0 -0
  137. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_solver_hotswap.py +0 -0
  138. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_spectrum.py +0 -0
  139. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_spectrum_rf_oneport.py +0 -0
  140. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_steadystate.py +0 -0
  141. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_stickslip.py +0 -0
  142. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_transferfunction.py +0 -0
  143. {pathsim-0.26.0 → pathsim-0.27.1}/examples/example_vanderpol_subsystem.py +0 -0
  144. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_billards_sphere.py +0 -0
  145. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncing_pendulum.py +0 -0
  146. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball.py +0 -0
  147. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball_friction.py +0 -0
  148. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_bouncingball_switched.py +0 -0
  149. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_integrator_reset.py +0 -0
  150. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_pulse.py +0 -0
  151. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_stickslip_event.py +0 -0
  152. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_thermostat.py +0 -0
  153. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_event/example_volterralotka_event.py +0 -0
  154. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_bonhoeffer_vanderpol.py +0 -0
  155. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_brusselator.py +0 -0
  156. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_chemical.py +0 -0
  157. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_duffing.py +0 -0
  158. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_fairen_velarde.py +0 -0
  159. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_fitzhughnagumo.py +0 -0
  160. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_flame.py +0 -0
  161. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_glycolysis.py +0 -0
  162. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_lorenz.py +0 -0
  163. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_morse.py +0 -0
  164. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_robertson.py +0 -0
  165. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_roessler.py +0 -0
  166. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_thomas_cyclic.py +0 -0
  167. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_vanderpol.py +0 -0
  168. {pathsim-0.26.0 → pathsim-0.27.1}/examples/examples_odes/example_volterralotka.py +0 -0
  169. {pathsim-0.26.0 → pathsim-0.27.1}/git +0 -0
  170. {pathsim-0.26.0 → pathsim-0.27.1}/pyproject.toml +0 -0
  171. {pathsim-0.26.0 → pathsim-0.27.1}/setup.cfg +0 -0
  172. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/__init__.py +0 -0
  173. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/_constants.py +0 -0
  174. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/README.md +0 -0
  175. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/__init__.py +0 -0
  176. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/_block.py +0 -0
  177. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/adder.py +0 -0
  178. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/amplifier.py +0 -0
  179. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/bvp.py +0 -0
  180. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/comparator.py +0 -0
  181. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/constraint.py +0 -0
  182. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/converters.py +0 -0
  183. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/counter.py +0 -0
  184. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/ctrl.py +0 -0
  185. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/delay.py +0 -0
  186. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/differentiator.py +0 -0
  187. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/discrete.py +0 -0
  188. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/divider.py +0 -0
  189. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/dynsys.py +0 -0
  190. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/filters.py +0 -0
  191. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/fmu.py +0 -0
  192. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/function.py +0 -0
  193. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/integrator.py +0 -0
  194. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/kalman.py +0 -0
  195. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/logic.py +0 -0
  196. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/lti.py +0 -0
  197. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/math.py +0 -0
  198. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/multiplier.py +0 -0
  199. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/noise.py +0 -0
  200. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/ode.py +0 -0
  201. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/relay.py +0 -0
  202. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/rf.py +0 -0
  203. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/rng.py +0 -0
  204. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/scope.py +0 -0
  205. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/sources.py +0 -0
  206. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/spectrum.py +0 -0
  207. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/switch.py +0 -0
  208. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/table.py +0 -0
  209. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/blocks/wrapper.py +0 -0
  210. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/connection.py +0 -0
  211. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/__init__.py +0 -0
  212. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/_event.py +0 -0
  213. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/condition.py +0 -0
  214. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/schedule.py +0 -0
  215. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/events/zerocrossing.py +0 -0
  216. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/exceptions.py +0 -0
  217. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/__init__.py +0 -0
  218. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/anderson.py +0 -0
  219. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/booster.py +0 -0
  220. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/linearization.py +0 -0
  221. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/newton.py +0 -0
  222. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/numerical.py +0 -0
  223. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/optim/operator.py +0 -0
  224. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/README.md +0 -0
  225. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/__init__.py +0 -0
  226. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/_rungekutta.py +0 -0
  227. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/_solver.py +0 -0
  228. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/bdf.py +0 -0
  229. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/dirk2.py +0 -0
  230. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/dirk3.py +0 -0
  231. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk32.py +0 -0
  232. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk4.py +0 -0
  233. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk43.py +0 -0
  234. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk54.py +0 -0
  235. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/esdirk85.py +0 -0
  236. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/euler.py +0 -0
  237. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/gear.py +0 -0
  238. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rk4.py +0 -0
  239. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkbs32.py +0 -0
  240. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkck54.py +0 -0
  241. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkdp54.py +0 -0
  242. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkdp87.py +0 -0
  243. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf21.py +0 -0
  244. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf45.py +0 -0
  245. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkf78.py +0 -0
  246. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/rkv65.py +0 -0
  247. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk22.py +0 -0
  248. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk33.py +0 -0
  249. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/ssprk34.py +0 -0
  250. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/solvers/steadystate.py +0 -0
  251. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/subsystem.py +0 -0
  252. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/__init__.py +0 -0
  253. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/adaptivebuffer.py +0 -0
  254. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/analysis.py +0 -0
  255. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/deprecation.py +0 -0
  256. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/diagnostics.py +0 -0
  257. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/fmuwrapper.py +0 -0
  258. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/gilbert.py +0 -0
  259. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/logger.py +0 -0
  260. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/mutable.py +0 -0
  261. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/portreference.py +0 -0
  262. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/progresstracker.py +0 -0
  263. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/realtimeplotter.py +0 -0
  264. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim/utils/register.py +0 -0
  265. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/SOURCES.txt +0 -0
  266. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/dependency_links.txt +0 -0
  267. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/requires.txt +0 -0
  268. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/scm_file_list.json +0 -0
  269. {pathsim-0.26.0 → pathsim-0.27.1}/src/pathsim.egg-info/top_level.txt +0 -0
  270. {pathsim-0.26.0 → pathsim-0.27.1}/tests/README.md +0 -0
  271. {pathsim-0.26.0 → pathsim-0.27.1}/tests/__init__.py +0 -0
  272. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/CoupledClutches_CS.fmu +0 -0
  273. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/__init__.py +0 -0
  274. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/conftest.py +0 -0
  275. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_algebraic_system.py +0 -0
  276. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_bouncingball_friction_event_system.py +0 -0
  277. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_bouncingball_system.py +0 -0
  278. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_brusselator_system.py +0 -0
  279. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_cosim_fmu_system.py +0 -0
  280. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_counter_comparator_system.py +0 -0
  281. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_dynamical_system_ivp.py +0 -0
  282. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_fitzhughnagumo_system.py +0 -0
  283. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_harmonic_oscillator_system.py +0 -0
  284. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_linear_feedback_system.py +0 -0
  285. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_logic_system.py +0 -0
  286. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_lorenz_system.py +0 -0
  287. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_me_analytical.py +0 -0
  288. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_model_exchange_fmu_system.py +0 -0
  289. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_pid_system.py +0 -0
  290. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_relay_thermostat_system.py +0 -0
  291. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_rescale_delay_system.py +0 -0
  292. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_robertson_system.py +0 -0
  293. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_roessler_system.py +0 -0
  294. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_signal_processing_system.py +0 -0
  295. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_steadystate_transient_system.py +0 -0
  296. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_switch_lti_system.py +0 -0
  297. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_vanderpol_system.py +0 -0
  298. {pathsim-0.26.0 → pathsim-0.27.1}/tests/evals/test_volterralotka_system.py +0 -0
  299. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/__init__.py +0 -0
  300. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/__init__.py +0 -0
  301. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/_embedding.py +0 -0
  302. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/__init__.py +0 -0
  303. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/ring_slot.s2p +0 -0
  304. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/ring_slot_meas.s1p +0 -0
  305. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/rf/test_rf.py +0 -0
  306. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_adder.py +0 -0
  307. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_amplifier.py +0 -0
  308. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_block.py +0 -0
  309. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_bvp.py +0 -0
  310. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_comparator.py +0 -0
  311. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_constraint.py +0 -0
  312. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_converters.py +0 -0
  313. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_counter.py +0 -0
  314. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_ctrl.py +0 -0
  315. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_delay.py +0 -0
  316. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_differentiator.py +0 -0
  317. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_discrete.py +0 -0
  318. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_divider.py +0 -0
  319. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_dynsys.py +0 -0
  320. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_filters.py +0 -0
  321. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_fmu.py +0 -0
  322. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_function.py +0 -0
  323. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_integrator.py +0 -0
  324. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_kalman.py +0 -0
  325. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_logic.py +0 -0
  326. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_lti.py +0 -0
  327. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_math.py +0 -0
  328. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_multiplier.py +0 -0
  329. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_noise.py +0 -0
  330. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_ode.py +0 -0
  331. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_relay.py +0 -0
  332. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_rng.py +0 -0
  333. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_scope.py +0 -0
  334. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_sources.py +0 -0
  335. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_spectrum.py +0 -0
  336. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_switch.py +0 -0
  337. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_table.py +0 -0
  338. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/blocks/test_wrapper.py +0 -0
  339. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/__init__.py +0 -0
  340. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_condition.py +0 -0
  341. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_event.py +0 -0
  342. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_schedule.py +0 -0
  343. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/events/test_zerocrossing.py +0 -0
  344. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/__init__.py +0 -0
  345. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_anderson.py +0 -0
  346. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_linearization.py +0 -0
  347. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_newton.py +0 -0
  348. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_numerical.py +0 -0
  349. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/optim/test_operator.py +0 -0
  350. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/__init__.py +0 -0
  351. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/_referenceproblems.py +0 -0
  352. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_bdf.py +0 -0
  353. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_dirk2.py +0 -0
  354. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_dirk3.py +0 -0
  355. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk32.py +0 -0
  356. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk4.py +0 -0
  357. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk43.py +0 -0
  358. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk54.py +0 -0
  359. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_esdirk85.py +0 -0
  360. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_euler.py +0 -0
  361. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_gear.py +0 -0
  362. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rfk21.py +0 -0
  363. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rk4.py +0 -0
  364. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkbs32.py +0 -0
  365. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkck54.py +0 -0
  366. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkdp54.py +0 -0
  367. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkdp87.py +0 -0
  368. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkf45.py +0 -0
  369. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkf78.py +0 -0
  370. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_rkv65.py +0 -0
  371. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_solver.py +0 -0
  372. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk22.py +0 -0
  373. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk33.py +0 -0
  374. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_ssprk34.py +0 -0
  375. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/solvers/test_steadystate.py +0 -0
  376. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_auto_initial_step.py +0 -0
  377. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_checkpoint.py +0 -0
  378. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_connection.py +0 -0
  379. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_diagnostics.py +0 -0
  380. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_simulation_pss.py +0 -0
  381. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/test_subsystem.py +0 -0
  382. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/__init__.py +0 -0
  383. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_adaptivebuffer.py +0 -0
  384. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_analysis.py +0 -0
  385. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_fmuwrapper.py +0 -0
  386. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_gilbert.py +0 -0
  387. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_logger.py +0 -0
  388. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_mutable.py +0 -0
  389. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_portreference.py +0 -0
  390. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_progresstracker.py +0 -0
  391. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_realtimeplotter.py +0 -0
  392. {pathsim-0.26.0 → pathsim-0.27.1}/tests/pathsim/utils/test_register.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pathsim
3
- Version: 0.26.0
3
+ Version: 0.27.1
4
4
  Summary: A differentiable block based hybrid system simulation framework.
5
5
  Author-email: Milan Rother <milan.rother@gmx.de>
6
6
  License: MIT
@@ -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.26.0'
22
- __version_tuple__ = version_tuple = (0, 26, 0)
21
+ __version__ = version = '0.27.1'
22
+ __version_tuple__ = version_tuple = (0, 27, 1)
23
23
 
24
- __commit_id__ = commit_id = 'g7c5a82fa9'
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.outputs.update_from_array(
191
- np.concatenate([self.initial_value, self.z0])
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
- x = self.engine.state if self.engine else self.initial_value
208
- self.outputs.update_from_array(
209
- np.concatenate([np.atleast_1d(x), self._z])
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.outputs.update_from_array(
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 row) and algebraic (zero row) states
478
- _nonzero_row = np.any(M != 0.0, axis=1)
479
- self._d = np.flatnonzero(_nonzero_row)
480
- self._a = np.flatnonzero(~_nonzero_row)
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._d, self._a)] != 0.0):
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
- #LU factorisation of the (constant) differential mass block
490
- self._lu = lu_factor(M[np.ix_(self._d, self._d)])
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 = lambda x, u, t: lu_solve(self._lu, np.atleast_2d(jac(x, u, t)))
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 lu_solve(self._lu, self.func(x, u, t)[self._d])
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 = lu_solve(self._lu, self.func(self._full(x_d), u, t)[self._d])
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 = lu_solve(self._lu, self.func(self._full(x_d), u, t)[self._d])
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. Identifies
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
- # Find SCCs (already optimized)
346
- sccs = self._find_strongly_connected_components(blocks_loop)
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 (cycles) within the given blocks using
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, where each SCC is a list of blocks forming a cycle
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
- # Keep only actual cycles
512
- if len(scc) > 1:
513
- result.append(scc)
514
- elif scc[0] in successors_cache[scc[0]]:
515
- result.append(scc)
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pathsim
3
- Version: 0.26.0
3
+ Version: 0.27.1
4
4
  Summary: A differentiable block based hybrid system simulation framework.
5
5
  Author-email: Milan Rother <milan.rother@gmx.de>
6
6
  License: MIT
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.27.1",
3
+ "distance": 0,
4
+ "node": "ga4e824de226c5a76509d6163b3c1e33445861144",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-12"
8
+ }
@@ -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"], 1001)
399
+ self.assertEqual(stats["total_steps"], 1000)
328
400
 
329
- #check internal time progression (fixed step solvers naturally overshoot)
330
- self.assertAlmostEqual(Sim.time, 10, 1)
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