pathsim 0.28.0__tar.gz → 0.29.0__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 (403) hide show
  1. {pathsim-0.28.0 → pathsim-0.29.0}/PKG-INFO +1 -1
  2. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/__init__.py +1 -0
  3. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/_version.py +3 -3
  4. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/__init__.py +1 -0
  5. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/_block.py +2 -34
  6. pathsim-0.29.0/src/pathsim/blocks/splitter.py +124 -0
  7. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/connection.py +31 -9
  8. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/linearization.py +24 -8
  9. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/simulation.py +24 -23
  10. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/subsystem.py +10 -1
  11. pathsim-0.29.0/src/pathsim/utils/carrier.py +213 -0
  12. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/graph.py +7 -4
  13. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/portreference.py +34 -10
  14. pathsim-0.29.0/src/pathsim/utils/register.py +298 -0
  15. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/PKG-INFO +1 -1
  16. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/SOURCES.txt +6 -0
  17. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/scm_file_list.json +6 -0
  18. pathsim-0.29.0/src/pathsim.egg-info/scm_version.json +8 -0
  19. pathsim-0.29.0/tests/pathsim/blocks/test_splitter.py +154 -0
  20. pathsim-0.29.0/tests/pathsim/test_simulation_steadystate_recovery.py +94 -0
  21. pathsim-0.29.0/tests/pathsim/test_subsystem_current_inputs.py +63 -0
  22. pathsim-0.29.0/tests/pathsim/utils/test_carrier.py +365 -0
  23. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_register.py +19 -0
  24. pathsim-0.28.0/src/pathsim/utils/register.py +0 -190
  25. pathsim-0.28.0/src/pathsim.egg-info/scm_version.json +0 -8
  26. {pathsim-0.28.0 → pathsim-0.29.0}/.codecov.yml +0 -0
  27. {pathsim-0.28.0 → pathsim-0.29.0}/.github/FUNDING.yml +0 -0
  28. {pathsim-0.28.0 → pathsim-0.29.0}/.github/pull_request_template.md +0 -0
  29. {pathsim-0.28.0 → pathsim-0.29.0}/.github/workflows/pypi_deployment.yml +0 -0
  30. {pathsim-0.28.0 → pathsim-0.29.0}/.github/workflows/tests_codecov.yml +0 -0
  31. {pathsim-0.28.0 → pathsim-0.29.0}/.github/workflows/urlchecker.yml +0 -0
  32. {pathsim-0.28.0 → pathsim-0.29.0}/.gitignore +0 -0
  33. {pathsim-0.28.0 → pathsim-0.29.0}/CITATION.cff +0 -0
  34. {pathsim-0.28.0 → pathsim-0.29.0}/CONTRIBUTING.md +0 -0
  35. {pathsim-0.28.0 → pathsim-0.29.0}/LICENSE.txt +0 -0
  36. {pathsim-0.28.0 → pathsim-0.29.0}/README.md +0 -0
  37. {pathsim-0.28.0 → pathsim-0.29.0}/conftest.py +0 -0
  38. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/abs_braking.ipynb +0 -0
  39. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/algebraic_loop.ipynb +0 -0
  40. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/billards.ipynb +0 -0
  41. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/bouncing_ball.ipynb +0 -0
  42. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/bouncing_pendulum.ipynb +0 -0
  43. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/cascade_controller.ipynb +0 -0
  44. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/checkpoints.ipynb +0 -0
  45. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/chemical_reactor.ipynb +0 -0
  46. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/coupled_oscillators.ipynb +0 -0
  47. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/data/BouncingBall_ME.fmu +0 -0
  48. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/data/CoupledClutches_CS_linux64.fmu +0 -0
  49. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/data/CoupledClutches_CS_win64.fmu +0 -0
  50. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/data/Dahlquist.fmu +0 -0
  51. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/data/VanDerPol_ME.fmu +0 -0
  52. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/dcmotor_control.ipynb +0 -0
  53. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/delta_sigma_adc.ipynb +0 -0
  54. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/diode_circuit.ipynb +0 -0
  55. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/elastic_pendulum.ipynb +0 -0
  56. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/algebraicloop_blockdiagram_g.png +0 -0
  57. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/billard_circle_g.png +0 -0
  58. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_blockdiagram_g.png +0 -0
  59. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_both_g.png +0 -0
  60. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_g.png +0 -0
  61. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_result_events_g.png +0 -0
  62. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_result_g.png +0 -0
  63. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_ball_result_timesteps_g.png +0 -0
  64. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/bouncing_pendulum_blockdiagram_g.png +0 -0
  65. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/cascade_blockdiagram_g.png +0 -0
  66. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/coupled_oscillators_blockdiagram_g.png +0 -0
  67. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/coupled_oscillators_g.png +0 -0
  68. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/delta_sigma_blockdiagram_g.png +0 -0
  69. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/diode_blockdiagram_g.png +0 -0
  70. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/elastic_pendulum_g.png +0 -0
  71. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/fmcw_blockdiagram_g.png +0 -0
  72. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/fmcw_g.png +0 -0
  73. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/harmonic_oscillator_g.png +0 -0
  74. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/harmonic_oscillator_result_g.png +0 -0
  75. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/kalman_filter_blockdiagram_g.png +0 -0
  76. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/linear_feedback_blockdiagram_g.png +0 -0
  77. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/linear_feedback_result_g.png +0 -0
  78. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/linear_feedback_result_sensitivity_g.png +0 -0
  79. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/miller_frequency_divider_blockdiagram_g.png +0 -0
  80. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/nonlinear_noisy_amplifier_blockdiagram_g.png +0 -0
  81. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/ode_blockdiagram_g.png +0 -0
  82. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/pendulum_blockdiagram_g.png +0 -0
  83. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/pid_blockdiagram_g.png +0 -0
  84. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/sar_adc_blockdiagram_g.png +0 -0
  85. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_g.png +0 -0
  86. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_slip_g.png +0 -0
  87. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/stick_slip_blockdiagram_stick_g.png +0 -0
  88. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/stick_slip_g.png +0 -0
  89. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/thermostat_blockdiagram_g.png +0 -0
  90. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_blockdiagram_g.png +0 -0
  91. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_result_g.png +0 -0
  92. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_subsystem_blockdiagram_g.png +0 -0
  93. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl1_g.png +0 -0
  94. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl2_g.png +0 -0
  95. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/vanderpol_subsystem_lvl3_g.png +0 -0
  96. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/figures_g/volterralotka_blockdiagram_g.png +0 -0
  97. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/ode_blockdiagram_2.png +0 -0
  98. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/stick_slip_blockdiagram_slip.png +0 -0
  99. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/figures/stick_slip_blockdiagram_stick.png +0 -0
  100. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/fmcw_radar.ipynb +0 -0
  101. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/fmu_cosimulation.ipynb +0 -0
  102. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/fmu_model_exchange_bouncing_ball.ipynb +0 -0
  103. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/fmu_model_exchange_vanderpol.ipynb +0 -0
  104. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/harmonic_oscillator.ipynb +0 -0
  105. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/kalman_filter.ipynb +0 -0
  106. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/linear_feedback.ipynb +0 -0
  107. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/lorenz_attractor.ipynb +0 -0
  108. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/nested_subsystems.ipynb +0 -0
  109. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/noisy_amplifier.ipynb +0 -0
  110. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/pendulum.ipynb +0 -0
  111. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/pid_controller.ipynb +0 -0
  112. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/poincare_maps.ipynb +0 -0
  113. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/rf_network_oneport.ipynb +0 -0
  114. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/sar_adc.ipynb +0 -0
  115. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/spectrum_analysis.ipynb +0 -0
  116. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/stick_slip.ipynb +0 -0
  117. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/switched_bouncing_ball.ipynb +0 -0
  118. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/thermostat.ipynb +0 -0
  119. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/transfer_function.ipynb +0 -0
  120. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/examples/vanderpol.ipynb +0 -0
  121. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/logos/pathsim_icon.png +0 -0
  122. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/logos/pathsim_logo.png +0 -0
  123. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/logos/pathsim_simplistic_logo.png +0 -0
  124. {pathsim-0.28.0 → pathsim-0.29.0}/docs/source/pathsim_docs.mplstyle +0 -0
  125. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_abs_braking.py +0 -0
  126. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_adc.py +0 -0
  127. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_algebraicchain.py +0 -0
  128. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_algebraicloop.py +0 -0
  129. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_cascade.py +0 -0
  130. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_dcmotor.py +0 -0
  131. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_deltasigma.py +0 -0
  132. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_derivative.py +0 -0
  133. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_diode.py +0 -0
  134. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_dualslope.py +0 -0
  135. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_elastic_pendulum.py +0 -0
  136. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_feedback.py +0 -0
  137. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_filters.py +0 -0
  138. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_harmonic_oscillator.py +0 -0
  139. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_kalman_filter.py +0 -0
  140. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_nested_subsystems.py +0 -0
  141. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_noise.py +0 -0
  142. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_pendulum.py +0 -0
  143. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_phasenoise.py +0 -0
  144. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_pid.py +0 -0
  145. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_pid_antiwindup.py +0 -0
  146. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_pid_vs_discretePID.py +0 -0
  147. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_radar.py +0 -0
  148. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_reactor.py +0 -0
  149. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_sar.py +0 -0
  150. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_solar.py +0 -0
  151. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_solver_hotswap.py +0 -0
  152. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_spectrum.py +0 -0
  153. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_spectrum_rf_oneport.py +0 -0
  154. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_steadystate.py +0 -0
  155. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_stickslip.py +0 -0
  156. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_transferfunction.py +0 -0
  157. {pathsim-0.28.0 → pathsim-0.29.0}/examples/example_vanderpol_subsystem.py +0 -0
  158. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_billards_sphere.py +0 -0
  159. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_bouncing_pendulum.py +0 -0
  160. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_bouncingball.py +0 -0
  161. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_bouncingball_friction.py +0 -0
  162. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_bouncingball_switched.py +0 -0
  163. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_integrator_reset.py +0 -0
  164. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_pulse.py +0 -0
  165. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_stickslip_event.py +0 -0
  166. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_thermostat.py +0 -0
  167. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_event/example_volterralotka_event.py +0 -0
  168. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_bonhoeffer_vanderpol.py +0 -0
  169. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_brusselator.py +0 -0
  170. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_chemical.py +0 -0
  171. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_duffing.py +0 -0
  172. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_fairen_velarde.py +0 -0
  173. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_fitzhughnagumo.py +0 -0
  174. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_flame.py +0 -0
  175. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_glycolysis.py +0 -0
  176. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_lorenz.py +0 -0
  177. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_morse.py +0 -0
  178. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_robertson.py +0 -0
  179. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_roessler.py +0 -0
  180. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_thomas_cyclic.py +0 -0
  181. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_vanderpol.py +0 -0
  182. {pathsim-0.28.0 → pathsim-0.29.0}/examples/examples_odes/example_volterralotka.py +0 -0
  183. {pathsim-0.28.0 → pathsim-0.29.0}/git +0 -0
  184. {pathsim-0.28.0 → pathsim-0.29.0}/pyproject.toml +0 -0
  185. {pathsim-0.28.0 → pathsim-0.29.0}/setup.cfg +0 -0
  186. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/_constants.py +0 -0
  187. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/README.md +0 -0
  188. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/adder.py +0 -0
  189. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/amplifier.py +0 -0
  190. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/bvp.py +0 -0
  191. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/comparator.py +0 -0
  192. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/constraint.py +0 -0
  193. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/converters.py +0 -0
  194. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/counter.py +0 -0
  195. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/ctrl.py +0 -0
  196. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/dae.py +0 -0
  197. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/delay.py +0 -0
  198. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/differentiator.py +0 -0
  199. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/discrete.py +0 -0
  200. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/divider.py +0 -0
  201. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/dynsys.py +0 -0
  202. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/filters.py +0 -0
  203. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/fmu.py +0 -0
  204. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/function.py +0 -0
  205. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/integrator.py +0 -0
  206. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/kalman.py +0 -0
  207. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/logic.py +0 -0
  208. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/lti.py +0 -0
  209. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/math.py +0 -0
  210. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/multiplier.py +0 -0
  211. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/noise.py +0 -0
  212. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/ode.py +0 -0
  213. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/relay.py +0 -0
  214. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/rf.py +0 -0
  215. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/rng.py +0 -0
  216. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/scope.py +0 -0
  217. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/sources.py +0 -0
  218. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/spectrum.py +0 -0
  219. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/switch.py +0 -0
  220. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/table.py +0 -0
  221. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/blocks/wrapper.py +0 -0
  222. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/events/__init__.py +0 -0
  223. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/events/_event.py +0 -0
  224. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/events/condition.py +0 -0
  225. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/events/schedule.py +0 -0
  226. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/events/zerocrossing.py +0 -0
  227. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/exceptions.py +0 -0
  228. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/__init__.py +0 -0
  229. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/anderson.py +0 -0
  230. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/booster.py +0 -0
  231. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/jacobian.py +0 -0
  232. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/newton.py +0 -0
  233. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/numerical.py +0 -0
  234. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/optim/operator.py +0 -0
  235. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/README.md +0 -0
  236. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/__init__.py +0 -0
  237. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/_rungekutta.py +0 -0
  238. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/_solver.py +0 -0
  239. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/bdf.py +0 -0
  240. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/dirk2.py +0 -0
  241. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/dirk3.py +0 -0
  242. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/esdirk32.py +0 -0
  243. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/esdirk4.py +0 -0
  244. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/esdirk43.py +0 -0
  245. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/esdirk54.py +0 -0
  246. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/esdirk85.py +0 -0
  247. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/euler.py +0 -0
  248. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/gear.py +0 -0
  249. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rk4.py +0 -0
  250. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkbs32.py +0 -0
  251. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkck54.py +0 -0
  252. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkdp54.py +0 -0
  253. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkdp87.py +0 -0
  254. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkf21.py +0 -0
  255. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkf45.py +0 -0
  256. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkf78.py +0 -0
  257. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/rkv65.py +0 -0
  258. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/ssprk22.py +0 -0
  259. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/ssprk33.py +0 -0
  260. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/ssprk34.py +0 -0
  261. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/solvers/steadystate.py +0 -0
  262. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/__init__.py +0 -0
  263. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/adaptivebuffer.py +0 -0
  264. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/analysis.py +0 -0
  265. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/deprecation.py +0 -0
  266. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/diagnostics.py +0 -0
  267. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/fmuwrapper.py +0 -0
  268. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/gilbert.py +0 -0
  269. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/logger.py +0 -0
  270. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/mutable.py +0 -0
  271. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/progresstracker.py +0 -0
  272. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim/utils/realtimeplotter.py +0 -0
  273. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/dependency_links.txt +0 -0
  274. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/requires.txt +0 -0
  275. {pathsim-0.28.0 → pathsim-0.29.0}/src/pathsim.egg-info/top_level.txt +0 -0
  276. {pathsim-0.28.0 → pathsim-0.29.0}/tests/README.md +0 -0
  277. {pathsim-0.28.0 → pathsim-0.29.0}/tests/__init__.py +0 -0
  278. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/CoupledClutches_CS.fmu +0 -0
  279. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/__init__.py +0 -0
  280. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/conftest.py +0 -0
  281. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_algebraic_system.py +0 -0
  282. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_bouncingball_friction_event_system.py +0 -0
  283. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_bouncingball_system.py +0 -0
  284. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_brusselator_system.py +0 -0
  285. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_cosim_fmu_system.py +0 -0
  286. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_counter_comparator_system.py +0 -0
  287. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_dynamical_system_ivp.py +0 -0
  288. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_fitzhughnagumo_system.py +0 -0
  289. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_harmonic_oscillator_system.py +0 -0
  290. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_linear_feedback_system.py +0 -0
  291. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_logic_system.py +0 -0
  292. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_lorenz_system.py +0 -0
  293. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_me_analytical.py +0 -0
  294. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_model_exchange_fmu_system.py +0 -0
  295. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_pid_system.py +0 -0
  296. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_relay_thermostat_system.py +0 -0
  297. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_rescale_delay_system.py +0 -0
  298. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_robertson_system.py +0 -0
  299. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_roessler_system.py +0 -0
  300. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_signal_processing_system.py +0 -0
  301. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_steadystate_transient_system.py +0 -0
  302. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_switch_lti_system.py +0 -0
  303. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_vanderpol_system.py +0 -0
  304. {pathsim-0.28.0 → pathsim-0.29.0}/tests/evals/test_volterralotka_system.py +0 -0
  305. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/__init__.py +0 -0
  306. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/__init__.py +0 -0
  307. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/_embedding.py +0 -0
  308. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/rf/__init__.py +0 -0
  309. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/rf/ring_slot.s2p +0 -0
  310. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/rf/ring_slot_meas.s1p +0 -0
  311. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/rf/test_rf.py +0 -0
  312. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_adder.py +0 -0
  313. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_amplifier.py +0 -0
  314. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_block.py +0 -0
  315. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_bvp.py +0 -0
  316. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_comparator.py +0 -0
  317. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_constraint.py +0 -0
  318. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_converters.py +0 -0
  319. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_counter.py +0 -0
  320. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_ctrl.py +0 -0
  321. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_dae.py +0 -0
  322. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_delay.py +0 -0
  323. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_delay_channels.py +0 -0
  324. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_differentiator.py +0 -0
  325. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_discrete.py +0 -0
  326. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_divider.py +0 -0
  327. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_dynsys.py +0 -0
  328. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_filters.py +0 -0
  329. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_fmu.py +0 -0
  330. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_function.py +0 -0
  331. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_integrator.py +0 -0
  332. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_kalman.py +0 -0
  333. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_logic.py +0 -0
  334. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_lti.py +0 -0
  335. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_math.py +0 -0
  336. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_multiplier.py +0 -0
  337. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_noise.py +0 -0
  338. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_ode.py +0 -0
  339. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_relay.py +0 -0
  340. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_rng.py +0 -0
  341. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_scope.py +0 -0
  342. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_sources.py +0 -0
  343. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_sparsedae.py +0 -0
  344. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_spectrum.py +0 -0
  345. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_switch.py +0 -0
  346. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_table.py +0 -0
  347. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/blocks/test_wrapper.py +0 -0
  348. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/events/__init__.py +0 -0
  349. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/events/test_condition.py +0 -0
  350. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/events/test_event.py +0 -0
  351. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/events/test_schedule.py +0 -0
  352. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/events/test_zerocrossing.py +0 -0
  353. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/__init__.py +0 -0
  354. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_anderson.py +0 -0
  355. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_linearization.py +0 -0
  356. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_newton.py +0 -0
  357. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_numerical.py +0 -0
  358. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_operator.py +0 -0
  359. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/optim/test_sparse_newton.py +0 -0
  360. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/__init__.py +0 -0
  361. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/_referenceproblems.py +0 -0
  362. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_bdf.py +0 -0
  363. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_dirk2.py +0 -0
  364. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_dirk3.py +0 -0
  365. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_esdirk32.py +0 -0
  366. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_esdirk4.py +0 -0
  367. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_esdirk43.py +0 -0
  368. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_esdirk54.py +0 -0
  369. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_esdirk85.py +0 -0
  370. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_euler.py +0 -0
  371. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_gear.py +0 -0
  372. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rfk21.py +0 -0
  373. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rk4.py +0 -0
  374. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkbs32.py +0 -0
  375. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkck54.py +0 -0
  376. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkdp54.py +0 -0
  377. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkdp87.py +0 -0
  378. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkf45.py +0 -0
  379. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkf78.py +0 -0
  380. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_rkv65.py +0 -0
  381. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_solver.py +0 -0
  382. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_ssprk22.py +0 -0
  383. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_ssprk33.py +0 -0
  384. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_ssprk34.py +0 -0
  385. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/solvers/test_steadystate.py +0 -0
  386. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_auto_initial_step.py +0 -0
  387. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_checkpoint.py +0 -0
  388. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_connection.py +0 -0
  389. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_diagnostics.py +0 -0
  390. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_simulation.py +0 -0
  391. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_simulation_pss.py +0 -0
  392. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/test_subsystem.py +0 -0
  393. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/__init__.py +0 -0
  394. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_adaptivebuffer.py +0 -0
  395. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_analysis.py +0 -0
  396. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_fmuwrapper.py +0 -0
  397. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_gilbert.py +0 -0
  398. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_graph.py +0 -0
  399. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_logger.py +0 -0
  400. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_mutable.py +0 -0
  401. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_portreference.py +0 -0
  402. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_progresstracker.py +0 -0
  403. {pathsim-0.28.0 → pathsim-0.29.0}/tests/pathsim/utils/test_realtimeplotter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pathsim
