Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heyoka updates #158

Merged
merged 5 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/breaking_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ heyoka.py 4 includes several backwards-incompatible changes.
API/behaviour changes
~~~~~~~~~~~~~~~~~~~~~

Terminal events callbacks
^^^^^^^^^^^^^^^^^^^^^^^^^

The second argument in the signature of callbacks for terminal events, a ``bool`` conventionally
called ``mr``, has been removed. This flag was meant to signal the possibility of multiple roots
in the event function within the cooldown period, but it never worked as intended and
it has thus been dropped.

Adapting existing code for this API change is straightforward: you just have to remove the second argument
from the signature of a terminal event callback.

Step callbacks and ``propagate_*()``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
4 changes: 4 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ New
Changes
~~~~~~~

- **BREAKING**: the signature of callbacks for terminal events
has been simplified
(`#158 <https://github.com/bluescarni/heyoka.py/pull/158>`__).
This is a :ref:`breaking change <bchanges_4_0_0>`.
- **BREAKING**: the ``propagate_*()`` functions
now return the (optional) step callback that can be
passed in input
Expand Down
6 changes: 3 additions & 3 deletions doc/notebooks/Batch mode overview.ipynb

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions doc/notebooks/Box control for Formation Flying Satellites.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@
"source": [
"# This callback flips the selected component (x = 3, y = 4, z = 5)\n",
"# of the relative velocity\n",
"def cb_flip_rel_component(ta, mr, component):\n",
"def cb_flip_rel_component(ta, component):\n",
" global DV\n",
" # Compute the perturbation effect on w\n",
" fh = J2_LHLV(ta.state[:6], c)[2]\n",
Expand All @@ -510,7 +510,7 @@
"\n",
"# This callback flips the selected component (x = 3, y = 4, z = 5)\n",
"# of the relative velocity\n",
"def cb_zero_rel_component(ta, mr, component):\n",
"def cb_zero_rel_component(ta, component):\n",
" global DV\n",
" # Compute the perturbation effect on w\n",
" fh = J2_LHLV(ta.state[:6], c)[2]\n",
Expand Down Expand Up @@ -564,19 +564,19 @@
"# The size of the control box is 10 cm\n",
"box_size = 0.0001\n",
"# We define one event per cube side\n",
"ev_left = hy.t_event(state_rel_sym[0] - box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 3), direction=hy.event_direction.positive)\n",
"ev_right = hy.t_event(state_rel_sym[0] + box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 3), direction=hy.event_direction.negative)\n",
"ev_front = hy.t_event(state_rel_sym[1] - trailing - box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 4), direction=hy.event_direction.positive)\n",
"ev_back = hy.t_event(state_rel_sym[1] - trailing + box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 4), direction=hy.event_direction.negative)\n",
"ev_top = hy.t_event(state_rel_sym[2] - hover - box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 5), direction=hy.event_direction.positive)\n",
"ev_bottom = hy.t_event(state_rel_sym[2] - hover + box_size / 2, callback = lambda ta, mr, d_sgn: cb_flip_rel_component(ta, mr, 5), direction=hy.event_direction.negative)\n",
"ev_left = hy.t_event(state_rel_sym[0] - box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 3), direction=hy.event_direction.positive)\n",
"ev_right = hy.t_event(state_rel_sym[0] + box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 3), direction=hy.event_direction.negative)\n",
"ev_front = hy.t_event(state_rel_sym[1] - trailing - box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 4), direction=hy.event_direction.positive)\n",
"ev_back = hy.t_event(state_rel_sym[1] - trailing + box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 4), direction=hy.event_direction.negative)\n",
"ev_top = hy.t_event(state_rel_sym[2] - hover - box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 5), direction=hy.event_direction.positive)\n",
"ev_bottom = hy.t_event(state_rel_sym[2] - hover + box_size / 2, callback = lambda ta, d_sgn: cb_flip_rel_component(ta, 5), direction=hy.event_direction.negative)\n",
"\n",
"# We define events when crossing the cube halves.\n",
"# Here the callback will cancel the velocity along that direction, so we need a cooldown\n",
"# As to avoid the event triggering immediately again.\n",
"ev_x = hy.t_event(state_rel_sym[0] , callback = lambda ta, mr, d_sgn: cb_zero_rel_component(ta, mr, 3), cooldown=20.)\n",
"ev_y = hy.t_event(state_rel_sym[1] - trailing , callback = lambda ta, mr, d_sgn: cb_zero_rel_component(ta, mr, 4), cooldown=20.)\n",
"ev_z = hy.t_event(state_rel_sym[2] - hover, callback = lambda ta, mr, d_sgn: cb_zero_rel_component(ta, mr, 5), cooldown=20.)\n",
"ev_x = hy.t_event(state_rel_sym[0] , callback = lambda ta, d_sgn: cb_zero_rel_component(ta, 3), cooldown=20.)\n",
"ev_y = hy.t_event(state_rel_sym[1] - trailing , callback = lambda ta, d_sgn: cb_zero_rel_component(ta, 4), cooldown=20.)\n",
"ev_z = hy.t_event(state_rel_sym[2] - hover, callback = lambda ta, d_sgn: cb_zero_rel_component(ta, 5), cooldown=20.)\n",
"\n",
"# We put all the control box events in a list as to pass them to the adaptive Taylor constructor.\n",
"bounce_events = [ev_top, ev_bottom, ev_front, ev_back, ev_left, ev_right]\n",
Expand Down
17 changes: 7 additions & 10 deletions doc/notebooks/Event detection.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@
"zero_vel_times.clear()\n",
"\n",
"# Callback for the terminal event.\n",
"def t_cb(ta, mr, d_sgn):\n",
"def t_cb(ta, d_sgn):\n",
" # NOTE: the value of the drag coefficient\n",
" # is stored as the first (and only) runtime parameter\n",
" # of the integrator.\n",
Expand Down Expand Up @@ -621,15 +621,18 @@
" because, when a terminal event triggers, the state of the integrator is propagated\n",
" up to the event, and thus the trigger time is the current integrator time\n",
" (which can be fetched via ``ta.time``);\n",
"- there is an additional boolean function argument, here called ``mr``. We will be ignoring\n",
" this extra argument for the moment, its meaning will be clarified in the\n",
" cooldown section below;\n",
"- whereas non-terminal event callbacks do not return anything, terminal event callbacks\n",
" are required to return ``True`` or ``False``. If the callback returns ``False`` the integration\n",
" will always be stopped after the execution of the callback. Otherwise, when using the\n",
" ``propagate_*()`` family of functions, the integration will resume after the execution\n",
" of the callback.\n",
"\n",
"```{versionchanged} 4.0.0\n",
"\n",
"The signature of callbacks for terminal events used to include an extra\n",
"``bool`` argument which has been removed in version 4.0.0.\n",
"```\n",
"\n",
"Note that, for the purpose of stopping the integration, an event *without* a callback is considered\n",
"equivalent to an event whose callback returns ``False``.\n",
"We thus refer to terminal events without a callback or whose callback returns ``False``\n",
Expand Down Expand Up @@ -790,12 +793,6 @@
"A custom cooldown period can be selected when constructing\n",
"a terminal event via the ``cooldown`` keyword argument.\n",
"\n",
"When a terminal event triggers and enters the cooldown period, the event detection system will also try to detect\n",
"the occurrence of multiple roots of the event equation within the cooldown period. If such multiple roots are detected,\n",
"then the ``mr`` boolean parameter in the terminal event callback will be set to ``True``, so that the user\n",
"has the possibility to handle such occurrence. Note that an ``mr`` value of ``False`` in the callback does not imply\n",
"that multiple roots do not exist, just that they were not detected.\n",
"\n",
"Note that manually modifying the integrator's time or state does **not** automatically reset the cooldown values\n",
"for terminal events. This could in principle lead to missing terminal events when the integration restarts.\n",
"For this reason, a method called ``reset_cooldowns()`` is available to clear the cooldown timers of\n",
Expand Down
27 changes: 13 additions & 14 deletions doc/notebooks/Optimal Control of the Lotka-Volterra equations.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -565,20 +565,19 @@
"switch_times = []\n",
"\n",
"# This callback will be called by the Taylor integrator when the switching event is detected \n",
"def switch_callback(ta, mr, log_times):\n",
" if not mr:\n",
" if ta.pars[6]==0.:\n",
" ta.pars[6] = 1.\n",
" else:\n",
" ta.pars[6]=0.\n",
" if log_times:\n",
" switch_times.append(ta.time)\n",
"def switch_callback(ta, log_times):\n",
" if ta.pars[6]==0.:\n",
" ta.pars[6] = 1.\n",
" else:\n",
" ta.pars[6]=0.\n",
" if log_times:\n",
" switch_times.append(ta.time)\n",
" # Do not stop the integration\n",
" return True\n",
" \n",
"# The switching event\n",
"switching_event = hy.t_event(x * lx * hy.par[4] + y * ly * hy.par[5],\n",
" callback = lambda ta, mr, d_sgn: switch_callback(ta, mr, True))\n",
" callback = lambda ta, d_sgn: switch_callback(ta, True))\n",
"\n",
"# The Taylor integrator\n",
"ta = hy.taylor_adaptive(ode_sys, [x_0, y_0, lx_0, ly_0], pars = ps, t_events = [switching_event])\n",
Expand Down Expand Up @@ -725,7 +724,7 @@
"metadata": {},
"outputs": [],
"source": [
"def distance_callback(ta, mr, d_sgn):\n",
"def distance_callback(ta, d_sgn):\n",
" candidates_t.append(ta.time)\n",
" candidates_d.append((ta.state[0]-x_t)**2 + (ta.state[1]-y_t)**2)\n",
" # Do not stop the integration\n",
Expand All @@ -736,7 +735,7 @@
"\n",
"# We also redefine the switching event as we have no need to log the switching times (this is optional and has not real impact in this case)\n",
"switching_event_no_log = hy.t_event(x * lx * hy.par[4] + y * ly * hy.par[5],\n",
" callback = lambda ta, mr, d_sgn: switch_callback(ta, mr, False))"
" callback = lambda ta, d_sgn: switch_callback(ta, False))"
]
},
{
Expand Down Expand Up @@ -905,9 +904,9 @@
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_23723/2413872175.py:11: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
"/tmp/ipykernel_78942/2413872175.py:11: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
" ta.pars[6] = np.heaviside(switching_function(x_0,y_0,lx_0,ly_0, ps), 1.)\n",
"/tmp/ipykernel_23723/2413872175.py:14: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
"/tmp/ipykernel_78942/2413872175.py:14: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
" ta.state[0] = x_0; ta.state[1] = y_0; ta.state[2] = lx_0; ta.state[3] = ly_0\n"
]
},
Expand Down Expand Up @@ -955,7 +954,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_23723/3578120629.py:12: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
"/tmp/ipykernel_78942/3578120629.py:12: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
" ta.pars[6] = np.heaviside(switching_function(x_0,y_0,lx_0,ly_0, ps), 1.)\n"
]
}
Expand Down
Loading