문제

I would like to write Fortran code that works like the R function seq(). E.g.:

x <- seq(0,1,0.1)

will give the vector

x <- c(0, 0.1, 0.2, ..., 1)

I will run several simulations over which the length of the sequence will change, in R this is easily done, by just varying the second argument in seq(). I have tried to do something like this in Fortran with dynamical arrays and the function ALLOCATE to dynamically change the size of the array. This has not worked so far and lead to the error

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0x2B371ED7C7D7
#1  0x2B371ED7CDDE
#2  0x2B371F3B8FEF
#3  0x401BE9 in MAIN__ at test3D.f90:?
Segmentation fault (core dumped)

so I was wondering whether there is an easy way to mimic the behaviour of the R function seq() in Fortran.

For further reference see the program below

program ffl
implicit none
integer, parameter           :: n = 2**12                  
integer                      :: m,j,l,o,num,r,posi         
real(kind=8), dimension(n)   :: results 
real(kind=8)                 :: dt,dk,dp, dtt, laenge, basal, periode,c      
real(kind=8), dimension(n,n) :: fitness, k_opt  
real(kind=8)                 :: t0,t1,t2,t3      
real(kind=8), dimension(:),allocatable    :: t   
real(kind=8), dimension(n)   :: k,p, tt1  
real(kind=8), dimension(6)   :: x_new, res, q0 
real(kind=8), dimension(6)   :: k1,k2,k3,k4    
real(kind=8)                 :: ts = 0.0    
real(kind=8)                 :: ks = 0.0, ke = 1.0  
real(kind=8)                 :: ps = 0.1, pe = 40.0  
real(kind=8)                 :: tts = 0.0, tte = 1.0  
real(kind=8), dimension(6)   :: u0,f1,f2,f3,u1    
external                     :: derivate 

! computing the vectors 
dk=(ke-ks)/real(n)    ! calculating resolution
dp=(pe-ps)/real(n)    ! calculating resolution
dtt=(tte-tts)/real(n) ! calculating resolution
k(1) = ks             ! first value for k = 0.0
p(1) = ps             ! first value for p = 0.001
tt1(1) = tts          ! first value for tts = 0.0

num = 10

do m = 1,n         
    k(m) = k(m-1)+dk ! setting the basal expression vector with resolution dt 
    tt1(m) = tt1(m-1)+dtt
end do

do m = 1,n
    p(m) = ps + 0.1
end do

do m = 1,n
    periode = p(m)

    do j = 1,n
    laenge = tt1(j)

        do l = 1,n
        basal = k(l)

            c = num * periode    ! calculating the length of the simulation
            dt=(c-ts)/real(n)    ! calculating time resolution
            r = 1
            t(1) = ts            ! setting first time value to t1 = 0

            allocate(t(1))       ! Initialize array dimension

            do while (ts + dt < c)
                t(r) = ts
                ts = ts + dt
                r = r + 1
                call resize_array
            end do

            ! initial conditions
            q0(1) = 0     ! x
            q0(2) = basal ! y
            q0(3) = 0     ! z
            q0(4) = 0     ! a
            q0(5) = 1     ! b
            q0(6) = 0     ! w 

            x_new = q0 ! set initial conditions
            ! Solving the model using a 4th order Runge-Kutta method
            do o = 1,n
                call derivate(basal,periode,laenge,t(l),x_new,k1)  

                t1 = t(o) + dt/2      
                f1 = x_new + (dt*k1)/2
                call derivate(basal,periode,laenge,t1,f1,k2)      

                t2 = t(o) + dt/2      
                f2 = x_new + (dt*k2)/2
                call derivate(basal,periode,laenge,t2,f2,k3)      

                t3 = t(o) + dt
                f3 = x_new + (dt*k3)/2
                call derivate(basal,periode,laenge,t3,f3,k4)      

                res = x_new + (dt*(k1+2*k2+2*k3+k4))/6
                if (res(2) < basal) then
                    res(2) = basal
                endif

                results(n) = res(6)

            end do
         fitness(j,l) = maxval(results)/c 
         end do
    write(*,*) fitness   
    !posi = maxloc(fitness(:,j)) 
    !k_opt(m,j) = k(posi)      ! inputting that value into the optimal k matrix
    end do
end do
!write(*,*) k_opt
!return k_opt

contains

! The subroutine increases the size of the array by 1
subroutine resize_array
real,dimension(:),allocatable :: tmp_arr
integer :: new

new = size(t) + 1

allocate(tmp_arr(new))
tmp_arr(1:new)=t
deallocate(t)

allocate(t(size(tmp_arr)))
t=tmp_arr

end subroutine resize_array   
end program ffl
도움이 되었습니까?

해결책

Fortran 2003 has (re-)allocation upon assignment for allocatable arrays, and the program

program xgrid
implicit none
real, allocatable :: x(:)
integer           :: i,n
do n=5,10,5
   x = 0.1*[(i,i=0,n)]
   write (*,"('x =',100(1x,f0.1))") x
end do
end program xgrid

compiled with gfortran 4.8.0, shows a Fortran one-liner equivalent to seq(), giving output

x = .0 .1 .2 .3 .4 .5

x = .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1.0

다른 팁

A simple implementation, if you really wanted the function, not wanting to always compute the n by hand. May need some clarification of the upper bound.

print *,seq(1.,10.,0.1)

contains

function seq(from, to, step)
  real, allocatable :: seq(:)
  real, intent(in) :: from, to, step

  allocate(seq(0:int((to - from)/step)))
  do i = 0, size(seq)
    seq(i) = from + i * step
  end do
end function

end

Regarding your program, when you use the fretures the compiler has, the backtrace would be much more helpful. Your resize_array should probably have tmp_arr(1:new-1)=t. The move_alloc() subroutine could make it little bit shorter.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top