Does Fortran have a standard function/keyword equivalent for C assert?
I could not find assert mentioned in Fortran2003 standard I have. I have found few ways how to use pre-processor, but in this answer it is suggested to write own assertions. Is it possible to create such user function/subroutine without using pre-processor?
I expect that these assertions are disabled for release builds.
Conditional compilation has never really caught on in Fortran and there isn't a standard pre-processor. If getting your pre-processor to switch in and out a dummy assert routine isn't something you want to tackle you could ...
Define a global parameter such as:
logical, parameter :: debugging = .true.
If you are of a nervous disposition you could put this into a module and use-associate it into every scope where it is needed; to my mind using a global parameter seems a reasonable approach here.
Then write guarded tests such as
if (debugging) call assert(...)
Once you want to release the code, set the value of debugging to .false. I expect, though I haven't tested this so you may care to, that any current Fortran compiler can remove dead code when it encounters an expression equivalent to
if (.false.) call assert(...)
and that your released code will pay no penalty for a dummy call to an assert routine.
Another approach might be to create a module, let's call it assertions, along these lines:
module assertions
contains
subroutine assert_prd(args)
! declare args
end subroutine
subroutine assert_dbg(args)
! declare args
! now do do some assertion checking and exception raising, etc
end subroutine
end module assertions
You could then rename the subroutines when you use-associate them, such as:
use, non_intrinsic :: assertions, assert=>assert_dbg
and change that to assert=>assert_prd when you want to turn off assertion checking. I suspect though that compilers may not eliminate the call to the empty subroutine entirely and that your production code might pay a small penalty for every assertion it encounters.
Beyond this, see the paper by Arjen Markus that #AlexanderVogt has referred you to.
To my knowledge, there is no such statement or function/subroutine in Standard Fortran. But - as you have said - you can use your own subroutines/function and/or OOP in Fortran to realize this goal. See Arjen Markus' excellent paper on this topic.
For fixed form sources, one can use -fd-lines-as-comments for release builds and -fd-lines-as-code for debug build (Intel Fortran -d-lines)
and use custom assert:
D if (assert_condition) then
D write(*,*) 'assert message'
D call exit(1)
D endif
Related
I have a FORTRAN code with a routine:
SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA)
integer ncid, recid
character*(*) varname
real*8 vardata
dimension vardata(15,45,75)
etc.
I want to add some flexibility to this code, and I thought I would do it by first adding an optional flag argument:
SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA, how_to_calculate)
! everything the same and then ...
logical, optional :: how_to_calculate
Now, at this point, I am not even using "how_to_calculate". I am just putting it into the code for testing. So I compile the code without a hitch. Then I run it, and I get an error in the subroutine. Specifically, some of the values in the code later on are "magically" altered from what they were without that optional argument. The new values don't make sense to the logic of the code, so it exits politely with an error message. Let me stress again that at this point, I am not even using this optional argument. So then, on a lark, I go back to all the places in the source that call this routine and, even though my new argument in optional, I put in values for it in all the calls. When I do that, the code runs fine. So, what's up? How can the mere presence of an unused optional argument in a subroutine result in other data being corrupted? And how can adding input parameters for this optional argument fix things again? This is being compiled with PGI, by the way.
Any ideas? Thanks.
BTW, sorry for not providing more code. My boss might not be too happy with me if I did that. I don't make the rules; I just work here.
Optional arguments in Fortran are implemented by passing 0 (a null pointer) for each optional argument that has no value provided by the calling subroutine. Because of this subroutines that take optional arguments have to:
either have an explicit INTERFACE definition inside the calling subroutine
or be a module-level subroutine (for them interfaces are generated automatically)
If you add an optional argument to a subroutine but it neither has an interface in the caller or is not a module-level subroutine, then the compiler will not generate the right calling sequence - it will pass less arguments than expected. This could pose a problem on Unix systems, where PGI passes the length of all CHARACTER*(*) arguments at the end of the argument list (on Windows it passes the length as the next argument after the address of the string). One missing argument would shift the length arguments placement in the stack (or put them in the wrong registers on x64) leading to the incorrect length of the VARNAME string being received by READ_NC_VALS. This could lead to all sorts of ill behaviour, including overwritting memory and "magically" changing values that should not change according to the program logic.
Obviously, just adding a dummy argument to a subroutine, with or without the optional attribute, shouldn't cause any problems. What might happen, though, is that the change exposes some other problem with the code, which was already there, but didn't cause any visible bad effects.
Without any more code, all we can do is guess, which usually isn't really useful.
One thing that pops into mind is the necessity of an explicit interface, when using optional arguments. Is the code organized into modules?
I'm trying to pass a parameter between a Fortran main program and a subroutine. However for some reason a different value is obtained in the subroutine. I am using common blocks.
program main
nzcur=1
write(*.*)"nzcur in main",nzcur
call hit
subroutine hit
common/part/nzcur
write(*,*)"nzcur in hit",nzcur; pause
end
end program
I would expect nzcur=1 but I get nzcur=0.
I think it could be a data type mismatch as I do not define it, only as a common block.
As noted in the comments, the correct learning response to this question is to avoid using common blocks to have access to variables from other scopes. In writing code in the modern era there are far better ways (more later).
Fortunately, however, we can look at this question in terms of "how do I understand what is happening with this common block?". Such a question is useful to those unfortunate programmers trying to understand old (or badly written new) code.
In considering the program of the question one should note that several corrections are required to have compilable code (with different possible approaches). The errors there are not directly relevant to the discussion.
In the subroutine
subroutine hit
common/part/nzcur
write(*,*)"nzcur in hit",nzcur; pause
end
we have a named common block called part, with one numeric storage unit which contains the integer variable nzcur (thanks to implicit typing).
In the question there is clearly the expectation that the variable nzcur in this common block accesses some other variable called nzcur and that this other variable is the one in the main program called nzcur. This is not correct.
nzcur in the subroutine is associated only with the first numeric storage unit of any other common block named part. The association is not based on named or location in the common block definition.
In the program of the question, there is no other common block called part; nzcur of the subroutine is not associated with anything else. It is certainly not associated with a variable not in a common block.
Because of this lack of association, the variable is not defined by the time the write statement references it. Again, the definition of the variable in the main program does not affect the definition of the local variable in the subroutine.
To "correct" the association, it will be necessary to put the variable nzcur of the main program in the correct location in a common block named part (in the main program).
To answer the question of "how do I set the value of nzcur in the subroutine without using common blocks?", refer to other questions such as this one.
Example
Suppose I want to write an elemental function that checks its arguments, as in the following toy example:
elemental real function square_root( x )
real, intent(IN) :: x
if (x<0) then
print *, "Error in square_root(): the variable x must be non-negative."
stop 1
endif
square_root = sqrt(x)
end function square_root
Motivation
Marking a procedure as elemental allows a flexible syntax: I can call it with a scalar or with a multi-dimensional array with no change in calling syntax. This is awesome.
Checking argument values is generally a good practice and has helped me greatly in the past.
Difficulty
This example would not compile because elemental procedures must also be pure procedures, and neither I/O nor program terminations are permitted in pure procedures.
It appears that I can do either one of the following, but not both:
Make a function check its inputs and throw some kind of error/exception
Mark a function as elemental
Question
Is there any way to get the flexible syntax provided by elemental while also checking argument values?
I'm happy to use features of newer Fortran standards and/or invoke polymorphism (e.g. via an interface) if necessary/possible, though I hope there's an easier way!
If you wish to avoid signalling errors or exceptional situations in the arguments (for a subroutine) or function result (for a function)1 then there are options:
from Fortran 2008 elemental procedures need not be pure;
from Fortran 2018 error termination prompted by an error stop statement may commence in a pure subprogram2.
An elemental function which is not pure may be specified with the impure prefix:
impure elemental function can_io_stdout(x)
..
print *, "Hello!"
end function
For Fortran 2018 (to be published):
elemental function can_terminate(x)
..
error stop "Termination from a pure function"
end function
1 For example, one may choose to return a NaN in the case of the square root of a real.
2 As IanH notes, error termination may come about in pure procedures by means other than error stop even in earlier language revisions.
I am running an atmospheric model, and need to compile an executable to convert some files. If I compile the code as supplied, it runs but it gets stuck and doesn't ever complete. It doesn't give an error or anything like that.
After doing some testing by adding print statements to see where it was getting stuck, I've found that the executable only runs if I compile the code with a print statement in one of the subroutines.
The piece of code in question is the one here. Specifically, the code fails to run unless I put a print statement somewhere in the get_bottom_top_dim subroutine.
Does anyone know why this might be? It doesn't matter what the print statement is (currently I'm using print*, '!'). but as soon as I remove it or comment it out, the code no longer works.
I'm assuming it must have something to do with my machine or compiler (ifort 12.1.0), but I'm stumped as to what the problem is!
This is an extended comment rather than an answer:
The situation you describe, inserting a print statement which apparently fixes a program, often arises when the underlying problem is due to either
a) an attempt to access an element outside the declared bounds of an array; or
b) a mismatch between dummy and actual arguments to some procedure.
Recompile your program with the compiler options to check interfaces at compile-time and to check array bounds at run-time.
Fortran has evolved a LOT since I last used it but here's how to go about solving your problem.
Think of some hypotheses that could explain the symptoms, e.g. the compiler is optimizing the subroutine down to a no-op when it has no print side effect. Or a compiler bug is translating this code into something empty or an infinite loop or crashing code. (What exactly do you mean by "fails to run"?) Or the Linker is failing to link in some needed code unless the subroutine explicitly calls print.
Or there's a bug in this subroutine and the print statement alters its symptoms e.g. by changing which data gets overwritten by an index-out-of-bounds bug.
Think of ways to test these hypotheses. You might already have observations adequate to rule out of some of them. You could decompile the object code to see if this subroutine is empty. Or step through it in a debugger. Or replace the print statement with a different side effect like logging to a file or to an in-memory text buffer.
Or turn on all optional runtime memory checks and compile time warnings. Or simplify the code until the problem goes away, then binary search on bringing back code until the problem recurs.
Do the most likely or easiest tests first. Rule out some hypotheses, and iterate.
I had a similar bug and I found that the problem was in the dependencies on the makefile.
This was what I had:
I set a variable with a value and the program stops.
I write a print command and it works.
I delete the print statement and continues to work.
I alter the variable value and stops.
The thing is, the variable value is set in a parameters.f90
The print statement is in a file H3.f90 that depends on parameters.f90 but it was not declared on the makefile.
After correcting:
h3.o: h3.f90 variables.f90 parameters.f90
$(FC) -c h3.f90
It all worked properly.
I want to solve a differential equation lots of times for different parameters. It is more complicated than this, but for the sake of clarity let's say the ODE is y'(x) = (y+a)*x with y(0) = 0 and I want y(1). I picked the dverk algorithm from netlib for solving the ODE and it expects the function on the right hand side to be of a certain form. Now what I did with the Intel Fortran compiler is the following (simplified):
subroutine f(x,a,ans)
implicite none
double precision f,a,ans,y,tol,c(24),w(9)
...
call dverk(1,faux,x,y,1.d0,tol,ind,c,1,w)
...
contains
subroutine faux(n,xx,yy,yprime)
implicite none
integer n
double precision xx,yy(n),yprime(n)
yprime(1) = (yy(1)+a)*xx
end subroutine faux
end subroutine f
This works just fine with ifort, the sub-subroutine faux sees the parameter a and everything works as expected. But I'd like the code to be compatible with gfortran, and with this compiler I get the following error message:
Error: Internal procedure 'faux' is not allowed as an actual argument at (1)
I need to have the faux routine inside f, or else I don't know how to tell it the value of a, because I can't change the list of parameters, since this is what the dverk routine expects.
I would like to keep the dverk routine and understand how to solve this specific problem without a workaround, since I feel it will become important again when I need to integrate a parameterized function with different integrators.
You could put this all in a module, and make a a global module variable. Make faux a module procedure. That way, it has access to a.
module ode_module
double precision::a
contains
subroutine f(x,a,ans)
implicit none
double precision f,ans,y,tol,c(24),w(9)
call dverk(1,faux,x,y,1.d0,tol,ind,c,1,w)
end subroutine
subroutine faux(n,xx,yy,yprime)
implicite none
integer n
double precision xx,yy(n),yprime(n)
yprime(1) = (yy(1)+a)*xx
end subroutine faux
end module
You can check here which compilers support this F2008 feature:
http://fortranwiki.org/fortran/show/Fortran+2008+status
On that page, search for "Internal procedure as an actual argument" .
Passing an internal procedure is allowed by Fortran 2008. That means that your code is correct Fortran and just a more recent compiler is needed.
At the time when this question was posted the support for that in existing compilers was patchy. Some did support it, some did not. This changed considerably and at the time of writing this revision of the answer one can normally use it without needing to think about compiler support any more.
You are not limited to sharing the data in a module. You just have to make sure, that the containing procedure is still running. It is not possible to save the pointer and make a so called 'closure' known from LISP and many modern languages. In languages like Fortran or C the enclosing environment for future calls is not saved and pointers to internal functions become invalid.
The advantage of internal procedure over module procedure is that you can share the data without sharing it in the whole module.
It works well will reasonably old versions of GCC (gfortran), Intel Fortran and Cray Fortran (personally tested) and possibly others. I remember not being able to compile by PGI and Oracle Fortran. As shown by Daniel, it can be checked at http://fortranwiki.org/fortran/show/Fortran+2008+status (search Internal procedure as an actual argument). The most recent version of this table is periodically published in ACM SIGPLAN Fortran Forum.
There is some interesting info in this article https://stevelionel.com/drfortran/2009/09/02/doctor-fortran-in-think-thank-thunk/
Be aware that the implementation of this feature normally requires executable stack due to the use of trampolines. One does not normally think about that but if the OS forbids executable stack, the executable might fail (there were issues in initial versions of Windows Subsystem for Linux, for example).