3
- Version: 0.28.0
3
+ Version: 0.29.0
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
@@ -8,5 +8,6 @@ except Exception:
8
8
  from .simulation import Simulation
9
9
  from .connection import Connection, Duplex
10
10
  from .subsystem import Subsystem, Interface
11
+ from .utils.carrier import Carrier, Vector
11
12
  from .utils.logger import LoggerManager
12
13
  from .exceptions import StopSimulation
@@ -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.28.0'
22
- __version_tuple__ = version_tuple = (0, 28, 0)
21
+ __version__ = version = '0.29.0'
22
+ __version_tuple__ = version_tuple = (0, 29, 0)
23
23
 
24
- __commit_id__ = commit_id = 'ge34add612'
24
+ __commit_id__ = commit_id = 'g220bc787c'
@@ -19,6 +19,7 @@ from .switch import *
19
19
  from .dynsys import *
20
20
  from .kalman import *
21
21
  from .adder import *
22
+ from .splitter import *
22
23
  from .scope import *
23
24
  from .delay import *
24
25
  from .noise import *
@@ -22,32 +22,6 @@ from ..optim.operator import DynamicOperator
22
22
  from ..exceptions import LinearizationError
23
23
 
24
24
 
25
- # HELPERS ===============================================================================
26
-
27
- def _labels_size(labels):
28
- """Minimum register size required to hold all declared port labels.
29
-
30
- Port labels map string aliases to integer port indices. The register has
31
- to be large enough to address the highest declared index, otherwise blocks
32
- with unconnected declared ports (e.g. a multi-input block placed without
33
- connections) would default to the size 1 register and break positional
34
- input access.
35
-
36
- Parameters
37
- ----------
38
- labels : dict[str: int] | None
39
- port label mapping (alias -> index)
40
-
41
- Returns
42
- -------
43
- size : int | None
44
- minimum register size, or None if no labels are declared
45
- """
46
- if not labels:
47
- return None
48
- return max(labels.values()) + 1
49
-
50
-
51
25
  # BASE BLOCK CLASS ======================================================================
