-
-
Notifications
You must be signed in to change notification settings - Fork 49
Conversation
In general, I would prefer something a little cleaner than a line-for-line port of Fortran 77 code, although that is a good baseline starting point for comparison to later efforts. |
We do not have a style of documentation yet, but it would be very nice if you added a file (eg. We should also have a |
Regarding the tests, you can have a look at |
There is an interesting efficiency question here: the problem with I think that probably the best thing would be to have a low-level interface in which you pass a subtype of type ODEProblemFunction <: ODEProblem
f::Function
end
F!(p::ODEProblemFunction, y, x, t) = copy!(y, p.f(x,t))
odeXX(f::Function, ....) = odeXX(ODEProblemFunction(f), ...) The That way, if the user needs greater efficiency, they could define their own |
@ivarne, a generic It is just nice to have an interface where the user can pass a function for simplicity; I view forcing the user to define their own type as a low-level interface that users can ignore unless it is needed. |
@stevengj Sorry, I read your comment again and you are completely right. We had very similar ideas, but I focused too much on the implementation detail for allowing anonymous functions in my comment. |
There seems to be a lot of code here that just defines a million variables for various parameters. Is there some logical way to group them to make the code more readable? I'm not familiar enough with these methods to be able to look at it at a glance and determine, but the current effort for
If that is possible, it would make for much easier addition of new solvers to the family. It will also make it easier to "hide" all the ugly parameter definition stuff from the implementation code and increase legibility, since we can just define all the parameter objects last. |
First of all many thanks for the valuable feedback everybody! @tlycken Sounds like a good idea to me. @stevengj & @acroy Did I understand correctly that the current approach to passing parameters to the callback requires that the callback function is defined in the same scope as the parameters? I think this might be impractical if a library contains "reusable" callbacks and only the parameters are read from input files. Are there any reasons why we should not use a |
Reasons to not use a
@helgee I think I understand why you ask, but I don't see the issue with scope and |
@ivarne You misunderstood me there. When one uses the low-level API with |
I would really prefer to have only one interface, but unfortunately the most intuitive interface is slow, and we need better options for performance critical cases. The question is how advanced cases we need to support for the simple interface, and when we want to say, "use this faster interface instead for complex problems." |
@helgee, we don't need a My suggestion is that all of our library implementations use the low-level (object-passing) interface, and that we provide (one-line) wrappers to support the high-level (function-passing) interface(s). |
What is the current status of DOP853? Is anyone still actively developing it? What remains to be done (dense output, etc)? |
@berceanu I don't know if @helgee is still doing any work on this, and I haven't taken a close look at the code to see what has already been done and what has not. I suspect you could help out e.g. by creating pull requests against his fork - when he merges them into his branch, the commits will automatically be added to this pull request. Take a look at doc/api.md for the latest discussion about what the API should look like. |
@tlycken I'm quite new to github. Could you please explain the "pull requests against his fork" suggestion in more detail? I already have a new version of his code, so how can I contribute? |
@berceanu It is hard to know what level of detail you want the explanation on. Please ask (or search) if you need more specific directions.
cd ~/.julia/ODE.jl
git remote add helgee [email protected]:helgee/ODE.jl.git
git remote add fork [email protected]:berceanu/ODE.jl.git
git checkout -b DOP853 --track helgee/master
git commit
git push fork DOP853 |
@berceanu I'll make an attempt to explain what I mean =) Basically, the most common way to organize work in open-source github projects is to have a main repo (the To facilitate code review and collaboration, Github was designed so that a pull request isn't static - if you push more commits to the branch in This opens a nice possibility to "chain" pull requests - if you see someone working on a PR, and you want to contribute something to their contribution, you can fork their fork and request that your changes are merged into there, instead of into the original source. In other words, it is entirely possible to create Finally, it's noteworthy that you don't really have to create I've used this pattern a couple of times when I wanted to help finish the work on a PR that someone else started, without having to first wait for that PR to get merged. Depending on whether @helgee still wants to invest anything in this PR, this is either a good idea or not - if Helge is still in, this approach helps the two of you to finish this functionality without having to wait for action from us ODE.jl people. However, if he's not, you'll get stuck waiting even longer for him to get back to you, than you'd have to wait for us. In that case, it might be better to merge his branch into your fork, do some more work, and create a new pull request against ODE.jl. Is this making any sense to you? =) |
Please excuse the long radio silence but my day job was keeping me busy. I am still interested in getting this merged and got started with the dense output functionality some weeks ago. Porting the numerical bits is actually straightforward. The challenge lies in defining a sensible and suffciently julian API and I have not made much progress there. |
Although I think dense output would/will be a really great feature, I just wanted to point out that But of course I don't want to discourage anyone from contributing to the dense output! |
Are you using the same tolerances? ( |
Yes, the tolerances are the same. |
The Julia version begins to deviate from the Fortran version after 4 integration steps. The time steps are identical though. Could this be due to differences in the floating point model? @acroy The Fortran version is three orders of magnitude more precise for problem A3. I guess there is something wrong with the Julia code then. |
|
||
copy!(y, y0) | ||
facold = 1e-4 | ||
expo1 = 1.0/8.0 - beta*0.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT, dopri5.f
uses EXPO1=0.2D0-BETA*0.75D0
here. Not sure it matters ...
I tracked down where the solutions start to deviate in the A3 problem and this either an upstream Julia problem or I am doing something awfully wrong. At that point Julia and Fortran do the same calculations with numerically indistinguishable numbers and get slightly different results. The error then probably grows due to the numerical method. I have also tried the specific calculation in C and Python and they agree with the Fortran result. Have a look at the code here: https://gist.github.com/helgee/f179b9610aa104e38966 Julia output:
C, Fortran, Python output:
What is going on? |
The difference is that C, Fortran and Python uses system libm implementation for You can compile julia with f(t,y) = y*ccall(("cos","libc"),Float64,(Float64,),t) The reason Julia uses openlibm is that people were reporting bugs in their system libm implementations and blamed Julia for being slow or wrong. |
@ivarne Correct, I'll keep on searching then. |
That might explain some deviations between Julia and C etc, but it doesn't explain why the deviation from the known solution in Julia is so large. Does |
@acroy No. See the updated results: https://gist.github.com/helgee/0eef2ca36afb4339710d |
Well, I was actually writing the wrong variable into the output array for Now the Fortran and Julia versions agree perfectly for A3 (with OSX's libm) and the maximum deviation from the known solution is at ~1e-6. |
Now both integrators deliver the exact same results as the Fortran versions. Embarrasingly there was also a bug in my Fortran code, which I used for checking the results. A lot of searching in the wrong place :-P |
In any case it is great that you found the error! On Wednesday, July 2, 2014, Helge Eichhorn [email protected] wrote:
|
h = hnew | ||
idid = 1 | ||
if points == :last | ||
return x, y1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to use
push!(tout, x)
push!(yout, y1)
in order to be type stable (otherwise the return type depends on the value of points
). Note that ATM :last
is not in the current API draft.
I apologize for letting this PR go stale. Should I continue with this or would it make more sense to just add the 8th-order Dormand-Prince coefficients to the new Runge-Kutta solvers? In that case I would still need facilities for event detection (e.g. a user function that gets called after every integration step and dense output) for ODE.jl to be useful to me. But until that is available I will use my wrapper for the Fortran codes (https://github.com/helgee/Dopri.jl). |
Adding the 8th-order coefficients would definitely be a nice contribution regardless of other things. I personally hope that event detection can be handled with the approach outlined in #49, with support across all solvers in ODE.jl, but that's quite a large undertaking. Also, I don't have the opportunity to use ODE.jl regularly anymore - and thus my ability to invest time in it is also limited - so my opinion on the matter carries very little weight nowadays :) |
I think we should stick to the current implementation for anything related to (explicit) RK methods. If you could add the 8th order coefficients this would be great. If you have ideas or needs for event functions, please post them in #11. |
Alright. I will close this then. |
It is easy to add the method to the existing RK solvers, you just need to provide a tableau like: At the moment dense output is only 3rd order. To change that would require some code changes. I hope to implement a general scheme at some point but cannot promise a time frame. Same goes for event location. |
This is an almost complete port of DOP853 (the dense output functionality is still missing) with quite good performance (https://groups.google.com/forum/#!searchin/julia-users/dop853/julia-users/41B3qULjF-0/WqGa-Lc04AkJ), approximately 2-3x slower than Fortran (without compiler optimizations) for longer runs. Since the 5-th order version DOPRI5 looks rather similar implementing it as well should not be a huge amount of work
See also: #25
To Do: