data-structuresfortranoperationuser-defined-data-types

How to handle user-defined data structure in Fortran90?


in my program I defined a data type called Lyapunov_orbit that contains 8 fields, then I used it to read data from external .txt file (see below where I report only a few lines for convenience because the file has about 4000 lines). I need to perform some operations by using such structure (as to find minimum and maximum value of an array) but to handle it I had to declare an "auxiliary" variable called vec_J_cst because if I try to directly use my data strucutre, I get some errors (the structure-name is invalid or missing).

Here is the .txt file:

   -0.990036333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.337762568000000E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090089101800E+01 
   -0.990037333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.344404791697701E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090088741935E+01 
   -0.990038333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.351079970065519E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090088372775E+01 
   -0.990039333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.357762241991673E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090087996039E+01 
   -0.990040333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.364443669596976E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090087612278E+01 
   -0.990041333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.371123821002079E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090087221528E+01 
   -0.990042333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.377014880488160E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090086883260E+01 
   -0.990043333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.384445283931247E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090086421774E+01 
   -0.990044333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.390403586590581E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090086066251E+01 
   -0.990045333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.397792952615728E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090085591825E+01 
   -0.990046333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.403738458530992E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090085225121E+01 
   -0.990047333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.411139963724134E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090084733683E+01 
   -0.990048333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.417123805736171E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090084351603E+01 
   -0.990049333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.424484757953771E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090083847487E+01 
   -0.990050333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.430437019162321E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090083455851E+01 
   -0.990051333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.437812214383817E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090082934584E+01 
   -0.990052333227000E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.443804068227964E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090082527265E+01 
   -0.990053333227001E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.451146181152564E-03    0.000000000000000E+00    0.301148079918400E+01    0.300090081992963E+01 
   -0.990054333227001E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.457168852630379E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090081570545E+01 
   -0.990055333227001E+00    0.000000000000000E+00    0.000000000000000E+00    0.000000000000000E+00    0.463719562991478E-03    0.000000000000000E+00    0.302089167668145E+01    0.300090081093777E+01 

Here are modules:

module Array
    
    use DataType
    
    contains 
    
!***********************************************************************
    subroutine linspace(from, to, array)
!***********************************************************************
    ! Generates evenly spaced numbers from `from` to `to` (inclusive).
    !
    ! Inputs:
    ! -------
    !
    ! from, to : the lower and upper boundaries of the numbers to generate
    !
    ! Outputs:
    ! -------
    !
    ! array : Array of evenly spaced numbers
!***********************************************************************
    implicit none
    
        !Arguments
        real(pr), intent(in)  :: from, to
        real(pr), intent(out) :: array(:)
        
        real(pr) :: range
        integer :: n, i
    
        n = size(array)
        range = to - from

        if (n == 0) return

        if (n == 1) then
            array(1) = from
            return
        end if


        do i=1, n
            array(i) = from + range * (i - 1) / (n - 1)
        end do
        
    end subroutine

end module Array



!***************************************************************************
! Program name: Cheops ver 0
! Author: Elena Fantino, ETSEIAT - UPC
! Date: August 2015
!***************************************************************************

module DataType

    implicit none

    INTEGER, PARAMETER :: pr = SELECTED_REAL_KIND (p = 15) 

    !"Lyapunov_orbit" data type declaration 
    type  Lyapunov_orbit                           
        real(pr) :: a         
        real(pr) :: b              
        real(pr) :: c             
        real(pr) :: d              
        real(pr) :: e            
        real(pr) :: f             
        real(pr) :: g             
        real(pr) :: J_cst                           
    end type Lyapunov_orbit                 
    
    
    
end module DataType




Here is my main program:

program Main_Planar_Lyapunov_orbits

    use DataType
    use Array
    
    implicit none

    ! Declarations
    character*100 :: input_path,input_filename, output_path, output_filename,line
    character*30, dimension(1) :: str_output    !questo mi servira per le intestazioni nel file di output
    integer :: i,j, iu_in,iu_out,n_lines, iflag, pos_err_min
    type(Lyapunov_orbit), dimension (:), allocatable :: Ly_data_SE_L1
    real(pr), dimension(:), allocatable :: vec_J_cst, err
    real(pr), dimension(1) :: first_J_cst_vec, last_J_cst_vec, Delta_J, step, accepted_value
    real(pr), dimension(50) :: array_Ly_orb
    
    ! Definition of constants, paths names and file names
    iu_in = 10
    iu_out = 11
    input_path = 'D:\OneDrive\MSc_Thesis\Projects\Planar_Lyapunov_orbits\InputFiles\'
    input_filename = 'Planar_Lyapunov_SE_L1_Buono.txt'
    output_path =  'D:\OneDrive\MSc_Thesis\Projects\Planar_Lyapunov_orbits\OutputFiles\'
    output_filename = 'Planar_Lyapunov_SE_L1_evenly_spaced.txt'
    

    ! Reading of Lyapunov orbits data from input file
    open(unit = iu_in, file = trim(input_path) // trim(input_filename), status='old', & 
         access = 'sequential',form = 'formatted', action='read')
    
        ! Count lines 
        n_lines = 0
        do     
          read(iu_in,*,iostat = iflag)
          if (iflag/=0) exit
           n_lines =  n_lines + 1
        enddo
    
        rewind(iu_in)
    
        ! Variables allocation
        allocate(Ly_data_SE_L1(n_lines))
        
        
        ! Data reading 
        do i = 1, n_lines
            read(iu_in,*) Ly_data_SE_L1(i)         
        enddo
        
    close(unit = iu_in, status='keep') 
 
    ! Creation of Jacobi constant evenly spaced 1-D array of 50 elements, 
    ! the first one and the last are the corresponding ones of input data
    
    ! Extraction of the first and last element by using auxiliary variable   
    
    !allocate(vec_J_cst(n_lines))    
    !do i = 1,n_lines       
    !    vec_J_cst(i) = Ly_data_SE_L1(i)%J_cst  
    !   first_J_cst_vec =  vec_J_cst (lbound(vec_J_cst))  ! max
    !    last_J_cst_vec  =  vec_J_cst (ubound(vec_J_cst))  ! min 
    !enddo
    
    !! ATTEMPT TO AVOID another variable usage (IT DOES NOT WORK!)
    first_J_cst_vec =  Ly_data_SE_L1(:)%J_cst  (lbound(Ly_data_SE_L1(:)%J_cst))  ! max
    last_J_cst_vec  =  Ly_data_SE_L1(:)%J_cst  (ubound(Ly_data_SE_L1(:)%J_cst))  ! min 
       
    ! Evenly spaced array: the 1st element is the greater value of jacobi constant: 
    ! the size of the array has to be specified in the declarations 
   
      call linspace(from = first_J_cst_vec(1), to = last_J_cst_vec(1), array = array_Ly_orb)
    

    allocate(err(n_lines)) 
    
    ! Filter the original input file and write data on new file of 50 Lyapunov orbits based on input data
    open(unit = iu_out, file = trim(output_path) // trim(output_filename), status = 'unknown', action ='write')
    
    ! Compare the original Jacobi constants array(Ly_data_SE_L1%J_cst) with the created evenly spaced array(array_Ly_orb)
    
    ! Header line
     write(iu_out,'(2a15)') 'unknown','Jacobi constant'
    
    ! Nested cycles
    do i = 1,50
        
        do j = 1, n_lines          
            ! Compute the error between the i-th element of evenly spaced array and the current element of original jacobi constants array
            err(j) = abs( vec_J_cst(j) - array_Ly_orb(i) )    
        enddo   
            ! Find the location of the absolute minimum of the Err array 
            pos_err_min = minloc(err, dim =1)
                     
            write(iu_out,'(2e25.15)') Ly_data_SE_L1(pos_err_min)%a, vec_J_cst(pos_err_min)
    enddo
       
    close(unit = iu_out,status='keep')
       
    
    !Idea di algoritmo per la parte di confronto e scrittura
    ! Abbiamo due array, il primo è quello originale con circa 4000 element e il secondo è quello creato con 50 elementi. Per prima cosa faccio un
    ! ciclo sul secondo array (indice i), poi ciclo sul primo array e calcolo l'errore fra il valore corrente j e quello fissato i, tale errore 
    ! sarà un vettore di circa 4000 elem. Uso la funzione predefinita minloc per localizzre la posizione del minimo assoluo del vettore di errore,
    ! e quindi accetto questo valore che poi deve essere scritto nel file. A questo punto si passa
    ! al successivo valore dell'indice i e si ripete la procedura. Alla fine devo avere un file di 50 elementi.
    
    
end program Main_Planar_Lyapunov_orbits

Is there a way to avoid the usage of "auxiliary" variable (vec_J_cst) I described above?

Errors:

error #6410: This name has not been declared as an array or a function.   [J_CST]
error #6158: The structure-name is invalid or is missing.   [LY_DATA_SE_L1]      
error #6158: The structure-name is invalid or is missing.   [LY_DATA_SE_L1]      

Solution

  • The problem with the lines

    first_J_cst_vec =  Ly_data_SE_L1(:)%J_cst  (lbound(Ly_data_SE_L1(:)%J_cst))
    last_J_cst_vec  =  Ly_data_SE_L1(:)%J_cst  (ubound(Ly_data_SE_L1(:)%J_cst)) 
    

    is that J_cst is a scalar member variable, so cannot be indexed.

    I assume your logic is that Ly_data_SE_L1(:)%J_cst is an array, so Ly_data_SE_L1(:)%J_cst(i) will access the i'th element of that array, but this is the wrong syntax. Instead, you need Ly_data_SE_L1(i)%J_cst, i.e. accessing J_cst of the i'th element, rather than the i'th element of the J_cst array.

    As such, these lines should read

    first_J_cst_vec =  Ly_data_SE_L1(lbound(Ly_data_SE_L1(:)%J_cst))%J_cst
    last_J_cst_vec  =  Ly_data_SE_L1(ubound(Ly_data_SE_L1(:)%J_cst))%J_cst
    

    Note that Ly_data_SE_L1(:)%J_cst has the same lbound and ubound as Ly_data_SE_L1, so you can simplify this to

    first_J_cst_vec =  Ly_data_SE_L1(lbound(Ly_data_SE_L1))%J_cst
    last_J_cst_vec  =  Ly_data_SE_L1(ubound(Ly_data_SE_L1))%J_cst