Search code examples
fortran

Fortran Derived Type cannot Access Other Parameters


I have defined the following derived type in Fortran:

type :: derived_type
    logical :: is_allocated = .false.
    integer :: n_layer = 0
    integer :: type = 0
    real, allocatable :: radius(:)
end type derived_type

I then define a variable with this derived type in a subroutine:

type(derived_type), intent(inout) :: sphere(15)

However, when I try to call sphere(1)%type, such as through print, later in the subroutine, I receive a segmentation fault error instead of the expected 0. I have tried renaming type to some other name because I was thinking that type might be a reserved name, but it still returns a segmentation fault. Weirdly enough, sphere(1)%is_allocated is defined and it returns .false.. I tried moving the integer :: type = 0 at the top of the list and it returns the correct value, but calling the other parameters return a segmentation fault.

I am not an expert in Fortran and I don't know what could be the problem here? I am using gfortran 9.4.0 in compiling the script.

The code itself is part of a bigger script and the error log seems to point to a part similar to what I mentioned.

Update

Here is a minimal reproducible example.

shape_type.mod

module shape_type
    type :: shape_params
        logical :: is_allocated = .false.
        integer :: type = 0
        real(8), allocatable :: perimeter(:)
    end type shape_params
end module shape_type

shape_list.mod

module shape_list
    use shape_type, only: shape_params

    type :: shape_list_params
        logical :: is_allocated = .false.
        type(shape_params), allocatable :: geometry(:)
    end type shape_list_params
end module shape_list

test_subroutine.f90

subroutine test_subroutine(geometry)
    use shape_type, only: shape_params

    implicit none

    type(shape_params), intent(inout) :: geometry(15)

    print *, geometry(1)%is_allocated
    print *, geometry(1)%type
end subroutine test_subroutine

main_program.f90

program main_program
    use shape_list, only: shape_list_params

    implicit none

    type(shape_list_params), save, dimension(1) :: form

    call test_subroutine(form(1)%geometry)
end program

Solution

  • You need to allocate all variables which have the allocatable attribute explicitly. This will not be done by the Fortran compiler automatically, you have to care for it yourself: Allocatable Arrays.

    Your program works after allocating the variable with allocate() like this:

    program main_program
        use shape_list, only: shape_list_params
    
        implicit none
    
        type(shape_list_params), save, dimension(1) :: form
    
        allocate(form(1)%geometry(15))  ! allocation added
        call test_subroutine(form(1)%geometry)
    end program
    

    Some comments:

    • Your program has a second occurence of allocatable for which you need to care: real(8), allocatable :: perimeter(:). You either need to allocate this also, or since it is only a single value, you could remove the attribute.
    • You do not need to track allocation yourself with is_allocated. Better use Fortran's intrinsic allocated.
    • The save attribute in your main program will not have any effect. It is useful only in subroutines and functions to keep the values of variables until the next call.
    • Your minimal reproducible example has two wrong file extensions: shape_type.mod and shape_list.mod. All files must have the .f90 extension. But that is most probably only a copy and paste error.