52
26
 
53
27
  class Block:
@@ -123,14 +97,8 @@ class Block:
123
97
 
124
98
  #registers to hold input and output values, pre-sized to the declared
125
99
  #port labels so blocks with unconnected ports are still addressable
126
- self.inputs = Register(
127
- size=_labels_size(self.input_port_labels),
128
- mapping=self.input_port_labels and self.input_port_labels.copy()
129
- )
130
- self.outputs = Register(
131
- size=_labels_size(self.output_port_labels),
132
- mapping=self.output_port_labels and self.output_port_labels.copy()
133
- )
100
+ self.inputs = Register(mapping=self.input_port_labels)
101
+ self.outputs = Register(mapping=self.output_port_labels)
134
102
 
135
103
  #initialize integration engine as 'None' by default
136
104
  self.engine = None
@@ -0,0 +1,124 @@
1
+ #########################################################################################
2
+ ##
3
+ ## SPLITTER BLOCK
4
+ ## (blocks/splitter.py)
5
+ ##
6
+ #########################################################################################
7
+
8
+ # IMPORTS ===============================================================================
9
+
10
+ import numpy as np
11
+
12
+ from ._block import Block
13
+ from ..optim.operator import Operator
14
+ from ..utils.carrier import Carrier, Vector
15
+ from ..utils.mutable import mutable
16
+
17
+
18
+ # SIMO BLOCKS ===========================================================================
19
+
20
+ @mutable
21
+ class Splitter(Block):
22
+ """Splits the input into multiple outputs, weighted with fractions (SIMO).
23
+
24
+ .. math::
25
+
26
+ y_i(t) = f_i \\cdot u(t)
27
+
28
+ The fractions have to sum up to one, so the splitter conserves what flows
29
+ through it, for example a mass or molar flow.
30
+
31
+ With a carrier, the input is a stream of multiple channels, for example
32
+ the flows of multiple species. Every output is a stream with the same
33
+ layout and each channel is split with the same fractions.
34
+
35
+
36
+ Example
37
+ -------
38
+ Split a flow into two outputs with 90 and 10 percent:
39
+
40
+ .. code-block:: python
41
+
42
+ S = Splitter([0.9, 0.1])
43
+
44
+ Split a stream of species flows, the ports 'in', 'out_0' and 'out_1'
45
+ have the layout of the carrier:
46
+
47
+ .. code-block:: python
48
+
49
+ class Species(Carrier):
50
+ keys = ("H", "D", "T")
51
+
52
+ S = Splitter([0.9, 0.1], carrier=Species())
53
+
54
+ C = Connection(S["out_1"], B["in"])
55
+
56
+
57
+ Note
58
+ ----
59
+ This block is purely algebraic and its operation (`op_alg`) will be called
60
+ multiple times per timestep, each time when `Simulation._update(t)` is
61
+ called in the global simulation loop.
62
+
63
+
64
+ Parameters
65
+ ----------
66
+ fractions : array_like
67
+ fractions of the input for each output, must sum up to one
68
+ carrier : Carrier | None
69
+ layout of the input and output streams, single channel if 'None'
70
+
71
+
72
+ Attributes
73
+ ----------
74
+ op_alg : Operator
75
+ internal algebraic operator
76
+ """
77
+
78
+ input_port_labels = {"in": 0}
79
+ output_port_labels = None
80
+
81
+ def __init__(self, fractions=None, carrier=None):
82
+
83
+ self.fractions = np.ones(1) if fractions is None else np.asarray(fractions, dtype=float)
84
+ self.carrier = carrier
85
+
86
+ #input validation
87
+ if not np.isclose(np.sum(self.fractions), 1.0):
88
+ raise ValueError(f"'fractions' must sum up to one but sum up to {np.sum(self.fractions)}!")
89
+
90
+ #ports with the layout of the carrier, placed one after another
91
+ n = 1 if carrier is None else len(carrier)
92
+
93
+ def _port(start):
94
+ if carrier is None:
95
+ return start
96
+ if carrier.keys:
97
+ return Carrier(start, keys=carrier.keys)
98
+ return Vector(n, start)
99
+
100
+ self.input_port_labels = {"in": _port(0)}
101
+ self.output_port_labels = {
102
+ f"out_{i}": _port(i * n) for i in range(len(self.fractions))
103
+ }
104
+
105
+ super().__init__()
106
+
107
+ #every channel of the input split with the same fractions
108
+ self.op_alg = Operator(
109
+ func=lambda u: np.kron(self.fractions, u),
110
+ jac=lambda u: np.kron(self.fractions.reshape(-1, 1), np.eye(len(u)))
111
+ )
112
+
113
+
114
+ def update(self, t):
115
+ """update system equation
116
+
117
+ Parameters
118
+ ----------
119
+ t : float
120
+ evaluation time
121
+ """
122
+ u = self.inputs.to_array()
123
+ y = self.op_alg(u)
124
+ self.outputs.update_from_array(y)
@@ -138,9 +138,12 @@ class Connection:
138
138
  ----------
