bugGNU Octave - Bugs: bug #63063, ode{23,45} options...

 
 

bug #63063: ode{23,45} options "Events", "OutputFcn", and "Refine" do not perform correctly.

Submitter:  Ken Marek <m5318>
Submitted:  Thu 15 Sep 2022 09:08:18 PM UTC
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Fixed Assigned to:  None
Originator Name:  Open/Closed:  * Closed
Release:  * dev Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment (Rich Markup)
   

Comment Type & Canned Response:
       

 

( Jump to the original submission )

Thu 10 Nov 2022 11:16:37 PM UTC, comment #28: 

no comments in > a month. marking as fixed and closing.

Nicholas Jankowski <nrjank>
Project Member
Thu 06 Oct 2022 08:47:04 PM UTC, comment #27: 

ok. i removed the odeplot tests from ode23, 23s, 45, and annotated your demo a little bit to make it more informative. We can just leave those "!test  # Details of OutputSel can't be tested" tests for now. if nothing else they'll get run during the test suite and serve as a "shouldn't generate any hard errors" test.

Pushed as https://hg.savannah.gnu.org/hgweb/octave/rev/c332a2f2959f

leaving this as Ready for Test for now, but I think this is largely complete.

Nicholas Jankowski <nrjank>
Project Member
Thu 06 Oct 2022 07:26:34 PM UTC, comment #26: 

Submitting a final patch to change the odeplot test to a demo. I also edited the first odeplot demo to remove the explicit setting of the OutputFcn, so that demo now displays this default behavior for ode45.

I'm not sure it's possible to fix the tests for defaulting to odeplot in the ode23/23s/45 files. I thought maybe if I overloaded the odeplot function name I could make a working test, but Octave still used the built-in function, so I was not able to implement a test. Since there is now a demo of the default OutputFcn in odeplot, I'm not sure we need to make this a demo in the ode files as well, so maybe those tests should just be removed. Do what you think is best. I'm happy with you closing the report after this last minor patch.

