Repeating a step in a Fortran loop - fortran

I'm trying to write a Fortran 90 program to carry out Euler's method to solve ode's using an adaptive time step.
I have an if statement inside of a do while loop, in which I check that the error at each iteration of the code is less than a certain tolerance. However, if it is not less than certain tolerance, I must change a certain value (the step size) and carry out the calculation again to get a new error to compare with the tolerance.
It looks something like (and forgive me this is my first time using this website):
do while (some condition)
(Get an approximation to the ODE with various subroutine calls)
(Calculate the error)
if (error < tol)
step = step/2
else
step = 2*step
(Something that will return to the top of my do while loop)
end if
end do
Say for example, I had do while (i < 4), where i starts at 1, and my error was not less than my tolerance, I would have to repeat the calculation again for i=1 with a new step size.
I hope this makes sense to those of you who read this. If you need any clarification, let me know.

Because there is no explicit counter in the do while loop unlike in a normal do i=1,... loop. you can just use cycle to start a new iteration. It will be the same as repeating the current iteration. But the condition will be evaluated again. If it shouldn't be evaluated, you would have to use go to or restructure your code.
Or another loop nested inside the main loop might be better, but that probably counts as the restructuring mentioned above. Depends what is the condition, how you change step and i and how the tolerance depends on the step and i.

Related

Is there a way to manipulate function arguments by their position number?

I wish to be able to manipulate function arguments by the order in which they are given. So,
void sum(int a, int b, int c)
std::cout<< arguments[0]+arguments[1];
sum(1,1,4);
should print 2. This feature is in JavaScript.
I need it to implement a numerical scheme. I'd create a function that takes 4 corner values and tangential direction as input. Then, using the tangential direction, it decides which corners to use. I wish to avoid an 'if' condition as this function would be called several times.
EDIT - The reason why I do not wish to use an array as input is for potential optimization and readability reasons. I would explain my situation a bit more. solution is a 2D array. We would be running this double for loop several times
for (int i = 0;i<N_x;i++)
for (int j = 0;j<N_y;j++)
update_solution(solution[i,j],solution[i+1,j],solution[i-1,j],...);
Optimization: N_x,N_y are large enough for me to be concerned about whether or not adding a step like variables_used = {solution(i,j),solution(i+1,j),...} in every single loop will increase the cost.
Readability The arguments of update_solution indicate which indices were used to update the solution. Putting that in the previous line is slightly non-standard, judging by the codes I have read.

When to use machine epsilon and when not to?

I'm reading a book about rendering 3d graphics and the author sometimes uses epsilon and sometimes doesn't.
Notice the if at the beginning using epsilon and the other ifs that don't.
What's the logic behind this? I can see he avoids any chance for division by zero but when not using epsilon in the function there's still a chance it will return a value that will make the outer code to divide by zero.
Book is Real-Time Rendering 3rd Edition, by the way.
The first statement, if(|f| > ϵ) is just checking to make sure f is significantly different from 0. It's important to do that in that specific spot in the code because the next two statements divide by f.
The other statements don't need to do that, so they don't need to use ϵ.
For example,
if(t1 > t2) swap(t1, t2);
is a self-contained statement that compares two numbers to each other and swaps them if the wrong one is greater. Since it's not comparing to see if a value is close to 0, there's no need to use ϵ.
If the value that is returned from this block of code can make the calling code divide by zero, that should be handled in the calling code.

Interval branching

A project (C++11) I am working on involves a block of code that will be run somewhere in the trillions of times. I have an integer parameter B in [1,N] and points 1 = b1 < b2 < ... < bk = N where the code executes a different small block of code depending on which interval [bi, b(i+1)) B lies in. The only value that is changing throughout execution is B. However while the value of the bi's are fixed, they are only determined at runtime.
The naive thing to do is to write a bunch of if and else if statements, which at worst case involves k comparisons. However one can do this in constant time: construct a vector myGotos of size N and on each interval [bi, b(i+1)) store the location of the corresponding code block. Then you just do goto myGotos[B].
The solution above seems to me like it would be on average quicker, but the code would be quite ugly. I was wondering if there is a better way to do this.
The common way to do this is with a switch statement
switch(B){
case b1:..//
break;
}
If you can declare those sections of code as lambdas or std::function provided they took the same arguments.Even a templated function might be ok. Its tough to answer without knowing what you actually need to run these functions.
map<int,decltype(yourLambda)>
Seems like it would work ok as well.
Initialize an array of N slots, let K, where each slot contains the index of the containing interval.
Then
switch (K[B])
{
case 1: // [B1,B2)
...
}

Modelica Evaluation Order