139
139
  _active : bool
140
140
  flag to set 'Connection' as active or inactive
141
+ _transfers : list[tuple[Block, int | np.ndarray, int | np.ndarray]] | None
142
+ resolved data transfers to the targets as tuples of target block,
143
+ target and source channel indices, built by 'resolve_ports'
141
144
  """
142
145
 
143
- __slots__ = ["source", "targets", "_active"]
146
+ __slots__ = ["source", "targets", "_active", "_transfers"]
144
147
 
145
148
 
146
149
  def __init__(self, source, *targets):
@@ -153,6 +156,9 @@ class Connection:
153
156
 
154
157
  #flag to set connection active
155
158
  self._active = True
159
+
160
+ #resolved data transfers (lazily initialized)
161
+ self._transfers = None
156
162
 
157
163
  #validate port aliases
158
164
  self._validate_ports()
@@ -169,8 +175,10 @@ class Connection:
169
175
 
170
176
 
171
177
  def __len__(self):
172
- """Returns the number of ports that are defined in the connection"""
173
- return len(self.source)
178
+ """Returns the number of channels that are defined in the connection,
179
+ ports that are carriers count with all of their channels
180
+ """
181
+ return len(self.source.block.outputs._resolve(self.source.ports))
174
182
 
175
183
 
176
184
  def __bool__(self):
@@ -199,9 +207,9 @@ class Connection:
199
207
  """Check the dimensions of the source and target ports,
