This is my first question on the internet!!! Also, this is a Fortan question and I just started to learn this language. So, please forgive my ignorance. Specifically, I apologize if my example code is large. I have done my best to reduce its size to bare minimum without undermining its clarity.
Here is the problem: I am trying to create a dynamic simulation model that uses a function that will be called multiple times during a model run. The function itself is a dynamic integration system so the values of the functions must be retained at each time step of the simulation so they can be used in the next time step.
The model includes a simple stock (P) that reduces over time by a constant rate (10% per time). The function is a exponential delay. It takes 4 arguments: (input, delay time, delay order, input initial). Note that the output of the function has 3 dimensions. The first dimension represents different instances of the delay call within the program. The second dimension represents order of the delay. And the third dimension represents the simulation time.
The main challenge here was to dynamically allocate the arrays that will be created by the function. To address this issue, I have tried to follow the guidelines provided here: How to increase array size on-the-fly in Fortran? The program I have written sounds to be working fine in some cases but not always. For example, if you compile the codes as they appear below, you will get the correct result (correct behavior is that all variables should start from 100 and gradually decline). But if you change the order of delay in U from 5 to 6, then the results will be wrong (U starts from 100 but then fluctuates and sometimes go above 100).
What am I missing here? Is there anything wrong with the way I have implemented move_alloc? Or the problem is somewhere else? Could it be the compiler (gfortran) that is failing? I truly appreciate your help, in advance!
program model
implicit none
real, parameter :: start = 0, end = 10, dt = 0.25
integer, parameter :: n = int((end - start)/dt)
real, dimension(0:n+1) :: time, P, R, S, W, U
integer :: i
real, dimension(:,:,:), allocatable :: DN, temp
P(0) = 100
time(0) = start
open (unit=10, file='out.txt', status='replace', action='write', position='rewind')
write (10, *) 'Time, ', 'P, ', 'R, ', 'S, ', 'W, ', 'U'
do i = 0, n
P(i+1) = P(i) - .1*P(i)*dt
R(i) = delay(P(i), 3.0, 4, P(0))
S(i) = delay(P(i), 2.0, 4, P(0))
W(i) = delay(P(i), 4.0, 5, P(0))
U(i) = delay(P(i), 1.0, 5, P(0))
time(i+1) = time(i) + dt
write (10, *) time(i), ',', P(i), ',', R(i), ',', S(i), ',', W(i), ',', U(i)
end do
close (10)
contains
function delay(input, dtime, order, init)
real :: delay
real, intent(in) :: input, dtime, init
integer, save :: j, k
integer, intent(in) :: order
integer :: l
data j /0/
data k /0/
if (j == i) then
k = k + 1
allocate(temp(1:k, 1:order, 0:n+1))
if (allocated(DN)) temp(1:k-1, 1:order, 0:n+1) = DN
call move_alloc(temp, DN)
else
k = 1
j = i
end if
if (i == 0) then
do l = 1, order
DN(k, l, 0) = init * dtime / order
end do
end if
DN(k, 1, i+1) = DN(k, 1, i) + (input - DN(k, 1, i) * order / dtime) * dt
if (order > 1) then
do l = 2, order
DN(k, l, i+1) = DN(k, l, i) + (DN(k, l-1, i) - DN(k, l, i)) * order * dt / dtime
end do
end if
delay = DN(k, order, i) * order / dtime
end function delay
end program model