(file #53809)

Ken Marek <m5318>
Thu 06 Oct 2022 03:59:52 PM UTC, comment #25: 

Please leave this bug open for now. I think I've  come up with a way to fix the self test in odexx, and I'll just move the odeplot self test to a demo. I think I will be able to spend some time on it in a few hours and hopefully have a patch by the end of the day.

Ken Marek <m5318>
Wed 05 Oct 2022 10:18:09 PM UTC, comment #24: 

Yes, I was wondering if the plotting would cause issues. In theory, there might be an error if the nargout == 0 case were not handled for odexx, but I guess it's not the greatest test. I don't know of any other way to test that odeplot is called as the OutputFcn if no return values are requested. Is there some way to disable all figure visibility, and see if a function tries to generate a figure while they are turned off? Otherwise we should just get rid of those tests in odexx.

Similarly with the odeplot BIST, there might be an error if odeplot did not correctly handle valid input, but I don't think there's any way to do an assert without generating the plot.

I guess we should just leave those plotting tests off if you can't figure out how to get a testable assertion either.

As far as the other test goes:

!test  # Details of OutputSel can't be tested

you are correct that it was already there. Once I get my other bug patch finished I will probably come back and add a test for this one as well. I'm just trying not to fix anything else here that isn't required, since the patch has already gotten a bit large.

Ken Marek <m5318>
Wed 05 Oct 2022 10:16:33 PM UTC, comment #23: 

ok. fixed my ssh key issue. patch pushed as http://hg.savannah.gnu.org/hgweb/octave/rev/449ed6f427cb

marking as ready for test.

only thing that would be remaining would be to fix the odeplot tests

Nicholas Jankowski <nrjank>
Project Member
Wed 05 Oct 2022 09:18:47 PM UTC, comment #22: 

ok. I trimmed up the commit message quite a bit. sorry, i neglected to link the wiki guidelines: https://wiki.octave.org/Commit_message_guidelines#:~:text=The%20commit%20message%20should%20describe,to%20someone%20reading%20it%20later.

my only other concern is with some of the new BISTs. most are good. but ones that generate plots, and don't have any assert or error statement tests, aren't of much use. unless something generates a hard error, BISTs are generally run passively during compilation to check for errors and to check that desired outputs haven't changed. that's why most pure plotting functions just use 'demo' blocks. for BISTS that to generate plots, its preferred to disable the actual plot rendering so that they aren't generated when someone runs the test suite. e.g., here's a BIST from figure.m:

%!test
%! hf = figure ("visible", "off");
%! unwind_protect
%!   assert (hf, gcf);
%!   assert (isfigure (hf));
%!   hf2 = figure (hf, "visible", "off");
%!   assert (hf, hf2);
%!   assert (hf2, gcf);
%!   assert (isfigure (hf2));
%!   assert (get (hf2, "visible"), "off");
%! unwind_protect_cleanup
%!   close (hf);
%! end_unwind_protect

so there are actual fail-able tests, and the visible plot is suppressed. if there is an error, it cleans up after itself.

So for now I've commented out those tests and left in FIXME: generate appropriate plot self test or convert to demo block

Each function still also has another BIST like:

!test  # Details of OutputSel can't be tested
%! opt = odeset ("OutputFcn", @fout, "OutputSel", 1);
%! sol = ode45 (@fpol, [0 2], [2 0], opt);

but I notice that was there before, too. perhaps these could actually be tested somehow.

the rest passes all tests, and seems to fix these bugs.  i was about to push the patch when I ran into some login/ authentication issues. patch attached for now.

(file #53798)

Nicholas Jankowski <nrjank>
Project Member
Wed 28 Sep 2022 12:01:51 AM UTC, comment #21: 

I have attached the new total patch file <bug_fix_63063_and_49408_total-20220927.patch>.

I have written a thorough commit message (you may wish to edit for line length), including user name. Let me know if any of the explanations are too unclear.

In addition to my previous patch's changes, I have updated documentation, added a few more tests, and added news items. Please note that odeplot.m now has a test when it did not before; I don't know if that fact needs to be updated somewhere for patch testing purposes.

(file #53763)

Ken Marek <m5318>
Thu 22 Sep 2022 02:46:49 AM UTC, comment #20: 

sorry, i only work with hg at the command line, so don't know the ins and outs of tortoisehg

comment #18 patch pushes clean on current tip and passes a make check. original and recent tests appear to run as expected.

I made a few very minor formatting tweaks (pulling some lines inside 80 characters, splitting AND asserts into two asserts, a few stray whitespace changes, etc.), and exported a modified patch (attached as <bug63063_ode2345options_v2.patch>)

I think this is almost ready to push. 

Ken:
- Can you check where the help docstrings might need to be updated with any changes. at least i think we'll need to edit odeset's help a little (it still says Refine is not yet implemented)

- Can you add a brief description of improvements to the /etc/NEWS.8.md file? This probably fits under the General Improvements section, although possible Matlab Compatibility, and then include that in the patch?

- I took a stab at a main line commit message, but can you add individual file details.  for recent multi-file examples see:
http://hg.savannah.gnu.org/hgweb/octave/rev/5330efaf9476
http://hg.savannah.gnu.org/hgweb/octave/rev/1bf26f913b9c

-  right now your name in the commit message is your username from the other patch.  would you like your name/email in there? (this is what octave generally compiles it's contributor list from, so it'll appear publicly however you choose.)

(file #53741)

Nicholas Jankowski <nrjank>
Project Member
Wed 21 Sep 2022 11:17:54 PM UTC, comment #19: 

File name in comment #18 should have been:
<bug_fix_63063_and_49408_total-20220921.patch>

I'm sure everyone figured that out, but I'm correcting it anyway.

Ken Marek <m5318>
Wed 21 Sep 2022 11:13:58 PM UTC, comment #18: 

I tried what you suggested, and what was supposed to be the overall patch file ended up being just part of the third patch. (I have been using TortoiseHg, and I couldn't figure out how to make it patch --no-commit, so I had to do that part command line, then back to the Tortoise. Maybe that caused the problem. Sometimes the Tortoise doesn't seem to find all my updates unless I close and reopen the Workbench.)

Instead, I ended up going back to the latest revision I could pull (Rev. 31243, Br. default, Des. "build: Fix Makefile rule ...", according to the Tortoise) and just merging all my changes with that. Resulting total bugfix is attached.

<bug_fix_63-63_and_49408_total-20220921.patch>

Hopefully it works this time. I may work on a couple things that I think will improve some output accuracy, but I'm going to wait until these current fixes are committed.

(file #53740)

Ken Marek <m5318>
Wed 21 Sep 2022 05:12:02 PM UTC, comment #17: 

I will try to reconstitute the patches and resubmit soon. Thank you for the advice.

Ken Marek <m5318>
Wed 21 Sep 2022 02:51:54 PM UTC, comment #16: 

@m5318, Can you rebase the patches to the current tip and ensure they apply correctly? 

it seems this is nearing completion, it may be worth applying reverting your source clone to the current state without your changes, then applying all patches without committing (hg patch --no-commit <patchname>) then, when you are able to have all changes in place, make a single fresh patch that includes all three option fixes and the self tests.

let us know if you need mercurial assistance.  i described some of my (less than elegant) approach to doing this in Comment #11 of bug #51333

Nicholas Jankowski <nrjank>
Project Member
Wed 21 Sep 2022 01:30:38 AM UTC, comment #15: 

applying

comment #9 patch: file #53726 <bug_fix_49408_20220919.patch>

after

comment #8 patch: file #53722 <bug_fix_63063_total-20220919.patch>

fails for me.

Carlo de Falco <cdf>
Project Member
Tue 20 Sep 2022 08:54:01 PM UTC, comment #14: 

That is correct.

Ken Marek <m5318>
Tue 20 Sep 2022 08:47:30 PM UTC, comment #13: 

just confirming that this is an independent patch file, and the current full solution is the following files, i assume they require application in order:

comment #8 patch: file #53722 <bug_fix_63063_total-20220919.patch>
comment #9 patch: file #53726 <bug_fix_49408_20220919.patch>
comment #12 patch: file #53733 <bug_fix_63063_tests-20220920.patch>

Nicholas Jankowski <nrjank>
Project Member
Tue 20 Sep 2022 08:30:32 PM UTC, comment #12: 

I have patched the tests for ode45/23/23s. I have included a new test for the "Refine" function, and have otherwise made things work with the new functionality, without adding additional tests for Events or OutputFcn.

Also a small bug fix in integrate_adaptive.m, which was caught with the tests.

Patch: <bug_fix_63063_tests-20220920.patch>

(file #53733)

Ken Marek <m5318>
Tue 20 Sep 2022 03:05:46 PM UTC, comment #11: 

since it looks like all work for bug #49408 on option Refine is moving here, I'm retitling this one accordingly and closing the other report to reduce the number of locations to follow the discussion.

Nicholas Jankowski <nrjank>
Project Member
Tue 20 Sep 2022 01:45:05 AM UTC, comment #10: 

please also fix the self tests at the end of ode23 and ode45 that are currently failing with the change in output orientation.  run 'test ode23' and 'test ode45' to see which ones are failing.

Nicholas Jankowski <nrjank>
Project Member
Tue 20 Sep 2022 01:36:13 AM UTC, comment #9: 

I am adding my patch for bug #49408 here, since it depends on the patch in comment #8. In this patch, I changed how data are stored and processed in integrate_adaptive.m, which actually solved the outstanding difference when outputting a struct (last bullet point in comment #8). This patch therefore also contributes to fixing this bug.

Files:
patch file: <bug_fix_49408_20220919.patch>
Octave/Matlab test cases: <bug63063_data_v3.zip>

Note that all my test cases now match Matlab output exactly (apart from minor formatting differences). I also removed the warning when integrate_adaptive.m encounters a terminal Event or OutputFcn return, since Matlab doesn't display a warning in either of those cases.

(file #53726, file #53727)

Ken Marek <m5318>
Mon 19 Sep 2022 09:53:46 PM UTC, comment #8: 

Here is what I believe to be the overall fix to this bug <bug_fix_63063_total-20220919.patch>

This incorporates the changes in comment #5, as well as additional fixes in integrate_adaptive.m to process Events and OutputFcn at approximately the same time. There is also an additional semicolon fix in ode_event_handler.m.

I am also attaching updated test scripts and results:<bug63063_data_v02.zip>. These update the ones given by Nicholas in comment #7 in a few useful ways, in addition to incorporating the rest of my fixes. In particular:

  • testscript.m now tries four tests, with four parts each.

  * Part 1: outputs as variables, fixed time specified
  * Part 2: outputs as struct, fixed time specified
  * Part 3: outputs as variables, start/stop time specified
  * Part 4: outputs as struct, start/stop time specified
  * Specified times for parts 1 & 2 are now [0, 1.05, 2, 2.5] to show whether the solver outputs the specified times or not.

  • testFuncOut.m now allows multiple points to be input per step, as it turns out Matlab does this in some cases. A second point is output as the same step number, but iteration 2.
  • testEvent.m now has three events, at y = {0.1, 1.1, 1.5}. The last event is still terminal. This lets us see what happens when two events occur in a single time step.

Diary files are included for Matlab, Octave original (bug), and Octave fixed. You can see that the Octave original shows all the bugs I mentioned before. Octave fixed mostly agrees with Matlab. In particular, the OutputFcn is called even when a terminal Event is found on that step. Duplicate calls of OutputFcn are removed (vs. original Octave output). Multiple Events are processed in a single step, like in Matlab. This patch corrects all the things I set out to fix at present, so that I can work on adding Refine capability once this is accepted.

There are, however, a few more issues, which should perhaps be added as their own bugs.

  • As I mentioned in a previous comment, Matlab behavior for terminal Events in the first step is somewhat different than what they describe in their documentation, and also different from current Octave implementation. I have not attempted to address that issue here.
  • Matlab behaves somewhat differently from Octave (the new, fixed version submitted here) when outputting a struct from ode45 (etc.). In particular, see the diary files for Test 3/Part 2. When output time values are specified, Matlab calls the OutputFcn at those specified times (including sending multiple values at once if they fall on the same solution step), even though it ignores the specified times for the x and y values in the struct. Octave also ignores the specified times for x and y in the struct, but it also ignores them when calling the OutputFcn, sending those same x and y values as found in the struct. The fix for this issue is a bit more structural than the others I have submitted for this bug, and so I am leaving it unaddressed for now. I think this is less serious than the other issues I addressed, since (1) an OutputFcn can be written to accept multiple points at once, and then perform about the same with Matlab or Octave; and (2) the user can force Matlab and Octave to output at the specified times by taking the variables as an output instead of a struct, which I think is a fairly easy workaround.

(file #53722, file #53723)

Ken Marek <m5318>
Mon 19 Sep 2022 01:44:27 PM UTC, comment #7: 

testing on ubuntu, both comment #5 patches push cleanly (don't know if order mattered, but I did the event handler and then struct fix)

make check returns

 PASS                            17446
  FAIL                                2
  XFAIL (reported bug)               35
  SKIP (missing feature)              3
  SKIP (run-time condition)          27

the two failures appear to just be tests due to the orientation change patch. so those BISTs should be updated:

>>>>> processing /home/nrjank/source/octave/scripts/ode/ode23.m
***** test  # Events option, now stop integration
 warning ("off", "integrate_adaptive:unexpected_termination", "local");
 opt = odeset ("Events", @fevn, "NormControl", "on");
 sol = ode23 (@fpol, [0 10], [2 0], opt);
 assert ([sol.ie, sol.xe, sol.ye],
         [2.0, 2.496110, -0.830550, -2.677589], .5e-1);
!!!!! test failed
horizontal dimensions mismatch (1x2 vs 2x1)
>>>>> processing /home/nrjank/source/octave/scripts/ode/ode23s.m
>>>>> processing /home/nrjank/source/octave/scripts/ode/ode45.m
***** test  # Events option, now stop integration
 warning ("off", "integrate_adaptive:unexpected_termination", "local");
 opt = odeset ("Events", @fevn, "NormControl", "on");
 sol = ode45 (@fpol, [0 10], [2 0], opt);
 assert ([sol.ie, sol.xe, sol.ye],
         [2.0, 2.496110, -0.830550, -2.677589], 6e-1);
!!!!! test failed
horizontal dimensions mismatch (1x2 vs 2x1)

I ran  the comment #0 and comment #1 tests with four test cases in matlab, patched and unpatched octave.  to be honest I haven't parsed them to verify corrected behavior, but they are here for inspection.

I've attached the testscript and the function files used to run this under the different programs in case they need to be rechecked with any patch revision.

Matlab 2022a:

test 1 (baseline)
odeOpt =
  struct with fields:

              AbsTol: []
                 BDF: []
              Events: []
         InitialStep: 1
            Jacobian: []
           JConstant: []
            JPattern: []
                Mass: []
        MassSingular: []
            MaxOrder: []
             MaxStep: 1
         NonNegative: []
         NormControl: []
           OutputFcn: []
           OutputSel: []
              Refine: 1
              RelTol: []
               Stats: []
          Vectorized: []
    MStateDependence: []
           MvPattern: []
        InitialSlope: []
t =
         0
    1.0000
    2.0000
    2.5000
y =
         0
    1.0000
    2.0000
    2.5000
structOut =
  struct with fields:

     solver: 'ode45'
    extdata: [1×1 struct]
          x: [0 1 2 2.5000]
          y: [0 1.0000 2.0000 2.5000]
      stats: [1×1 struct]
      idata: [1×1 struct]
test 2 (event only)
odeOpt =
  struct with fields:

              AbsTol: []
                 BDF: []
              Events: @testEvent
         InitialStep: 1
            Jacobian: []
           JConstant: []
            JPattern: []
                Mass: []
        MassSingular: []
            MaxOrder: []
             MaxStep: 1
         NonNegative: []
         NormControl: []
           OutputFcn: []
           OutputSel: []
              Refine: 1
              RelTol: []
               Stats: []
          Vectorized: []
    MStateDependence: []
           MvPattern: []
        InitialSlope: []
t =
         0
    1.0000
    1.5000
y =
         0
    1.0000
    1.5000
structOut =
  struct with fields:

     solver: 'ode45'
    extdata: [1×1 struct]
          x: [0 1 1.5000]
          y: [0 1.0000 1.5000]
         xe: [0.1000 1.5000]
         ye: [0.1000 1.5000]
         ie: [1 2]
      stats: [1×1 struct]
      idata: [1×1 struct]
test 3 (output function only)
odeOpt =
  struct with fields:

              AbsTol: []
                 BDF: []
              Events: []
         InitialStep: 1
            Jacobian: []
           JConstant: []
            JPattern: []
                Mass: []
        MassSingular: []
            MaxOrder: []
             MaxStep: 1
         NonNegative: []
         NormControl: []
           OutputFcn: @testFuncOut
           OutputSel: []
              Refine: 1
              RelTol: []
               Stats: []
          Vectorized: []
    MStateDependence: []
           MvPattern: []
        InitialSlope: []
Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
Output function received DONE signal
t =
     0
     1
     2
y =
         0
    1.0000
    2.0000
Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
Output function received DONE signal
structOut =
  struct with fields:

     solver: 'ode45'
    extdata: [1×1 struct]
          x: [0 1 2]
          y: [0 1.0000 2.0000]
      stats: [1×1 struct]
      idata: [1×1 struct]
test 4 (event and output function)
odeOpt =
  struct with fields:

              AbsTol: []
                 BDF: []
              Events: @testEvent
         InitialStep: 1
            Jacobian: []
           JConstant: []
            JPattern: []
                Mass: []
        MassSingular: []
            MaxOrder: []
             MaxStep: 1
         NonNegative: []
         NormControl: []
           OutputFcn: @testFuncOut
           OutputSel: []
              Refine: 1
              RelTol: []
               Stats: []
          Vectorized: []
    MStateDependence: []
           MvPattern: []
        InitialSlope: []
Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 1.5, y = 1.5
y value is 1.5, greater than 1.2. Sending STOP signal.
Output function received DONE signal
t =
         0
    1.0000
    1.5000
y =
         0
    1.0000
    1.5000
Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 1.5, y = 1.5
y value is 1.5, greater than 1.2. Sending STOP signal.
Output function received DONE signal
structOut =
  struct with fields:

     solver: 'ode45'
    extdata: [1×1 struct]
          x: [0 1 1.5000]
          y: [0 1.0000 1.5000]
         xe: [0.1000 1.5000]
         ye: [0.1000 1.5000]
         ie: [1 2]
      stats: [1×1 struct]
      idata: [1×1 struct]

Octave 8.0.0 with these patches:

test 1 (baseline)
odeOpt =
  scalar structure containing the fields:
    Events = [](0x0)
    InitialStep = 1
    OutputFcn = [](0x0)
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

t =
        0
   1.0000
   2.0000
   2.5000

y =
        0
   1.0000
   2.0000
   2.5000

structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   2.0000   2.5000
    y =
            0   1.0000   2.0000   2.5000
    solver = ode45

test 2 (event only)
odeOpt =
  scalar structure containing the fields:
    Events = @testEvent
    InitialStep = 1
    OutputFcn = [](0x0)
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

evtcntnew = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 10 column 12

t =
        0
   1.0000
   1.5000

y =
        0
   1.0000
   1.5000

evtcntnew = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 11 column 15

structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   1.5000
    y =
            0   1.0000   1.5000
    solver = ode45
    xe =
       0.1000   1.5000
    ye =
       0.1000   1.5000
    ie =
       1   2

test 3 (output function only)
odeOpt =
  scalar structure containing the fields:
    Events = [](0x0)
    InitialStep = 1
    OutputFcn = @testFuncOut
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 2.000000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 16 column 12

Output function received DONE signal
t =
   0
   1
   2

y =
   0
   1
   2

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 2.000000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 17 column 15

Output function received DONE signal
structOut =
  scalar structure containing the fields:
    x =
       0   1   2
    y =
       0   1   2
    solver = ode45

test 4 (event and output function)
odeOpt =
  scalar structure containing the fields:
    Events = @testEvent
    InitialStep = 1
    OutputFcn = @testFuncOut
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
evtcntnew = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 22 column 12

Output function received DONE signal
t =
        0
   1.0000
   1.5000

y =
        0
   1.0000
   1.5000

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
evtcntnew = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t = 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 23 column 15

Output function received DONE signal
structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   1.5000
    y =
            0   1.0000   1.5000
    solver = ode45
    xe =
       0.1000   1.5000
    ye =
       0.1000   1.5000
    ie =
       1   2

and for reference, Octave 7.2.0 unpatched:

test 1 (baseline)
odeOpt =
  scalar structure containing the fields:
    Events = [](0x0)
    InitialStep = 1
    OutputFcn = [](0x0)
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

t =
        0
   1.0000
   2.0000
   2.5000

y =
        0
   1.0000
   2.0000
   2.5000

structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   2.0000   2.5000
    y =
            0   1.0000   2.0000   2.5000
    solver = ode45

test 2 (event only)
odeOpt =
  scalar structure containing the fields:
    Events = @testEvent
    InitialStep = 1
    OutputFcn = [](0x0)
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 10 column 12

t =
        0
   1.0000
   1.5000

y =
        0
   1.0000
   1.5000

warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 11 column 15

structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   1.5000
    y =
            0   1.0000   1.5000
    solver = ode45
    xe =
       0.1000
       1.5000
    ye =
       0.1000
       1.5000
    ie =
       1
       2

test 3 (output function only)
odeOpt =
  scalar structure containing the fields:
    Events = [](0x0)
    InitialStep = 1
    OutputFcn = @testFuncOut
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 2.000000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 16 column 12

Output function received DONE signal
t =
   0
   1
   2

y =
   0
   1
   2

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
Step: 2, t = 2, y = 2
y value is 2, greater than 1.2. Sending STOP signal.
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 2.000000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 17 column 15

Output function received DONE signal
structOut =
  scalar structure containing the fields:
    x =
       0   1   2
    y =
       0   1   2
    solver = ode45
test 4 (event and output function)
odeOpt =
  scalar structure containing the fields:
    Events = @testEvent
    InitialStep = 1
    OutputFcn = @testFuncOut
    Refine = 1
    MaxStep = 1
    AbsTol = [](0x0)
    BDF = [](0x0)
    InitialSlope = [](0x0)
    JConstant = [](0x0)
    JPattern = [](0x0)
    Jacobian = [](0x0)
    MStateDependence = [](0x0)
    Mass = [](0x0)
    MassSingular = [](0x0)
    MaxOrder = [](0x0)
    MvPattern = [](0x0)
    NonNegative = [](0x0)
    NormControl = [](0x0)
    OutputSel = [](0x0)
    RelTol = [](0x0)
    Stats = [](0x0)
    Vectorized = [](0x0)

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 22 column 12
Output function received DONE signal
t =
        0
   1.0000
   1.5000

y =
        0
   1.0000
   1.5000

Step: 0, t = 0, y = 0
Step: 1, t = 1, y = 1
warning: Solver was stopped by a call of 'break' in the main iteration loop at time t =
 1.500000 before the endpoint at tend = 2.500000 was reached.  This may happen because
the @odeplot function returned 'true' or the @event function returned 'true'.
warning: called from
    integrate_adaptive at line 327 column 7
    ode45 at line 241 column 12
    testscript at line 23 column 15

Output function received DONE signal
structOut =
  scalar structure containing the fields:
    x =
            0   1.0000   1.5000
    y =
            0   1.0000   1.5000
    solver = ode45
    xe =
       0.1000
       1.5000
    ye =
       0.1000
       1.5000
    ie =
       1
       2

(file #53716)

Nicholas Jankowski <nrjank>
Project Member
Sun 18 Sep 2022 10:23:10 AM UTC, comment #6: 

Marking as patch submitted.

I do not have Matlab myself. Could someone with Matlab verify the patches in comment #5 from Ken please?

@Ken: for your initial patches, it's OK to submit "hg diff" output without a commit message so others can test it. Thank you for the work you've done on this bug.

Arun Giridhar <arungiridhar>
Project Member
Fri 16 Sep 2022 08:56:37 PM UTC, comment #5: 

I have attached the same patches as comment #4 below, but with better commit messages. Again, I apologize for my mistakes as I learn how to use Mercurial.

ode_event_handler-v3-20220916.patch
ode_events_struct_fix-v2-20220916.patch

(file #53702, file #53703)

Ken Marek <m5318>
Fri 16 Sep 2022 08:30:50 PM UTC, comment #4: 

Please disregard the patch in comment #2. I didn't realize someone had changed the function name in several spots while I was editing different parts of the file. I have attached a new patch file, ode_event_handler-v2-20220916.patch, which covers my changes only.

I am also attaching another patch, ode_events_struct_fix-20220916.patch. This makes ode45 and ode23 output Events data in row form when outputting a struct, while leaving them in column form when outputting individual variables. This matches Matlab's format (R2017b).

(file #53700, file #53701)

Ken Marek <m5318>
Fri 16 Sep 2022 06:33:59 PM UTC, comment #3: 

Also, I apologize about several lines in the diff file that remove and then add the same line. I'm not sure why that happened (I didn't edit those lines, to my knowledge), and this is my first time using Mercurial, so I wasn't really sure what to do apart from submitting it as is.

Ken Marek <m5318>
Fri 16 Sep 2022 06:30:43 PM UTC, comment #2: 

I am attaching a diff file that fixes test case 2, i.e. Octave only returning one event per step when more than one is present. I think these are the only changes needed for ode_event_handler.m with respect to this bug report. There are more fixes to come with integrate_adaptive.m, so please don't close this report yet.

This fix allows multiple events to be returned per step. It also sorts by time, and clips any events occurring after a terminal event. Matlab does some interesting things with events in the first step, and I don't claim to have matched everything exactly (that's for another bug report at a later time), but I believe I have avoided any regressions of prior bug fixes on that topic.

I should probably mention that I am comparing to Matlab R2017b.

(file #53699)

Ken Marek <m5318>
Thu 15 Sep 2022 09:58:21 PM UTC, comment #1: 

A correction to the original bug description:

In test case 2 (and 4), two events were encountered on the same step, and the second event was terminal. Octave detected a terminal event but only reported the first (non-terminal) event. If the testEvent function were redefined so that the non-terminal event occurs on a different step than the terminal event, e.g.:

function [val, isTerm, dir] = testEvent ( t , y )
  isTerm = [ 0; 1 ];
  dir = [ 1; 1 ];
  val = [ y(1) - 0.1; y(1) - 1.5 ];
end

then test case 2 returns the same as Matlab.

This is still a different result than Matlab gives, and should be fixed. The pre-empting of OutputFcn by an Events break (case 4) is still an issue, although with the modified testEvent function, both Events would be reported.

Contrary to my initial indication, fixing test case 2 will require modifications to ode_event_handler.m. I believe the rest of the problems still lie in integrate_adaptive.m.

Ken Marek <m5318>
Thu 15 Sep 2022 09:08:18 PM UTC, original submission:  

Overview: Each of these options displays incorrect behavior on its own. Additionally, there is an interaction between the two bugs, so I am treating this as a single bug. (Interaction is: termination due to an Event prevents OutputFcn from being called on the last iteration.) I am currently working on a fix to bug #49408 relating to ode{23,45} "Refine", and that fix will require fixing these issues as well. This bug report is to document these additional problems.

To display these bugs, we need two functions defined. I have made the following simple examples:

function [val, isTerm, dir] = testEvent ( t , y )
  isTerm = [ 0; 1 ];
  dir = [ 1; 1 ];
  val = [ y(1) - 1.1; y(1) - 1.5 ];
end

and

function stopSolve = testFuncOut ( t, y, flag )
  persistent stepNum
  stopVal = 1.2;
  if strcmp ( flag, 'init' )
    stepNum = 0;
  elseif strcmp ( flag, 'done' )
    disp ( 'Output function received DONE signal' )
    return
  else
    stepNum = stepNum + 1;
  end
  disp ( ['Step: ' num2str(stepNum) ', t = ' num2str(t(1)) ', y = ' num2str(y) ] )
  if y(1) > stopVal
    stopSolve = true;
    disp ( ['y value is ' num2str(y(1)) ', greater than ' num2str(stopVal) '. Sending STOP signal.'] )
  else
    stopSolve = false;
  end
end

These examples are in Matlab compatible script so we can compare results.

Function testEvent creates a non-terminating event at y = 1.1, and a terminating event at y = 1.5 (for scalar y). Function testFuncOut prints t and y to the screen each time the function is called, except when the "done" flag is sent, in which case it indicates it received the "done" signal. Additionally, testFuncOut returns a termination signal if y > 1.2.

Now I have created 4 test cases:

%test 1 (baseline)
odeOpt = odeset ( 'Events', [], 'InitialStep', 1, 'OutputFcn', [], ...
  'Refine', 1, 'MaxStep', 1 );

%test 2 (event only)
odeOpt = odeset ( 'Events', @testEvent, 'InitialStep', 1, 'OutputFcn', [], ...
  'Refine', 1, 'MaxStep', 1 );

%test 3 (output function only)
odeOpt = odeset ( 'Events', [], 'InitialStep', 1, 'OutputFcn', @testFuncOut, ...
  'Refine', 1, 'MaxStep', 1 );

%test 4 (event and output function)
odeOpt = odeset ( 'Events', @testEvent, 'InitialStep', 1, 'OutputFcn', @testFuncOut, ...
  'Refine', 1, 'MaxStep', 1 );

With each set of odeOpt options, I ran ode45 using:

[t, y] = ode45 ( @(t,y) 1, [0,1,2,2.5], [0], odeOpt )

I also ran with struct output:

structOut = ode45 ( @(t,y) 1, [0,1,2,2.5], [0], odeOpt )

when needed to pull out the returned Event variables (one could alternately assign additional return variables to get them). The ODE I have selected has the solution y(t) = t, so ode45 will return only exact solution results.

Results are:
----------
Test 1

Matlab:
t = [0; 1; 2; 2.5]
y = [0; 1; 2; 2.5]
Octave: same

There are no errors for the test scenario when Events and OutputFcn options are not used.

----------
Test 2
Matlab:
t = [0; 1; 1.5]
y = [0; 1; 1.5]
event variables:
  xe = [1.1, 1.5]
  ye = [1.1, 1.5]
  ie = [1, 2]
Octave: produces warning. Also:
t = [0; 1; 1.1]
y = [0; 1; 1.1]
event variables:
  xe = [1.1]
  ye = [1.1]
  ie = [1]

Here we see an error in the Events option alone. Octave produces a warning where Matlab does not, and it also incorrectly treats the non-terminal Event as a terminal one. I do not plan to remove the warning in my bug fixes, unless asked to do so.

----------
Test 3
Matlab:
t = [0; 1; 2]
y = [0; 1; 2]
testFuncOut shows steps 0, 1, and 2
Octave: produces warning, otherwise same

There is no error here when OutputFcn is used alone (but we will see an OutputFcn bug in a later test case).

----------
Test 4
Matlab:
t = [0; 1; 1.5]
y = [0; 1; 1.5]
testFuncOut shows steps 0, 1, and 2
Octave: produces warning. Also:
t = [0; 1; 1.1]
y = [0; 1; 1.1]
testFuncOut shows only steps 0 and 1

Here, termination due to an Event prevents OutputFcn from being called on the last step in Octave.

----------

The above function calls to ode45 used a fixed set of output times. We now try again using a 2-element trange:

[t, y] = ode45 ( @(t,y) 1, [0,2.5], [0], odeOpt )

Because of the initial step and maximum step size I have chosen, the results here should have the same t values as before, so all results should theoretically be identical to the above tests. Actual results are:

----------
Tests 1-4 for Matlab and Tests 1-2 for Octave are the same as above.

----------
Test 3 Octave:
testFuncOut shows steps numbered 0 to 4 (t = 0 and t = 1 are each repeated once).

This is an error in OutputFcn with no Events, and is due to an incorrect implementation of Refine (hence the connection to the other bug, as mentioned in the summary).

----------
Test 4 Octave:
Results are qualitatively similar to Test 3. testFuncOut shows steps numbered 0 to 2 (t = 0 is repeated once). The Events/OutputFcn interaction bug is also still present.

----------

A brief search did not reveal this to be an open bug, though I found several bugs about Events initialization, which I think have all been fixed. I think they are all in ode_event_handler.m, which I don't expect to modify in these fixes, so hopefully I won't break anything in the process.

As far as I have identified, all the bugs are in the file integrate_adaptive.m, which is called by both ode45 and ode23. Therefore, bugs as shown here with ode45 will be also be expressed in ode23.

Ken Marek <m5318>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #53809:  odeplot_demo.patch added by m5318 (1KiB - application/octet-stream)
file #53798:  bug_fix_63063_and_49408_total-20220927v2.patch added by nrjank (37KiB - application/octet-stream)
file #53763:  bug_fix_63063_and_49408_total-20220927.patch added by m5318 (38KiB - application/octet-stream)
file #53741:  bug63063_ode2345options_v2.patch added by nrjank (31KiB - application/octet-stream)
file #53740:  bug_fix_63063_and_49408_total-20220921.patch added by m5318 (30KiB - application/octet-stream)
file #53733:  bug_fix_63063_tests-20220920.patch added by m5318 (8KiB - application/octet-stream)
file #53726:  bug_fix_49408_20220919.patch added by m5318 (18KiB - application/octet-stream)
file #53727:  bug63063_data_v3.zip added by m5318 (3KiB - application/x-zip-compressed)
file #53722:  bug_fix_63063_total-20220919.patch added by m5318 (12KiB - application/octet-stream)
file #53723:  bug63063_data_v02.zip added by m5318 (4KiB - application/x-zip-compressed)
file #53716:  bug63063testscripts.zip added by nrjank (1KiB - application/zip - comment #7 test script and functions)
file #53702:  ode_event_handler-v3-20220916.patch added by m5318 (3KiB - application/octet-stream)
file #53703:  ode_events_struct_fix-v2-20220916.patch added by m5318 (3KiB - application/octet-stream)
file #53700:  ode_event_handler-v2-20220916.patch added by m5318 (3KiB - application/octet-stream)
file #53701:  ode_events_struct_fix-20220916.patch added by m5318 (3KiB - application/octet-stream)

 

Carbon-Copy List
  • -email is unavailable- added by cdf (Posted a comment)
  • -email is unavailable- added by nrjank (Updated the item)
  • -email is unavailable- added by arungiridhar (Posted a comment)
  • -email is unavailable- added by m5318 (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only project members can vote.

     

     

     

     

    Follow 25 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2022-11-10 nrjank StatusReady For Test Fixed
        Open/ClosedOpen Closed
    2022-10-17 nrjank Dependencies- bugs #63229 is dependent
    2022-10-06 m5318 Attached File- Added odeplot_demo.patch, #53809
    2022-10-05 nrjank StatusPatch Submitted Ready For Test
    2022-10-05 nrjank Attached File- Added bug_fix_63063_and_49408_total-20220927v2.patch, #53798
        Release7.2.0 dev
        Operating SystemMicrosoft Windows Any
    2022-10-05 nrjank Dependencies- bugs #63162 is dependent
    2022-09-28 m5318 Attached File- Added bug_fix_63063_and_49408_total-20220927.patch, #53763
    2022-09-22 nrjank Attached File- Added bug63063_ode2345options_v2.patch, #53741
    2022-09-21 m5318 Attached File- Added bug_fix_63063_and_49408_total-20220921.patch, #53740
    2022-09-20 m5318 Attached File- Added bug_fix_63063_tests-20220920.patch, #53733
    2022-09-20 nrjank Summaryode{23,45} options "Events" and "OutputFcn" do not perform correctly. ode{23,45} options "Events", "OutputFcn", and "Refine" do not perform correctly.
    2022-09-20 nrjank Dependencies- bugs #49408 is dependent
    2022-09-20 m5318 Attached File- Added bug_fix_49408_20220919.patch, #53726
        Attached File- Added bug63063_data_v3.zip, #53727
    2022-09-19 m5318 Attached File- Added bug_fix_63063_total-20220919.patch, #53722
        Attached File- Added bug63063_data_v02.zip, #53723
    2022-09-19 nrjank Attached File- Added bug63063testscripts.zip, #53716
    2022-09-18 arungiridhar StatusNone Patch Submitted
    2022-09-16 m5318 Attached File- Added ode_event_handler-v3-20220916.patch, #53702
        Attached File- Added ode_events_struct_fix-v2-20220916.patch, #53703
    2022-09-16 m5318 Attached File- Added ode_event_handler-v2-20220916.patch, #53700
        Attached File- Added ode_events_struct_fix-20220916.patch, #53701

    Back to the top


    Powered by Savane 3.9