Compiler won't recognize dp (double precision param) gfortran

This has been driving me nuts for hours.
I’m very new to fortran (mostly used to python) and I’ve been creating a mesh generator for cfd.
I got it all finished and then decided I wanted to make everything double precision.
I have a module that defines the ‘dp’ parameter and its used in my main init program.
In all the other modules it recognizes, but it won’t on this program.
Even chatgpt and deepseek can’t figure it out its crazy.
This is the error:

project1_init.f90:9:5:

    9 |     real(dp) :: y_lower,y_upper
      |     1
Error: Unclassifiable statement at (1)

This is the relevant snippet of code from the program:

program Project1Init
    use MeshInitialziation
    use Boundaries
    use DefineMesh
    implicit none

    type(Mesh) :: m1
    real(dp) :: y_lower,y_upper
    real(dp) :: x_left, x_right
    integer :: num_args, ios
    integer :: i_max, j_max
...

and this is where it should be inherited from:

module DefineMesh
    use iso_fortran_env, only: real64
    implicit none
    integer, parameter :: dp = real64
...

Any thoughts are appreciated, and if this is a dumb question, or there is already a relevant thread, let me know.
Thanks

Are the variables under DefineMesh private by default?

By the way, under DefineMesh, you can also do: use iso_fortran_env, only: dp => real64.

I don’t think it’s something directly related to the dp kind parameter, but more of something happening earlier that makes the parser fail as soon as it encounters the r of the real declaration statement.
Chech everything comung earlier carefully.

No the variables in DefineMesh are not private and they work fine in the other modules.
Thanks for the tip though.

I’m pretty sure it has at least something to do with it because I changed it to r64 and it works fine now.

program Project1Init
    use iso_fortran_env, only : real64
    use MeshInitialziation
    use Boundaries
    use DefineMesh
    implicit none
    integer, parameter :: r64 = real64


    type(Mesh) :: m1
    real(r64) :: y_lower,y_upper
    real(r64) :: x_left, x_right
    integer :: num_args, ios
    integer :: i_max, j_max

Keep in mind, I tried doing the same thing but just with dp instead of r64, and it said something about “ambiguous term”?
I don’t know.
It works fine with this shoddy quickfix, but it’s still annoying to me to not know whats going on.

Can you try to create a minimal reproducible example (MRE)? Then people can try it and figure out what is causing it.

1 Like

Do you define dp in more than one place?
I’d suggest to put everything related to kinds in a dedicated module, and use that everywhere needed.

1 Like

I did. I went and tried to make a MRE, and I found that by deleting the line use Boundaries it fixed. In the boundaries module I had made another dp parameter because DefineMesh wasn’t used in that module. I went ahead and added

use DefineMesh, only : dp
implicit none
private :: dp

to the boundaries module to fix it and it worked!
Thanks for the suggestions guys.
This statically typed stuff is really kicking me right now.
But this program was just a rewrite of a python script and it did in half a second what took python 20 seconds, so I’m glad to learn it.
Cheers!

With code such as

program main
use kind_mod
use foo_mod

there can be a problem if more than one module exports dp. To avoid this, use only clauses, giving

program main
use kind_mod, only: dp
use foo_mod, only: bar
2 Likes

Many fortran programmers do this as standard practice. With this programming style, you can look at the USE statements to see exactly where each parameter, variable, and subroutine comes from. With many modules in use, that can be quite a challenge otherwise.

2 Likes

I would add make everything in a module private by default except what you know you need to share with the rest of the world. Those you explicitly declare public. I know it can be tedious declaring things public if you have a lot of variables or routines you need to share but its only tedious once if you plan and program carefully. This approach coupled with using ONLY really cuts down on conflicts among modules and procedures

4 Likes

I have done this in a few of my modules, and it is actually more tedious that just doing it once. Every time a new entity is added to the module (a new derived type, a new variable, a new subroutine), then you must add it to the public list. I have, countless times, added something to a module, recompiled my program, and I get the error that something is not available from the module. Then I go back, realize it needed to be added also to the public list, and then it works.

Another way to have designed this feature would have been public and private blocks of a module. Everything in a public block would be public by default, and everything in a private block would be private by default. That would probably have been a better approach, but after all these decades, I think we are stuck with the current one-by-one approach.

Totally agree with this but as you say we are stuck with what we have for now. Also, I seem to remember some mention somewhere of some recent changes that address the public/private status of entities in modules USED by other modules that allow you to specify public or private on the used module without having to add that modules public or private entities to the parent modules public or private list. I probably have this all wrong since my memory isn’t what it used to be but I do seem to remember something was changed along those lines.

Fortran 2018(?) added that:

module mod1
    use ISO_C_BINDING
    integer :: dummy = 0
end module mod1
module mod2
    use mod1

    implicit none
    private

    public :: mod1
    ...
end mod2

The ifort/ifx and flang-new compilers support it, although with ifort/ifx nesting is a hit-or-miss —i.e., something USEing mod2 will see dummy but might or might not see symbols from the ISO_C_BINDING module.