OOP and Fortran90 - oop

Hello I am trying to learn Object Oriented Programming using Fortran (all my codes are written in Fortran 90), I partially know C++ but I want to carry on using Fortran.
In Fortran you make classes employing modules. I am facing compiling errors when writing the integer, parameter :: dp = selected_real_kind(15,307) statement. Here goes my academic code. Its a short code that uses Abstract classes
module class_Rectangle
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
type Rectangle
real(dp) :: a,b
end type Rectangle
contains
subroutine area_rectangle(area,info)
implicit none
real(dp), intent(out) :: area
type(Rectangle), intent(in) :: info
area = info%a * info%b
end subroutine area_rectangle
end module class_Rectangle
program Main
use class_Rectangle
use class_Circle
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
interface compute_area
module procedure area_rectangle, area_circle
end interface compute_area
type(Rectangle) :: geoA
type(Circle) :: geoB
real(dp) :: area
geoA = Rectangle(2.0d0,4.0d0)
call area_rectangle(area,geoA)
write(*,*) 'Rectangle area:', area
geoB = Circle(1.0d0)
call area_circle(area,geoB)
write(*,*) 'Circle area:',area
end program Main
The message that the compiler returns me is the following:
integer, parameter :: dp = selected_real_kind(15,307)
1
Error: Name 'dp' at (1) is an ambiguous reference to 'dp' from module 'class_rectangle'
Main.f90:81.13:
real(dp) :: area
1
Error: Name 'dp' at (1) is an ambiguous reference to 'dp' from module 'class_rectangle'
Main.f90:84.30:
Any hint or advice is welcome.

Always try to use USE statement with ONLY. If you do so, you will not encounter the ambiguity error you get. In addition, you will know exactly what is being used in your code from each module, just by a quick look at the top lines of your code. Therefore, your main program header could look like this:
program Main
use class_Rectangle, only: Rectangle, area_rectangle
use class_Circle, only: Circle, area_circle
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
interface compute_area
module procedure area_rectangle, area_circle
end interface
type(Rectangle) :: geoA
type(Circle) :: geoB
real(dp) :: area
geoA = Rectangle(2.0d0,4.0d0)
call area_rectangle(area,geoA)
write(*,*) 'Rectangle area:', area
geoB = Circle(1.0d0)
call area_circle(area,geoB)
write(*,*) 'Circle area:',area
end program Main
For a good tutorial on OOP programming in Fortran with some good examples, see the book "Modern Fortran Explained" by Metcalf et al.

Depending on your compiler, you should get pretty helpful messages
module a
end module a
program b
implicit none
use a
end program b
And compile:
$ gfortran mod_test.F90
mod_test.F90:6:9:
implicit none
2
use a
1
Error: USE statement at (1) cannot follow IMPLICIT NONE statement at (2)

Just omit: integer, parameter :: dp = selected_real_kind(15,307)
in the main program! By USEing class_Rectangle the main program it
shares this variable with the module (except you declare it private,
which is not what you want here I guess).

Related

Making module variables private