I can't really find any answer in the Modelica specification so ill ask you guys. The specification states that
A tool is free to solve equations, reorder expressions and to not evaluate expressions if their values do not influence the result (e.g. short-circuit evaluation of Boolean expressions). If-statements and if-expressions guarantee that their clauses are only evaluated if the appropriate condition is true, but relational operators generating state or time events will during continuous integration have the value from the most recent event.
If a numeric operation overflows the result is undefined. For literals it is recommended to automatically convert the number to another type with greater precision.
Now, I wonder, can the tool choose to evaluate an expression several time in an integrator step? For example (probably not an valid example, just to give you guys an idea of what I was wondering :) )
Real x;
equation
der(x) = -t;
Modelica.Utilities.Streams.print(String(time));
This will print the same time for several times, so I figured that there is some kind of iteration going on. But I would really like to have it confirmed by some source.
That is normal.
Variable step size solvers (like dassl) can go back
and forth in time to find the direction of the curve.
Also, if you have events more values can be generated
at the same time.
If you want to print time or values just at exact time instants you need when equations:
when sample(0, 1) then
Modelica.Utilities.Streams.print(String(time));
end when;
Read more in the Modelica Spec about sample.
Is also possible to use fixed step size solvers like Euler or so.

Efficient convergence check

I have a grid with thousands of double precision reals.
It's iterating through, and I need it to stop when it's reached convergence to 3 decimal places.
The target is to have it run as fast as possible, but needs to give the same result every (to 3 dp) every time.
At the minute I'm doing something like this
REAL(KIND=DP) :: TOL = 0.001_DP
DO WHILE(.NOT. CONVERGED)
CONVERGED = .TRUE.
DO I = 1, NUM_POINTS
NEW POTENTIAL = !blah blah blah
IF (CONVERGED) THEN
IF (NEW_POTENTIAL < OLD_POTENTIAL - TOL .OR. NEW_POTENTIAL > OLD_POTENTIAL + TOL) THEN
CONVERGED = .FALSE.
END IF
END IF
OLD_POTENTIAL = NEW POTENTIAL
END DO
END DO
I'm thinking that many IF statements can't be too great for performance. I thought about checking for convergence at the end; finding the average value (summing the whole grid, divide by num_points), and checking if that has converged in the same way as above, but I'm not convinced this will always be accurate.
What is the best way of doing this?
If I understand correctly you've got some kind of time-stepping going on, where you create the values in new_potential by calculations on old_potential. Then make old equal to new and carry on.
You could replace your existing convergence tests with the single statement
converged = all(abs(new_potential - old_potential)<tol)
which might be faster. If the speed of the test is a major concern you could test only every other (or every third or fourth ...) iteration
A few comments:
1) If you used a potential array with 2 planes, instead of an old_ and new_potential, you could transfer new_ into old_ by swapping indices at the end of each iteration. As your code stands there's a lot of data movement going on.
2) While semantically you are right to have a while loop, I'd always use a do loop with a maximum number of iterations, just in case the convergence criterion is never met.
3) In your declaration REAL(KIND=DP) :: TOL = 0.001_DP the specification of DP on the numerical value of TOL is redundant, REAL(KIND=DP) :: TOL = 0.001 is adequate. I'd also make this a parameter, the compiler may be able to optimise its use if it knows that it is immutable.
4) You don't really need to execute CONVERGED = .TRUE. inside the outermost loop, set it before the first iteration -- this will save you a nanosecond or two.
Finally, if your convergence criterion is that every element in the potential array has converged to 3dp then that is what you should test for. It would be relatively easy to construct counterexamples for your suggested averages. However, my concern would be that your system will never converge on every element and that you should be using some matrix norm computation to determine convergence. SO is not the place for a lesson in that topic.
What are the calculations for the convergence criteria? Unless they are worse then the calculations to advance the potential it is probably better to have the IF statement to terminate the loop as soon as possible rather than guess a very large number of iterations to be sure to obtain a good solution.
Re High Performance Mark's suggestion #1, if the copying operation is a significant portion of the run time, you could also use pointers.
The only way to be sure about this stuff is to measure the run time ... Fortran provides intrinsic functions to measure both CPU and clock time. Otherwise you may modify your some portion of you code to make it faster, perhaps making it less easier to understand and possibly introducing a bug, possibly without much improvement in runtime ... if that portion was taking a small amount of the total runtime, no amount of cleverness will can make much difference.
As High Performance Mark says, though the current semantics are elegant, you probably want to guard against an infinite loop. One approach:
PotentialLoop: do i=1, MaxIter
blah
Converged = test...
if (Converged) exit PotentialLoop
blah
end do PotentialLoop
if (.NOT. Converged) write (*, *) "error, did not converge"
I = 1
DO
NEWPOT = !bla bla bla
IF (ABS(NEWPOT-OLDPOT).LT.TOL) EXIT
OLDPOT = NEWPOT
I = MOD(I,NUMPOINTS) + 1
END DO
Maybe better
I = 1
DO
NEWPOT = !bla bla bla
IF (ABS(NEWPOT-OLDPOT).LT.TOL) EXIT
OLDPOT = NEWPOT
IF (I.EQ.NUMPOINTS) THEN
I = 1
ELSE
I = I + 1
END IF
END DO