Passing additional arguments in Newton’s method in Fortran - fortran

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.

Related

How to define generic interfaces for the same Fortran function body

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?

Overloading function in Fortran and polymorphic derived data types

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

Is there a Fortran equivalent of unpacking a list of arguments in Python?

I'm writing my first numerical optimization program (Newton's method) and my first Fortran program too. I started with Python to understand the first problem and now I'm porting to Fortran to work on the other. (One thing at a time, right?)
In Python, there's a handy way of passing arguments to a function: unpacking a list, like so:
def f(x_1, x_2):
"""Just a function with two arguments."""
return math.sqrt(x_1 ** 2 + x_2 ** 2)
...
f(*[4, 3]) # calls f with parameters 4 and 3
# output: 5
Does Fortran have something resembling this star operator? I put my 2-dimensional points into a matrix, and I'm trying to learn the most conventional way of passing one of my 2D point "vectors" to a function to be evaluated. It looks a little like this:
! "double precision", using SELECTED_REAL_KIND
REAL(KIND=dp), DIMENSION(100, 2) :: iterates = 0.0_dp
! f expects two REALs
REAL(KIND=dp) :: first_value = f(iterates(1, :))
No.
You can make your function accept a vector. If the function is from a dependency, you can write a wrapper:
function f_array_input(x)
real(kind=dp), intent(in) :: x(2)
real(kind=dp) :: f_array_input
f_array_input = f(x(1), x(2))
end function
(

How to pass a function with multiple arguments to a subroutine that expects a function with only one argument?

I have a subroutine (minimal example)
subroutine treatfunction(f,input,output)
external, real::f
real, intent(in):: input
real, intent(out):: output
output = f(input) + f(1.0) ! i.e. f has only one argument
end subroutine
and a function with two arguments
real function fun(x,a)
real,intent(in)::x,a
Now for a given a fixed at runtime, I want to pass fun to treatfunction. So ideally, I would want to call something like
call treatfunction(fun(:,a=a0), input=myinput, output=myoutput)
What is the most elegant way of doing this with the Fortran2003 features gfortran-5 supports?
Of course, I could insert an optional dummy argument a in treatfunction and call f either with f(x) or f(x,a) depending on present(a) in the subroutine's body. But changing the subroutine is not elegant.
In Fortran 2008 you can pass internal functions as arguments and gfortran supports it.
subroutine calling()
a0 = ...
call treatfunction(wrapper, input=myinput, output=myoutput)
contains
real function wrapper(x)
real, intent(in) :: x
wrapper = fun(x,a0)
end function
end subroutine
BTW, I would stay away from external it is evil, use interface blocks.

Manhattan distance Fortran

I would like to calculate the Manhattan distance between 2 arrays in Fortran according to the formula:
d = Sum(|P(i)-R(i)|)
So I made a code in Fortran:
function DistM(v, u, dim)
integer dim
real(8) v(dim), u(dim), DistM
DistM=sum(abs(v-u))
end function DistM
I call this function by using this:
Coeff=DistM(tempvector1,tempvector2, dim)
But this doesn't seem to work (I don't get any return). I also tried by taking the power of 2 and then doing the sqrt of it, but it gets stuck at the sqrt then (if I run it in steps).
I tried another function and that one worked (see here after), but this one doesn't work :(:
function Roznica(v, u, dim)
integer dim
real(8) v(dim), u(dim), Rozn
Rozn=sum((v-u)**2)/dim
end function Roznica
Anyone an idea?
I would write a Manhattan distance function simply like this (with assumed-shape arrays you no longer have to use automatic arrays like you do, provided the function has an explicit interface):
pure function L1(v)
real, intent(in) :: v(:) ! <- shape assumed from actual argument
real :: L1
L1 = sum(abs(v))
end function
And then if you have two vectors you simply call the function as foo = L1(p - q).