You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello Martin,
I have a question concerning the detection of events.
I see that to detect events I need to provide a closure that has a zero crossing at the event and then I need to use the return value of OdeSolverMethod::step to check if an event has been detected.
In the documentation for OdeSolverStopReason it states:
RootFound(t_root): The solver has found a root at time t_root. Note that the internal state of the solver is at the internal time step self.state().t, not at time t_root.
In my case I would like to know both t_root and also the state at time t=t_root. Is there an easy way to obtain this information?
I would then restart/continue the integration from the event onwards.
I am sorry if this has an obvious answer, but I am new to the Rust programming language and it is not immediately obvious to me.
If you are happy then continuing the integration from the internal time of the solver, then great :). However, if you wanted to restart from exactly the time of the event, then you would have to mutate the state (using OdeSolverMethod::state_mut) and set it to the interpolated state.
Perhaps something like this (I havn't tried compiling/running this!)
let t = loop{match solver.step(){Ok(OdeSolverStopReason::InternalTimestep) => continue,Ok(OdeSolverStopReason::TstopReached) => panic!("We didn't set a stop time"),Ok(OdeSolverStopReason::RootFound(t)) => break t,Err(e) => panic!("Solver failed to converge: {}", e),}};println!("Root found at t = {}", t);let new_state = solver.interpolate(t).unwrap();
solver.state_mut().unwrap().y.copy_from(&new_state);*solver.state_mut().unwrap().t = t;
solver.step();
Note that this is inefficient for some solvers (the BDF one) as it needs to be re-initialised after the call to state_mut, so if you are happy to just continue solving without mutating the state (the solver will carry on from its current internal timestep) this is the best.
Thank you for taking the time to answer my question and providing a clear answer.
Using your draft code I was able to obtain the state at the event time and then propagate further.
The only change that I needed to make to the draft code was to replace the line
solver.state_mut().unwrap().copy_from(&new_state);
with the two lines
solver.state_mut().unwrap().y.copy_from(&new_state);
solver.state_mut().unwrap().dy.copy_from(&new_state);
The additional documentation „Solving the Problem“ is also very helpful.
Regards,
James
Activity
martinjrobins commentedon Jul 18, 2024
Hi @JEMH, you can use
OdeSolverMethod::interpolateto get the state vector at the time of the event (i.e.t_root).If you are happy then continuing the integration from the internal time of the solver, then great :). However, if you wanted to restart from exactly the time of the event, then you would have to mutate the state (using
OdeSolverMethod::state_mut) and set it to the interpolated state.Perhaps something like this (I havn't tried compiling/running this!)
Note that this is inefficient for some solvers (the BDF one) as it needs to be re-initialised after the call to
state_mut, so if you are happy to just continue solving without mutating the state (the solver will carry on from its current internal timestep) this is the best.martinjrobins commentedon Jul 18, 2024
note I've just put together some docs on this: https://martinjrobins.github.io/diffsol/solving_the_problem.html
JEMH commentedon Jul 19, 2024