200
208
  if they dont match, raises an exception.
201
209
  """
202
- n_src = len(self.source)
210
+ n_src = len(self)
203
211
  for trg in self.targets:
204
- if len(trg) != n_src:
212
+ if len(trg.block.inputs._resolve(trg.ports)) != n_src:
205
213
  raise ValueError(f"Source and target have different number of ports!")
206
214
 
207
215
 
@@ -245,8 +253,12 @@ class Connection:
245
253
  """Transfers data from the source block output port
246
254
  to the target block input port.
247
255
  """
248
- for trg in self.targets:
249
- self.source.to(trg)
256
+ if self._transfers is None:
257
+ self.resolve_ports()
258
+
259
+ _data = self.source.block.outputs._data
260
+ for block, i_trg, i_src in self._transfers:
261
+ block.inputs._data[i_trg] = _data[i_src]
250
262
 
251
263
 
252
264
  def resolve_ports(self):
@@ -267,10 +279,20 @@ class Connection:
267
279
  Calling ``resolve_ports`` once during graph assembly closes that
268
280
  gap. Idempotent. New register slots are zero-initialised through
269
281
  ``np.zeros`` in ``Register.resize``.
282
+
283
+ The resolved indices are stored as data transfers for ``update``,
284
+ transfers of a single channel use plain integer indices, which is
285
+ faster than fancy indexing with an index array.
270
286
  """