During the last few years, I have been creating several modules with subroutines that I then use for different projects. I am having problems when I define parameter variables in one of those project-specific files that conflict with a variable name defined within those modules. Is it possible to make those names subroutine-private or module-private?
Here is an example. Suppose I have the following module:
module mymod
implicit none
contains
subroutine test1(x)
real, intent(in) :: x(:)
print *, x**2.0
end subroutine test1
end module mymod
This module is then called by the main program
program main
use mymod
implicit none
real :: y
real,dimension(2,1),parameter :: x = [1.0,2.0]
y = 3.0
call test1(y)
end program main
In this case, given that x in the main program is defined as a parameter with different dimensions to the x in subroutine test1, there will be problems when compiling (shape matching rules violated). Is there any way of making x in module mymod private within the module?
I know an option could be to use "non-common" variable names in my modules or have a list of forbidden names, but that seems complicated at this point (requires editing too many files and lose consistency of notation with books/papers where these procedures are outlined), and would make collaboration with colleagues more difficult.
Two different questions in one:
Why is the example program failing to compile:
This has nothing to do with public or private, or x being defined in the program itself.
It has everything to do with the fact that in the module, x as a parameter is defined as a 1-d array, and in the main program, y is a scalar.
Try it, remove the declaration of x in the main program and it will still fail.
(In fact, the declaration doesn't work like that anyway, you declare x as a 2-d array (shape 2, 1), but then give it a 1-d array. You'd have to do something like:
real, dimension(2, 1), parameter x = reshape([1.0, 2.0], [2, 1])
But to get rid of the error you describe, you either need to change the subroutine interface by removing the (:) behind the real, intent(in) :: x, or change the call to call test1([y]).
What can you do when 2 modules import different variables of the same name:
It would be different if you were to say have this:
module modA
implicit none
real, parameter :: x = 2.0
contains
subroutine subA(k)
real, intent(in) :: k
print *, k*x
end subroutine subA
end module modA
module modB
implicit none
real :: x(3)
end module modB
program progtest
use modA
use modB
implicit none
call subA(x(1))
end program progtest
In this example, it would try to import the variable x from both modules.
Ways to avoid it:
Make one x private:
implicit none
real, parameter, private :: x = 2.0
or
real, parameter :: x = 2.0
private :: x
or
implicit none
private
real, parameter :: x = 2.0
public :: subA
Only import the parts that you need:
program progtest
use modA, only: subA
use modB
implicit none
...
Rename one or both of the x:
use modA
use modB, only: xB => x
...
call subA(xB(1))

Calling type-bound procedure for an array of derrived types in Fortran

Let's assume that I have a derived type Coordinates with its type-bound procedure swap:
module myTypes
implicit none
public :: Coordinates
type Coordinates
real :: x,y
contains
procedure :: swap ! Error here
end type
contains
subroutine swap(this)
class (Coordinates) :: this
this%x = this%x + this%y
this%y = -(this%y - this%x)
this%x = this%x - this%y
end subroutine
end module
Now, if I have an instance of Coordinates called point_A, and if I want to call the type-bound procedure swap for it, I would just write: call point_A%swap. But if I have an array of instances of Coordinates, like:
type(Coordinates), dimension(:), allocatable :: setOfPoints
then to call the swap for all the elements of setOfPoints, I would like to write:
call setOfPoints(:)%swap
In order to achieve that, I change the code of swap procedure to:
subroutine swap(these)
class (Coordinates), dimension(:) :: these
integer :: i
do i = 1, size(this)
this(i)%x = this(i)%x + this(i)%y
this(i)%y = -(this(i)%y - this(i)%x)
this(i)%x = this(i)%x - this(i)%y
end do
end subroutine
Unfortunately, gfortran doesn't like my idea. On the line that I marked in the first piece of code it says:
Error: Passed-object dummy argument of 'swap' must be scalar.
Question: how can I call the type-bound procedure for all the instances of the derived type at once? I don't want to put the call in the loop, but I want to do this as I wrote it before, like what we always do with arrays in Fortran.
I read about the ELEMENTAL keyword, but if I want to use it, I need the type-bound procedure to be 'pure', which is not my case.
I tried to place a DEFERRED keyword after the word procedure, but then compiler says:
Error: Interface must be specified for DEFERRED binding
I created an interface for swap, but I couldn't figure out where to place it. I tried many positions and compiler said that 'interface was unexpected there'.
Also, I read about SELECT TYPE, but I think it won't help in my case.
Your specific example is perfectly fine with ELEMENTAL
module myTypes
implicit none
public :: Coordinates
type Coordinates
real :: x,y
contains
procedure :: swap ! Error here
end type
contains
elemental subroutine swap(this)
class (Coordinates), intent(inout) :: this
this%x = this%x + this%y
this%y = -(this%y - this%x)
this%x = this%x - this%y
end subroutine
end module
use myTypes
type(Coordinates) :: arr(10)
arr = Coordinates(1.,2.)
call arr%swap
end
Your subroutine is pure. If it cannot be, consider using impure elemental.

Resolving procedure confusion when using OOP

I am writing a vector type in Fortran and am getting very confused.
Suppose I have the following derived type
Type (Vector)
Real :: x, y
Contains
Procedure :: vector_smul
End Type
Function vector_smul &
( &
va, vb &
) &
Result (c)
Real :: c
Class (Vector), Intent (In) :: va, vb
c = (va%x + vb%x) + (va%y * vb%y)
End Function vector_smul
However when I use
Type (Vectors)
Real :: x, y
Contains
Procedure :: smul => vector_smul
End Type
I get an error when I use
Program Test
Use Vector
Implicit None
Real :: c
Type (Vector) :: va, vb
c = smul (va, vb)
End Program
You are just defining a type-bound procedure xyz%smul that points to vector_smul! The original module procedure vector_smul is not effected!
To stay in the terminology of the Fortran Standard (2008, ch. 4.5.5), smul is the binding name for the procedure name vector_smul. You still can access the procedure itself.
You can "rename" the function when using it in the main program:
Program Test
Use Vector, only: Vector, smul => vector_smul
Implicit None
Real :: c
Type (Vector) :: va, vb
c = smul (va, vb)
End Program
[Although it is not possible to have the same name for the type different and the module, i.e. not name them both Vector...]
Take a look at the corresponding topic at the Fortran Wiki...

Fortran tips in large modules

I have a module that consists of many small subroutines and one main subroutine, which is the only one that is public. The rest of the subroutines are private and called by the main subroutine or within them. The main subroutine has to take all the necessary arguments to perform its work, but often when it delivers a task to a private subroutine, it has to pass again some of the arguments. I would like to avoid this when dealing with arrays. With scalar numbers I can simply define a module wide variable and assign it the corresponding value in the main subroutine:
module test
integer, private :: m, n
private :: foo
public :: main
contains
subroutine main(matrixA, m0, n0)
integer, intent(in) :: m0, n0
real, intent(inout) :: matrixA(m0,n0)
!assign values to module variables m & n
m = m0
n = n0
...
!no need to pass m0 & n0
call foo(matrixA)
end subroutine
subroutine foo(matrixA)
real, intent(inout) :: matrixA(m,n)
...
end subroutine
end module
I would like to also not need to pass matrixA at all. What is the best way to do this? By best, I mean giving the best performance.
I can't comment on the "best" way, but there are some things to say. And now the question has been edited to point "best" in the direction of performance I'll add something else.
The question appears to be made under the premise that arrays cannot be module variables. They can be, even allocatable/pointer (deferred-shape) ones.
In the examples that follow I'll make the assumption that the array dummy argument in main will be assumed-shape. This is just to make things simpler in the form; changing to explicit-shape is a simple extension.
First, just like we set m and n in the question, we can set a module array variable.
module test
private ! Have this as default
public main ! But we do want a way in
integer m, n
real, allocatable :: matrixA(:,:)
contains
! In this subroutine we're making an assumption that the person asking isn't
! wholly correct in not wanting to assume shape. But we can change that if
! required. It's just a more natural thing if one can.
subroutine main(matrix) ! Note, not passing m, n
real, intent(inout) :: matrix(:,:) ! It's assumed shape
m = SIZE(matrix,1)
n = SIZE(matrix,2)
matrixA = matrix ! Copy in to the module's matrixA
call foo()
! .... etc.
matrix = matrixA ! Copy back out to the dummy
end subroutine main
subroutine foo
! Here we have access to the module's matrixA
! And we do our stuff
end subroutine foo
end module test
Note the use of the assumed-shape dummy argument and the discussion above. To avoid copying in this example, one could think about whether using a pointer is a suitable thing.
With the copy, that's not going to be good performance (assuming the array is biiig). So:
module test
implicit none
private
integer m, n ! If we want these we'll have to set them somehow
real, allocatable, public :: matrixA(:,:)
public main
contains
subroutine main()
! Stuff with matrixA host-associated
end subroutine main
end module test
program hello
use test, only : matrixA, main
implicit none
matrixA = ... ! Set this: it's matrixA from the module
call main
end program hello
As we care about "performance" rather than "encapsulation" that seems like a reasonable thing. However, having encapsulation, performance and reduced-argument passing, we could consider, rather than using a module variable for matrixA, having the work subroutines internal to main.
module test
contains
subroutine main(matrixA)
real, intent(inout) :: matrixA(:,:)
call foo
contains
subroutine foo
! Here we have access to matrixA under host association
end subroutine foo
end subroutine main
end module test
In many circumstances I prefer this last, but wouldn't say it's best, or even preferred under all circumstances. Note, in particular, that if foo already has an internal subprogram we'll start to wonder about life.
I feel the first is rather extreme just to avoid passing as an argument.

File IO using polymorphic datatypes in Fortran

I am writing a library for importing geometries of many types (spheres,planes,NURBS surfaces, stl files...) into a scientific Fortran code. This kind of problem seems taylor-made for OOP because it is simple to define a type :: geom and then type,extends(geom) :: analytic and so on. The part I am having trouble with is the file IO.
My solution at this point is to write the parameters defining the shapes, including some flags which tell me which shape it is. When reading, I instantiate a class(geom) :: object, (since I don't know ahead of time which subtype it will be) but how can I read it?
I can't access any of the specific components of the subtype. I read that downcasting is verboten, and besides, the new allocate(subtype :: class) doesn't seem to work. The new READ(FORMATTED) doesn't seem to be implemented by ifort or gfortran. i.e.
module geom_mod
type :: geom
end type
type,extends(geom) :: sphere
integer :: type
real(8) :: center(3),radius
contains
generic :: READ(FORMATTED)=> read_sphere ! not implemented anywhere
end type
contains
subroutine read_geom(object)
class(geom),intent(out),pointer :: object
integer :: type
read(10,*) object%type ! can't access the subtype data yet
read(10,*) type
backspace(10)
if(type==1) then
allocate(sphere :: object)! downcast?
read(10,*) object ! doesn't work
end if
end read_geom
end module
Am I going about this all wrong? I could hack this using something other than polymorphism, but this seems cleaner everywhere else. Assistance would be greatly appreciated.
EDIT: sample program using IanH's module
program test
use geom_mod
implicit none
class(geom),allocatable :: object
open(10)
write(10,*) '1'
write(10,*) sphere(center=0,radius=1)
rewind(10)
call read(object) ! works !
end program test
Current gfortran and ifort do not implement defined input/output. I have not seen any evidence that this situation will change in the near future. However, apart from allowing some syntactic shortcuts that feature does not actually save you much work here.
One approach for this situation is to call a "factory" for extensions of geom that uses the data in the file to allocate the argument to the correct type, then hand off to a type bound procedure that reads in the type specific data. For example:
module geom_mod
implicit none
integer, parameter :: dp = kind(1.0d0)
type, abstract :: geom
contains
procedure(read_geom), deferred :: read
end type geom
abstract interface
subroutine read_geom(object)
import :: geom
implicit none
class(geom), intent(out) :: object
end subroutine read_geom
end interface
type, extends(geom) :: sphere
real(dp) :: center(3), radius
contains
procedure :: read => read_sphere
end type sphere
contains
subroutine read(object)
class(geom), intent(out), allocatable :: object
integer :: type
read (10, *) type
! Create (and set the dynamic type of object) based on type.
select case (type)
case (1) ; allocate(sphere :: object)
case default ; stop 'Unsupported type index'
end select
call object%read
end subroutine read
subroutine read_sphere(object)
class(sphere), intent(out) :: object
read (10, *) object%center, object%radius
end subroutine read_sphere
end module geom_mod
Current ifort (12.1.5) has issues with intent(out) polymorphic arguments that may require workarounds, but the general approach remains the same.
(Note that the subroutine read is not a type bound subroutine - to read a generic geom object use ''call read(object)'' in the conventional subroutine reference style.)