I'm thinking of using the submodule feature in Fortran and have setup a small test example. I have two questions related to their usage. Below is the example code:
module points
type :: point
real :: x, y
end type point
interface
module function point_dist(a, b) result(distance)
type(point), intent(in) :: a, b
real :: distance
end function point_dist
end interface
end module points
submodule (points) points_a
contains
module procedure point_dist
distance = sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist
end submodule points_a
This works and in my program I can just use it as such:
program test
use points
real(kind(1.0D0)) :: result
type (point) :: p1, p2
p1%x = 1
p1%y = 1
p2%x = 2
p2%y = 2
result = point_dist(p1, p2)
write(*,*) result
end program test
Questions
1) However I was wondering if it is possible to have two submodules that use the same interface but provide different outcomes. This has some uses where we have different formulae calculating the same physical quantity. Below is how I imagined it would work, even though it does not.
module points
type :: point
real :: x, y
end type point
interface
module function point_dist(a, b) result(distance)
type(point), intent(in) :: a, b
real :: distance
end function point_dist
end interface
end module points
submodule (points) points_a
contains
module procedure point_dist
distance = sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist
end submodule points_a
submodule (points) points_b
contains
module procedure point_dist
distance = 2.0*sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist
end submodule points_b
I get an error in the program as I only have the statement use points and it complains about duplicate definitions of point_dist. Is is possible to specify which submodule I want to use?
2) I also looked but couldn't find out if it is possible to use the same module level interface for different procedures inside the same submodule. In my head it would be something like:
module points
type :: point
real :: x, y
end type point
interface
module function point_dist(a, b) result(distance)
type(point), intent(in) :: a, b
real :: distance
end function point_dist
end interface
end module points
submodule (points) points_a
contains
module procedure (type=point_dist) point_dist_a
distance = sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist_a
module procedure (type=point_dist) point_dist_b
distance = 2.0*sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist_b
end submodule points_a
Although I realise that this could lead to some quite misleading and hard to follow code.
(I'm using gfortran 8.3.0 on OS X)
1) However I was wondering if it is possible to have two submodules that use the same interface but provide different outcomes. This has some uses where we have different formulae calculating the same physical quantity.
If this were possible, how were you plannig to make use of it? I mean, if you have two different implementations avaliable for a function point_dist thay may yield different outcomes, you wouldn´t want to mismatch them, would you?
If you want them to have the same name, you (and the compiler) must be able to identify which one you're calling. This is usually done with function overloading. In Fortran, you may have a generic interface. BUT the dispatched funtions MUST differ in their interface (argument types and/or quantity, position, among other rules). You know, how would anyone else know which of the two you do mean?
2) I also looked but couldn't find out if it is possible to use the same module level interface for different procedures inside the same submodule.
As I said, an interface can indeed encapsulate multiple procedures, if they are distinguishible.
module points
type :: point
real :: x, y
end type point
interface point_dist
module function point_dist_a(a, b) result(distance)
type(point), intent(in) :: a, b
real :: distance
end function
module function point_dist_b(a, b, k) result(distance)
type(point), intent(in) :: a, b
real, intent(in) :: k
real :: distance
end function
end interface
end module points
submodule (points) points_a
contains
module procedure point_dist_a
distance = sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist_a
end submodule points_a
submodule (points) points_b
contains
module procedure point_dist_b
distance = k*sqrt((a%x - b%x)**2 + (a%y - b%y)**2)
end procedure point_dist_b
end submodule points_b
Testing:
program test
use points
real(kind(1.0D0)) :: result
type (point) :: p1, p2
p1%x = 1
p1%y = 1
p2%x = 2
p2%y = 2
result = point_dist(p1, p2)
write(*,*) result
result = point_dist(p1, p2, 2.0)
write(*,*) result
end program test
As an end note, submodules have absolutely nothing to do with all this.
Related
I want to implement a generic interface in Fortran to call a function with either REAL or COMPLEX type variables. Since the function itself is quite extensive, I want to let both single interfaces access the same function body.
Using a simple addition problem as an example, i would like to have an callable interface addfun which takes two variables of either REAL or COMPLEX type and returns their sum. As mentioned before i want the functions to share the same body z = x+y to avoid having to implement it twice.
My attempt so far looks like this:
module varaddition
interface
module function add_c(x, y) result(z)
complex(kind=8) :: x,y,z
end function add_c
module function add_r(x, y) result(z)
real(kind=8) :: x,y,z
end function add_r
end interface
! defining an common interface
interface addfun
procedure :: add_c, add_r
end interface addfun
end module varaddition
submodule (varaddition) varaddition_s
contains
! attempt to set the same body to both single interfaces by simply
! assigning it to the generic interface
module procedure addfun
z = x+y
end procedure addfun
end submodule varaddition_s
program addTest
use varaddition
real(kind=8) :: xr,yr,zr
complex(kind=8) :: xc,yc,zc
xr = 1d0
yr = 2d0
zr = addfun(xr, yr)
print*, "Result using REAL type variables: ", zr
xc = complex(1d0,1d0)
yc = complex(2d0,2d0)
zc = addfun(xc, yc)
print*, "Result using COMPLEX type variables: ", zc
end program addtest
However, my approach of simply assigning the body to the generic procedure doesn't work that way. Can anyone give me a hint how to solve this?
I have a program dealing with calculations for an engine. There are multiple limiters that need to be considered (pressure ratio, temperature, ect.). These are organized from users perspective in groups, with some parameters common to all groups and some not.
Because during the run time I need to work with these limiters depending on the requirements, potentially changing them during various calculation steps it would make sense to organize these in an array of polymorphic elements, depending on what each limiter group needs. In principle it works, but not quite how I want to.
I wrote a small program to test different method shown below:
Here is the module with derived types etc.
module ArrayTest
interface init_limiter
module procedure :: initGroup1, initGroup2
end interface
type :: base
contains
procedure, pass :: setup => idontwanttodothis
procedure, pass :: print_param
end type base
type, extends(base) :: Group1
real :: p1
contains
procedure, pass :: init => initGroup1
procedure, pass :: print_param => printGroup1
end type Group1
type, extends(base) :: Group2
integer :: p1
real :: rDummy
contains
procedure, pass :: init => initGroup2
procedure, pass :: print_param => printGroup2
end type Group2
type ArrElem
integer :: a, b, c
class(base), allocatable :: param
end type ArrElem
type(ArrElem), dimension(5) :: T1, T2
contains
subroutine idontwanttodothis(self, iDummy, rDummy)
class(base) :: self
integer, optional :: iDummy
real, optional :: rDummy
select type (self)
type is(group1); call self.init(rDummy)
type is(group2); call self.init(iDummy,rDummy)
end select
end subroutine idontwanttodothis
subroutine print_param(self)
class(base) :: self
select type(self)
type is(group1); call self.print_param()
type is(group2); call self.print_param()
class default; write(*,'(A)') 'Type:: Unknown'
end select
end subroutine print_param
pure subroutine initGroup1(self, x)
class(Group1), intent(inout) :: self
real, intent(in) :: x
self.p1 = x
end subroutine initGroup1
pure subroutine initGroup2(self, x, y)
class(Group2), intent(inout) :: self
integer, intent(in) :: x
real, intent(in) :: y
self.p1 = x
self.rDummy = y
end subroutine initGroup2
subroutine printGroup1(self)
class(Group1) :: self
write(*,'(A,F5.2)') 'Type:: Group1 ',self.p1
end subroutine printGroup1
subroutine printGroup2(self)
class(Group2) :: self
write(*,'(A,I2,F5.2)') 'Type:: Group2 ',self.p1, self.rDummy
end subroutine printGroup2
end module ArrayTest
And here is the main program:
program TestAlloc
use ArrayTest
call main()
contains
subroutine main
integer i
type(group1) :: g1Dummy
!Option 1
g1Dummy.p1 = 29
allocate(T1(1).param, source = g1Dummy)
!Option 2
allocate(Group2::T1(2).param)
select type(dummy => T1(2).param)
type is(Group2); call dummy.init(12,8.7)
end select
!Option 3
allocate(Group2::T1(3).param)
call T1(3).param.setup(3, 4.5)
!Option 4
allocate(Group1::T1(4).param)
call init_limiter(T1(4).param, 8.) !this does not work
call init_limiter(g1Dummy, 8.) !this works
T2 = T1
do i=1,5
if(allocated(T2(i).param)) call T2(i).param.print_param()
end do
return
end subroutine main
end program TestAlloc
Options 1, 2 and 3 work. Option 4 doesn't. Is there any way to make this work? i.e. overload a function call for an allocatable parameter?
p.s. Overriding inherited function through child will work, but that will require both parent and children to have the same interface, which I find inconvenient, might as well use option 3 then.
To my knowledge, there is no way to make this work.
As far as the compiler is concerned, at compile time T1(4).param is of class(base), and it only becomes type(Group1) at runtime. Since you have not defined init_limiter for class(base), only for class(Group1) and class(Group2), the compiler has no appropriate init_limiter function to call.
Your init_limiter functions are not polymorphic, they simply share an interface, so the compiler has no way of treating them the same at compile time and calling the correct one at runtime using polymorphism.
p.s. Overriding inherited function through child will work, but that will require both parent and children to have the same interface, which I find inconvenient, might as well use option 3 then.
This is essentially the crux of your problem. You want to call a function with a different number of arguments depending on the runtime type of an object. Fortran is not set up to handle this case; the number and type of function arguments must be known at compile time.
One potential workaround, which you might or might not consider an improvement, is to use the select type construct. This allows you to turn runtime information (the type of T1(4).param) into compile time information (the signature of the function to call). This would look something like
allocate(Group1::T1(4).param)
select type(foo => T1(4).param); type is(Group1)
call init_limiter(foo, 8.)
end select
Let us say I have the following abstract interface to a double precision function of single argument
module abstract
abstract interface
function dp_func (x)
double precision, intent(in) :: x
double precision :: dp_func
end function dp_func
end interface
end module abstract
In a different module I define two functions, a simple one g of the type dp_func and a more complicated one f
module fns
contains
double precision function f(a,b,x)
double precision, intent(in)::a,b,x
f=(a-b)*x
end function f
double precision function g(x)
double precision, intent(in)::x
g=x**2
end function g
end module fns
Now a pointer to g can be created as follows
program main
use abstract,fns
procedure(dp_func), pointer :: p
double precision::x=1.0D0, myA=1.D2, myB=1.D1, y
p => g
y=p(x)
end program main
But how one can create a pointer to f(myA,myB,x), i.e., to f at fixed values of a and b, which can be regarded as a function of just 1 parameter, that is, of the dp_func type?
At the end result I want to be able to write something like
p=>f(myA, myB, )
y=p(x)
Comments below suggest that function closure is not a part of fortran standard and that a wrapper function would be a possible solution to it. However, the wrapper must be initialized and this introduces some chances that end user may forget to call the initializer. How one can do it in a clean and transparent way?
EDIT
After posting this question and googling with "closure and fortran", I found this example
which I present in picture form to emphasize the highlighting. This was presented in an online course. But I doubt such implicit parameter setting is a good programming practice. In fact, dangling variables like z in this example are perfect sources of errors!
You can use internal functions to wrap your functions, e.g.
program main
use abstract
use fns
implicit none
procedure(dp_func), pointer :: p
double precision :: x, myA, myB, y
x = 1.0D0
myA = 1.D2
myB = 1.D1
p => g
y=p(x)
p => f2
y = p(x) ! Calls f(1.D2, 1.D1, x)
myA = 1.D3
myB = 1.D2
y = p(x) ! Calls f(1.D3, 1.D2, x)
contains
double precision function f2(x)
double precision, intent(in) :: x
write(*,*) myA, myB
f2 = f(myA,myB,x)
end function
end program main
An internal function in a given scope can use variables from that scope, so they can act like closures.
The implicit use of myA and myB in the internal function f2 may well be a source of programming error, but, provided the scope of f2 is still in scope, this behaviour is identical to lambda functions in other languages, for example the equivalent python lambda:
f2 = lambda x: f(myA,myB,x)
As pointed out by #vladimirF, once the scope of f2 drops out of scope (e.g. if a pointer to f2 is stored and the procedure where f2 is declared returns) any pointers to f2 will become invalid. This can be seen in this code:
module bad
use abstract
use fns
implicit none
contains
function bad_pointer() result(output)
procedure(dp_func), pointer :: output
double precision :: myA,myB
myA = 1.D2
myB = 1.D1
output => f2
contains
double precision function f2(x)
double precision, intent(in) :: x
write(*,*) myA, myB
f2 = f(myA,myB,x)
end function
end function
end module
program main
use abstract
use fns
use bad
implicit none
procedure(dp_func), pointer :: p
double precision :: y,x
p => bad_pointer()
x = 1.D0
y = p(x)
end program
N.B. the above code may well run fine for this simple case, but it's relying on undefined behaviour so shouldn't be used.
You stated the following:
"...However, the wrapper must be initialized and this introduces some chances that end user may forget to call the initializer. How one can do it in a clean and transparent way?..."
The following might be a solution.
It still needs to be initialized but will throw errors if the user hasn't done so.
I defined a type closure which handles the function pointers.
! file closure.f90
module closure_m
implicit none
type closure
private
procedure(f1), pointer, nopass :: f1ptr => null()
procedure(f3), pointer, nopass :: f3ptr => null()
real :: a, b
contains
generic :: init => closure_init_f1, closure_init_f3
!! this way by calling obj%init one can call either of the two closure_init_fX procedures
procedure :: exec => closure_exec
procedure :: closure_init_f1, closure_init_f3
end type
abstract interface
real function f1(x)
real, intent(in) :: x
end function
real function f3(a, b, x)
real, intent(in) :: a, b, x
end function
end interface
contains
subroutine closure_init_f1(this, f)
class(closure), intent(out) :: this
procedure(f1) :: f
this%f1ptr => f
this%f3ptr => null()
end subroutine
subroutine closure_init_f3(this, f, a, b)
class(closure), intent(out) :: this
procedure(f3) :: f
real, intent(in) :: a, b
this%f1ptr => null()
this%f3ptr => f
this%a = a
this%b = b
end subroutine
real function closure_exec(this, x) result(y)
class(closure), intent(in) :: this
real, intent(in) :: x
if (associated(this%f1ptr)) then
y = this%f1ptr(x)
else if (associated(this%f3ptr)) then
y = this%f3ptr(this%a, this%b, x)
else
error stop "Initialize the object (call init) before computing values (call exec)!"
end if
end function
end module
Concerning the lines class(closure), intent(out) :: this:
This is the standard way of writing initializers for Fortran types.
Note that it is class instead of type which makes this polymorphic as is needed for type-bound procedures.
I slightly adjusted your functions module (changed data types)
! file fns.f90
module fns_m
contains
real function f(a, b, x)
real, intent(in) :: a, b, x
f = (a-b)*x
end function
real function g(x)
real, intent(in) :: x
g = x**2
end function
end module
An example program
! file a.f90
program main
use closure_m
use fns_m
implicit none
type(closure) :: c1, c2
call c1%init(g)
print *, c1%exec(2.0)
call c1%init(f, 1.0, 2.0)
print *, c1%exec(2.0)
call c2%init(f, 1.0, -2.0)
print *, c2%exec(3.0)
end program
Example output
$ gfortran closure.f90 fns.f90 a.f90 && ./a.out
4.00000000
-2.00000000
9.00000000
I am having trouble in implementing an approach to call Newton's method in a Fortran program.
So I want to use Newton's method to solve an equation following the link
However, my program is slightly different with the example above. In my case, the equation requires some additional information which are produced during runtime.
subroutine solve(f, fp, x0, x, iters, debug)
which means the f is calculated not only based on x, but also a few other variables (but x is the unknown).
I have a solution, which only works for a simple case:
I used a module to include Newton's solver. I also defined a derived data type to hold all the arguments inside the module. It works good now.
My question is: I need to call the Newton's method many times, and each time the arguments are different. How should I design the structure of the modules? Or should I use a different solution?
I provided a simple example below:
module solver
type argu
integer :: m
end type argu
type(argu):: aArgu_test !should I put here?
contains
subroutine solve(f, fp, x0, x, iters, debug)
...
!m is used inside here
end subroutine solve
subroutine set_parameter(m_in)
aArgu%m = m_in
end subroutine set_parameter()
end module solver
And the calling module is:
!only one set of argument, but used many times
module A
use module solver
do i = 1, 4, 1
set_parameter(i)
!call Newtow method
...
enddo
end module A
!can I use an array for argu type if possible?
module B
use module solver
type(argu), dimension(:), allocable :: aArgu ! or should I put here or inside solver module?
end module B
My understanding is that if I put the argu object inside the solver module, then all solver calling will use the same arguments (I can still save all of them inside module A using the above method). In that case, I have to update the arguments during each for loop?
Because the program runs using MPI/OpenMP, I want to make sure there is no overwritten among threads.
Thank you.
There is a common pattern in modern Fortran for the problem you are facing (partial function application). Unlike other languages, Fortran doesn't have function closures, so making a lexical scope for a function is a little "convoluted" and kind of limited.
You should really consider revisiting all the links #VladmirF shared on the comment, most of them apply straightforwardly to your case. I will give you an example of a solution.
This is a solution without using a wrapper type. I will use a feature included in Fortran 2008 standard: passing an internal procedure as an argument. It is compatible with the latest gfortran, Intel and many others.
If you can't access a compiler with this feature or if you prefer a solution with a derived type, you can refer to this answer.
module without_custom_type
use, intrinsic :: iso_fortran_env, only: r8 => real64
use :: solver
contains
subroutine solve_quad(a, b, c, x0, x, iters, debug)
integer, intent(in) :: a, b, c
real(r8), intent(in) :: x0
real(r8), intent(out) :: x
integer, intent(out) :: iters
logical, intent(in) :: debug
call solve(f, fp, x0, x, iters, debug)
contains
real(r8) function f(x)
real(r8),intent(in) :: x
f = a * x * x + b * x + c
end
real(r8) function fp(x)
real(r8),intent(in) :: x
fp = 2 * a * x + b
end
end
end
The rationale of this code is: as f and fp lay inside of the solve_quad procedure, they have access to the arguments a, b and c by host association, without touching those function's signatures. The resulting effect is like changing the arity of the function.
Testing it with gfortran 8.0 and the solver implementation from the link you shared, I got this:
program test
use, intrinsic :: iso_fortran_env, only: r8 => real64
use :: without_custom_type
implicit none
real(r8) :: x, x0
integer :: iters
integer :: a = 1, b = -5, c = 4
x0 = 0
call solve_quad(a, b, c, x0, x, iters, .false.)
print *, x, iters
! output: 1.0000000000000000, 5
x0 = 7
call solve_quad(a, b, c, x0, x, iters, .false.)
print *, x, iters
! output: 4.0000000000000000, 6
end
After discussing with a colleague, I have a solution to my question 2.
If we have only one argument object for the solver module, then all the calling will access the same arguments because they share the same memory space.
To avoid this, we want to pass the argument object as an argument into the solver.
So instead of using the default solver subroutine, we will re-write the Newton's method so it can accept additional argument.
(I used the simplest Newton subroutine earlier because I wanted to keep it untouched.)
In this way, we will define an array of argument objects and pass them during runtime.
Thank you for the comments.
I want to pass a type bound procedures (as an external function) to another function as follows:
module mod1
implicit none
type type1
real :: a
contains
procedure,pass :: f
end type
contains
real function f(y,e)
class(type1), intent(in) :: y
real,intent(in) :: e
f=y%a+e
end function
end module
program test
use mod1
type(type1) :: t
t%a=3e0
write(*,*) s(t%f)
contains
real function s(g)
real,external :: g
s=g(5e0)+2e0
end function
end program
gfortran produces gives this error :
write(*,*) s(t%f)
1
Error: Expected argument list at (1)
But what I can do is:
program test
t%a=3e0
write(*,*) s(k)
contains
real function s(g)
real,external :: g
s=g(5e0)+2e0
end function
real function k(e)
real,intent(in) :: e
k=3e0+e
end function
end program
I think the problem is related to Passing type bound procedures as arguments, but I don't see at the moment how the answers there can help me.
EDIT:
A better example which (hopefully) shows the difficulty:
module mod2
implicit none
contains
real function s(g)
interface
real function g(x)
real, intent(in) :: x
end function
end interface
s=g(5e0)+2e0
end function
end module
module mod1
use mod2
type type1
real :: a
contains
procedure,pass :: f
procedure,pass :: h
end type
contains
real function f(y,e)
class(type1), intent(in) :: y
real,intent(in) :: e
f=y%a+e
end function
real function h(y)
class(type1), intent(inout) :: y
h=s(y%f)
end function
end module
program test
use mod1
type(type1) :: t
t%a=3e0
write(*,*) t%h
end program
EDIT II:
Ok, the wrappers still work in combination with a pointer:
module mod2
implicit none
contains
real function s(g)
interface
real function g(x)
real, intent(in) :: x
end function
end interface
s=g(5e0)+2e0
end function
end module
module mod1
use mod2
type type1
real :: a
contains
procedure,pass :: f
procedure,pass :: h
end type
class(type1),pointer :: help_w
contains
real function f(y,e)
class(type1), intent(in) :: y
real,intent(in) :: e
f=y%a+e
end function
real function h(y)
class(type1), intent(inout),target :: y
help_w => y
h=s(wrap)
end function
function wrap(x)
real,intent(in) :: x
wrap=help_w%f(x)
end function
end module
program test
use mod1
type(type1) :: t
t%a=3e0
write(*,*) t%h()
end program
This is certainly not a beautiful solution but at least it works.
You can write a wrapper. This is the most straightforward version. Requires passing internal function as a dummy argument (F2008), but you could declare the wrapper in a module too, if the t can bee there.
Note I changed the declaration of the procedure argument in s to something more modern - the interface block.
program test
use mod1
type(type1) :: t
t%a=3e0
write(*,*) s(wrap)
contains
real function s(g)
interface
real function g(x)
real, intent(in) :: x
end function
end interface
s=g(5e0)+2e0
end function
function wrap(x)
real, intent(in) :: x
wrap = t%f(x)
end function
end program
The reason for your error is well described in the answers to the linked question, you cannot pass type bound procedures the way you tried.