271
- self.source._get_output_indices()
287
+ i_src = self.source._get_output_indices()
288
+
289
+ self._transfers = []
272
290
  for trg in self.targets:
273
- trg._get_input_indices()
291
+ i_trg = trg._get_input_indices()
292
+ if len(i_trg) == 1:
293
+ self._transfers.append((trg.block, int(i_trg[0]), int(i_src[0])))
294
+ else:
295
+ self._transfers.append((trg.block, i_trg, i_src))
274
296
 
275
297
 
276
298
  @deprecated(version="1.0.0")
@@ -69,28 +69,44 @@ def _state_labels(x_layout, keys):
69
69
  return labels
70
70
 
71
71
 
72
- def _port_labels(port_refs, keys):
73
- """One label per resolved port across a list of 'PortReference', in the
72
+ def _port_labels(port_refs, keys, inputs=True):
73
+ """One label per resolved channel across a list of 'PortReference', in the
74
74
  same order as the assembled 'B' columns or 'C' and 'D' rows.
75
75
 
76
+ Ports that are carriers get one label per channel, named by the channel
77
+ key or by the channel position for carriers without keys.
78
+
76
79
  Parameters
77
80
  ----------
78
81
  port_refs : list[PortReference]
79
82
  break points or tap points
80
83
  keys : dict[Block: str]
81
84
  canonical identifiers from '_block_keys'
85
+ inputs : bool
86
+ resolve the ports in the block inputs, otherwise in the block outputs
82
87
 
83
88
  Returns
84
89
  -------
85
90
  labels : list[str]
86
- one label per port
91
+ one label per channel
87
92
  """
88
93
  labels = []
89
94
  for pr in port_refs:
90
- if len(pr.ports) == 1:
95
+ register = pr.block.inputs if inputs else pr.block.outputs
96
+
97
+ #single channel -> block identifier only
98
+ if len(register._resolve(pr.ports)) == 1:
91
99
  labels.append(keys[pr.block])
92
- else:
93
- labels.extend(f"{keys[pr.block]}[{p}]" for p in pr.ports)
100
+ continue
101
+
102
+ for p in pr.ports:
103
+ carrier = register._carriers.get(p) if isinstance(p, str) else None
104
+ if carrier is None:
105
+ name = f"{p[0]}.{p[1]}" if isinstance(p, tuple) else p
106
+ labels.append(f"{keys[pr.block]}[{name}]")
107
+ else:
108
+ names = carrier.keys or range(len(carrier))
109
+ labels.extend(f"{keys[pr.block]}[{p}.{k}]" for k in names)
94
110
  return labels
95
111
 
96
112
 
@@ -305,6 +321,6 @@ def assemble_statespace(blocks, connections, inputs, outputs, t):
305
321
  return (
306
322
  A, B, C, D,
307
323
  _state_labels(x_layout, keys),
308
- _port_labels(inputs, keys),
309
- _port_labels(outputs, keys)
324
+ _port_labels(inputs, keys, inputs=True),
325
+ _port_labels(outputs, keys, inputs=False)
310
326
  )
@@ -1260,29 +1260,30 @@ class Simulation:
1260
1260
  #log message begin of steady state solver
1261
1261
  self.logger.info(f"STEADYSTATE -> STARTING (reset: {reset})")
1262
1262
 
1263
- #solve for steady state at current time
1264
- with Timer(verbose=False) as T:
1265
- success, evals, iters = self._solve(self.time, self.dt)
1266
-
1267
- #catch non convergence
1268
- if not success:
1269
- details = self._solve_tracker.details(lambda b: b.__class__.__name__)
1270
- _msg = "STEADYSTATE -> FAILED (evals: {}, iters: {}, runtime: {})\n{}".format(
1271
- evals, iters, T, "\n".join(details))
1272
- self.logger.error(_msg)
1273
- raise RuntimeError(_msg)
1274
-
1275
- #sample result
1276
- self._sample(self.time, self.dt)
1277
-
1278
- #log message
1279
- self.logger.info(
1280
- "STEADYSTATE -> FINISHED (success: {}, evals: {}, iters: {}, runtime: {})".format(
1281
- success, evals, iters, T)
1282
- )
1283
-
1284
- #switch back to original solver
1285
- self._set_solver(_solver)
1263
+ try:
1264
+ #solve for steady state at current time
1265
+ with Timer(verbose=False) as T:
1266
+ success, evals, iters = self._solve(self.time, self.dt)
1267
+
1268
+ #catch non convergence
1269
+ if not success:
1270
+ details = self._solve_tracker.details(lambda b: b.__class__.__name__)
1271
+ _msg = "STEADYSTATE -> FAILED (evals: {}, iters: {}, runtime: {})\n{}".format(
1272
+ evals, iters, T, "\n".join(details))
1273
+ self.logger.error(_msg)
1274
+ raise RuntimeError(_msg)
1275
+
1276
+ #sample result
1277
+ self._sample(self.time, self.dt)
1278
+
1279
+ #log message
1280
+ self.logger.info(
1281
+ "STEADYSTATE -> FINISHED (success: {}, evals: {}, iters: {}, runtime: {})".format(
1282
+ success, evals, iters, T)
1283
+ )
1284
+ finally:
1285
+ #restore the transient solver even if solving or sampling fails
1286
+ self._set_solver(_solver)
1286
1287
 
1287
1288
 
1288
1289
  # initial timestep estimation -------------------------------------------------
@@ -786,6 +786,9 @@ class Subsystem(Block):
786
786
  if not _blocks_dyn:
787
787
  return None
788
788
 
789
+ #the parent may have supplied new inputs after evaluating our outputs
790
+ self.update(t)
791
+
789
792
  _derivatives = []
790
793
  for b in _blocks_dyn:
791
794
  _d = b.derivative(t)
@@ -928,6 +931,9 @@ class Subsystem(Block):
928
931
  max_error : float
929
932
  maximum error of implicit update equaiton
930
933
  """
934
+ #refresh internal inputs for the current implicit stage
935
+ self.update(t)
936
+
931
937
  max_error = 0.0
932
938
  for block in self._blocks_dyn:
933
939
  if not block: continue
@@ -963,6 +969,9 @@ class Subsystem(Block):
963
969
  rescale factor for timestep
964
970
  """
965
971
 
972
+ #refresh internal inputs for the current explicit stage
973
+ self.update(t)
974
+
966
975
  #initial timestep rescale and error estimate
967
976
  success, max_error_norm, min_scale = True, 0.0, None
968
977
 
@@ -1045,4 +1054,4 @@ class Subsystem(Block):
1045
1054
  evaluation time for buffering
1046
1055
  """
1047
1056
  for block in self._blocks_dyn:
1048
- if block: block.buffer(dt)
1057
+ if block: block.buffer(dt)
@@ -0,0 +1,213 @@
1
+ #########################################################################################
2
+ ##
3
+ ## CARRIER CLASS
4
+ ## (utils/carrier.py)
5
+ ##
6
+ ## This module defines the 'Carrier' class that groups multiple
7
+ ## scalar channels of a block register into a single named entity
8
+ ##
9
+ #########################################################################################
10
+
11
+ # CLASSES ===============================================================================
12
+
13
+ class Carrier:
14
+ """Named range of scalar channels of a block register.
15
+
16
+ A carrier describes a contiguous block of channels and gives each of them
17
+ a name. It is placed at an explicit position ('start') in the register of
18
+ a block and used as the value of a port label
19
+
20
+ .. code-block:: python
21
+
22
+ _in_1 = Carrier(keys=("F", "T"))
23
+ _in_2 = Carrier(_in_1.stop, keys=("F", "T"))
24
+
25
+ class Mixer(Block):
26
+ input_port_labels = {"in_1": _in_1, "in_2": _in_2}
27
+
28
+
29
+ The carrier only exists while the system graph is assembled. Component
30
+ access resolves to plain integer indices, either by attribute or by key
31
+
32
+ .. code-block:: python
33
+
34
+ _in_1.F # -> 0
35
+ _in_1["T"] # -> 1
36
+ _in_1[1] # -> 1
37
+
38
+
39
+ so the values themselves stay in the flat float64 register of the block
40
+ and nothing carrier specific is left at runtime
41
+
42
+ .. code-block:: python
43
+
44
+ def func(u):
45
+ return u[_in_1.F] + u[_in_2.F]
46
+
47
+
48
+ Note
49
+ ----
50
+ Carriers are addressed as a whole when blocks are connected, a connection
51
+ to a carrier port transfers all its channels at once.
52
+
53
+
54
+ Parameters
55
+ ----------
56
+ start : int
57
+ index of the first channel in the register of the block
58
+ keys : tuple[str] | list[str] | None
59
+ names of the channels, overrides the class level 'keys'
60
+
61
+
62
+ Attributes
63
+ ----------
64
+ keys : tuple[str]
65
+ names of the channels
66
+ start : int
67
+ index of the first channel
68
+ stop : int
69
+ index after the last channel
70
+ """
71
+
72
+ keys = ()
73
+
74
+ #names that would collide with the carrier interface itself
75
+ _reserved = ("keys", "start", "stop", "size", "slice")
76
+
77
+ def __init__(self, start=0, keys=None):
78
+
79
+ #channel names, from the arguments or from the class
80
+ if keys is not None:
81
+ self.keys = tuple(keys)
82
+
83
+ #key validation
84
+ for key in self.keys:
85
+ if not isinstance(key, str):
86
+ raise ValueError(f"Key '{key}' must be str but is '{type(key)}'!")
87
+ if key in self._reserved or key.startswith("_"):
88
+ raise ValueError(f"Key '{key}' is reserved!")
89
+ if len(set(self.keys)) < len(self.keys):
90
+ raise ValueError("Keys must be unique!")
91
+
92
+ #position validation
93
+ if not isinstance(start, int) or start < 0:
94
+ raise ValueError(f"Start '{start}' must be a positive int!")
95
+
96
+ #size validation
97
+ if self.size < 1:
98
+ raise ValueError("Carrier must have at least one channel!")
99
+
100
+ self.start = start
101
+ self.stop = start + self.size
102
+
103
+ #channel indices as plain attributes, resolved once
104
+ for i, key in enumerate(self.keys):
105
+ setattr(self, key, start + i)
106
+
107
+
108
+ def __repr__(self):
109
+ return f"{self.__class__.__name__}({self.start}, {self.keys})"
110
+
111
+
112
+ @property
113
+ def size(self):
114
+ """Number of channels covered by the carrier
115
+
116
+ Returns
117
+ -------
118
+ size : int
119
+ number of channels
120
+ """
121
+ return len(self.keys)
122
+
123
+
124
+ def __len__(self):
125
+ return self.size
126
+
127
+
128
+ def __getitem__(self, key):
129
+ """Index of a single channel of the carrier, by key or by position.
130
+
131
+ Parameters
132
+ ----------
133
+ key : int, str
134
+ channel name or channel position within the carrier
135
+
136
+ Returns
137
+ -------
138
+ index : int
139
+ index of the channel in the register of the block
140
+ """
141
+
142
+ if isinstance(key, str):
143
+ if key not in self.keys:
144
+ raise ValueError(f"Key '{key}' not defined for {self}!")
145
+ return getattr(self, key)
146
+
147
+ if isinstance(key, int):
148
+ if key < 0 or key >= self.size:
149
+ raise ValueError(f"Channel '{key}' outside of {self}!")
150
+ return self.start + key
151
+
152
+ raise ValueError(f"Key must be (int, str) but is '{type(key)}'!")
153
+
154
+
155
+ @property
156
+ def slice(self):
157
+ """All channels of the carrier as a slice, for direct access to the
158
+ flat register data, for example 'u[_in_1.slice]'
159
+
160
+ Returns
161
+ -------
162
+ slice : slice
163
+ slice covering all channels of the carrier
164
+ """
165
+ return slice(self.start, self.stop)
166
+
167
+
168
+ class Vector(Carrier):
169
+ """Carrier for a fixed number of unnamed channels.
170
+
171
+ Channels are addressed by position only, which makes this the carrier
172
+ for values that have a size but no component names, such as a spatial
173
+ discretization
174
+
175
+ .. code-block:: python
176
+
177
+ v = Vector(3)
178
+ v[0] # -> 0
179
+ v[2] # -> 2
180
+
181
+
182
+ Parameters
183
+ ----------
184
+ size : int
185
+ number of channels
186
+ start : int
187
+ index of the first channel in the register of the block
188
+ """
189
+
190
+ def __init__(self, size, start=0):
191
+
192
+ #size validation
193
+ if not isinstance(size, int) or size < 1:
194
+ raise ValueError(f"Size '{size}' must be a positive int!")
195
+
196
+ self._size = size
197
+ super().__init__(start)
198
+
199
+
200
+ def __repr__(self):
201
+ return f"{self.__class__.__name__}({self.size}, {self.start})"
202
+
203
+
204
+ @property
205
+ def size(self):
206
+ """Number of channels covered by the carrier
207
+
208
+ Returns
209
+ -------
210
+ size : int
211
+ number of channels
212
+ """
213
+ return self._size
@@ -115,16 +115,19 @@ class Graph:
115
115
  def _validate_connections(self):
116
116
  """Fast O(N) validation that no connections overwrite each other.
117
117
 
118
- Checks that no two connections target the same (block, port) pair.
118
+ Checks that no two connections target the same (block, channel) pair.
119
+ Ports are resolved to channel indices first, so port names, ports that
120
+ are carriers and single carrier channels are compared on the channels
121
+ they actually cover.
119
122
  """
120
- # {(block, port_idx): connection}
123
+ # {(block, channel_idx): connection}
121
124
  connected_targets = set()
122
125
 
123
126
  for connection in self.connections:
124
127
  for target in connection.targets:
125
128
  target_block = target.block
126
- for port_idx in target.ports:
127
- key = (target_block, port_idx)
129
+ for port_idx in target_block.inputs._resolve(target.ports):
130
+ key = (target_block, int(port_idx))
128
131
  if key in connected_targets:
129
132
  raise ValueError(
130
133
  f"Connection conflict detected"