2017-05-27 254 views
2

我正在嘗試創建一個全局可訪問的主程序和所有子例程的數據結構。數據結構是通過讀取一些.dat文件構建的。Fortran模塊和全局變量

這種全局可訪問性似乎適用於某個模塊。到目前爲止,我的模塊解決方案包括:1)全局定義數據類型; 2)在模塊中包含(包含)一系列子例程以打開/讀取.dat文件; 3)從.dat文件構造數據類型。

理想情況下,我想在模塊中構建這個數據結構ONCE,然後讓這個數據結構可以在全局訪問。我不想在每次調用模塊過程時打開/讀取.dat文件。

例如。有沒有辦法從主程序中將數據結構聲明爲全局變量,然後調用模塊過程來構建一次數據結構?

@Ross。源代碼:

module DataTypeModule 

    implicit none 

    type :: DatCube 
     integer :: NGrid(4) 
     double precision, allocatable :: tgrid(:) 
    end type DatCube 

    contains 

    subroutine DataArraySizes(NGrd) 
    implicit none 
    integer, intent(out) :: NGrd(4) 
    open(unit=15, file='./Data/DataHeader.txt', status='old') 
    read(15,*) NGrd(1) 
    read(15,*) NGrd(2) 
    read(15,*) NGrd(3) 
    read(15,*) NGrd(4) 
    close(15) 
    end subroutine DataArraySizes 

    subroutine DataTGrd(NGrd,tgrd) 
    implicit none 
    integer, intent(in) :: NGrd(4) 
    double precision, intent(out) :: tgrd(NGrd(1)) 
    open(unit=16, file='./Data/tgrid.dat', status='old') 
    read(16,*) tgrd 
    close(16) 
    end subroutine DataTGrd 

    subroutine ConstructDataCube(DataCube) 
    implicit none 
    type(DatCube), Intent(out) :: DataCube 

    integer, allocatable :: NGrd(:) 
    double precision, allocatable :: tgrd(:) 

    allocate(NGrd(4)) 
    call DataArraySizes(NGrd) 
    DataCube%NGrid = NGrd 

    allocate(tgrd(NGrd(1)),DataCube%tgrid(NGrd(1))) 
    call DataTGrd(NGrd,tgrd) 
    DataCube%tgrid = tgrd 

    deallocate(NGrd,tgrd) 

    return 
    end 

end module DataTypeModule 

program main 
    use DatatypeModule 
    implicit none 
    double precision :: arg1,out1(4) 
    type(DatCube) :: DataCube 

    call ConstructDataCube(DataCube) 

    call subrtn1(arg1,out1) 

    stop 
end 


subroutine subrtn1(arg1,out1) 
    use DataTypeModule 
    implicit none 
    double precision, Intent(in) :: arg1 
    double precision, Intent(out) :: out1(4) 
    type(DatCube) :: DataCube 

    out1 = DataCube%NGrid 

    return 
end 
+1

我不明白你的困惑的來源。爲什麼不在程序開始時調用'read_data',並且使用來自任何地方的變量? – Ross

+0

@Ross。每次我調用模塊過程(從主程序或各種子例程)時,它都會打開/讀取.dat文件並構建數據結構。這是一個巨大的時間。 我想調用模塊過程(構造數據結構)一次,並將此數據結構設置爲主程序和所有子例程可訪問的全局變量。 我不想將此數據結構作爲參數傳遞給每個子例程,因爲我有許多嵌套過程。 – jkedmond

+0

好吧,這是之前發佈的不同版本的源代碼,但它看起來更小,所以這很好。 – Ross

回答

2

被讀取一次並訪問多次的數據非常普遍。這是一個簡單的例子,說明如何工作。模塊my_data包含要存儲的數據x,i和從磁盤read_data讀取該數據的子例程。讀取應該被調用一次,數據可以從主程序和子程序中多次訪問。在源文件main.f90

module my_data 
    implicit none 

    real :: x 
    integer :: i 

contains 
subroutine read_data 
    integer :: fid 

    open(newunit=fid,file='config.txt',action='read',position='rewind') 

    read(fid,*) x 
    read(fid,*) i 

    close(fid) 
end subroutine read_data 
end module my_data 

module routines 
    implicit none 

contains 
subroutine mysub 
    use my_data, only : x, i 

    ! -- Use data again 
    write(*,*) 'x and i in subroutine are: ', x, i 

end subroutine mysub 
end module routines 

program main 
    use my_data, only : read_data, x, i 
    use routines, only : mysub 
    implicit none 

    ! -- Initialize 
    call read_data 

    ! -- Use data 
    write(*,*) 'x and i in main are: ', x, i 

    ! -- Use data in subroutine 
    call mysub 

end program main 

文件config.txt包含要讀取的數據。

mach5% more config.txt 
1.23 
5 
mach5% ifort main.f90 && ./a.out 
x and i in main are: 1.230000    5 
x and i in subroutine are: 1.230000    5 

編輯:這裏發生了什麼的一個關鍵部分是xi存儲由讀取模塊和主程序都可以訪問的地方。在這個簡單的例子中,我選擇將它存儲在my_data中,但它可能在別處。您發佈的示例代碼已被刪除(請將其編輯爲您的問題),從不儲存您已閱讀的數據。閱讀一次數據後存儲數據至關重要。編輯2:在您編輯的源代碼中,您將數據讀入主程序中聲明的變量DataCube。然後,您嘗試訪問在子程序subrtn1中聲明的變量DataCube中的數據。 這些不是同一個變量。您必須聲明一次,並從多個地方訪問它。做到這一點的最佳方式是將其包含在模塊中,正如我在示例中所示。但是,您也可以將它作爲參數傳遞給例程,但這會變得很麻煩。

+0

在你的例子中,從主程序調用的can(嵌套)子例程訪問數據x,我沒有傳遞x和i作爲參數? – jkedmond

+0

@jkedmond只有他們有權訪問相應的模塊。 –

+0

@VladimirF。你說的是,只要我在特定的子程序中添加聲明「use my_data,only:read_data,x,i」,我就不必傳遞x和i作爲參數。 – jkedmond

-1

您可以將模塊假定爲PRIVATE或假定爲PUBLIC。我會顯示PRIVATE。

module DataTypeModule 
    implicit none 
    PRIVATE            !<-- 

    type :: DatCube_Struct 
     integer           :: nGrid 
     double precision, allocatable, DIMENSION(:)  :: tgrid 
    end type DatCube_Struct 
    !PUBLIC DatCube_Struct !(Only needs to be public if you want to use it in separate from DataCube) 
    type(DatCube_Struct), DIMENSION(4)   , PUBLIC :: DataCube !<-- 

    double precision, DIMENSION(:,:), ALLOCATABLE, PUBLIC :: tgrd  !<-- 

    !! PUBLIC DataArraySizes, DataTGrd !<-- These do not seem to need to be PUBLIC 
    PUBLIC ConstructDataCube !<-- 

!%%%%%%%%%%%%%% 
    contains 
!%%%%%%%%%%%%%% 

!%%%%%%%%%%%%%% 
!! subroutine DataArraySizes(NGrd) 
subroutine DataArraySizes 
implicit none 
!!--> integer, intent(out) :: NGrd(4) 

open(unit=15, file='./Data/DataHeader.txt', status='old') 
read(15,*) NGrd(1) 
read(15,*) NGrd(2) 
read(15,*) NGrd(3) 
read(15,*) NGrd(4) 
close(15) 

RETURN 
end subroutine DataArraySizes 

!%%%%%%%%%%%%%% 
subroutine DataTGrd(i) 
implicit none 
integer, intent(in) :: i      !<-- 
!! double precision, intent(out) :: tgrd(i) !--> (NGrd(1)) 

open(unit=16, file='./Data/tgrid.dat', status='old') 
read(16,*) DataCube(I)%tgrid(:)    !<-- Is this grid(1:4)? or a single like #1 tgrd(1) 
close(16) 

RETURN 
end subroutine DataTGrd 

!%%%%%%%%%%%%%% 
subroutine ConstructDataCube()    !--> (DataCube) 
implicit none 
!!--> type(DatCube) , Intent(out) :: DataCube 
!!--> integer   , allocatable :: NGrd(:) 
!!--> double precision, allocatable :: tgrd(:) 

!!--> allocate(NGrd(4)) 
call DataArraySizes()  !!--> (NGrd) 

do I = 1, UBOUND(nGrd,1)        !<-- 
    DataCube(I)%NGrid = NGrd(I) 
ENDDO             !<-- 

AlloTGrd: do I = 1, UBOUND(nGrd,1)        !<-- 
    allocate(tgrd(I ,DataCube(I)%tgrid(NGrd(I))) 
    call DataTGrd(I) 
    !!--> DataCube(I)%tgrid = tgrd(I,:) 
ENDDO AlloTGrd 

!!deallocate(NGrd,tgrd) 

RETURN 
END subroutine ConstructDataCube 

!%%%%%%%%%%%%%% 
end module DataTypeModule 
!%%%%%%%%%%%%%% 

PROGRAM main 
USE DatatypeModule 
implicit none 
double precision, PARAMETER :: arg1 = 1.0D0 
double precision, DIMENSION(4) :: out1 
!!--> type(DatCube) :: DataCube 

call ConstructDataCube(DataCube) 

call subrtn1(arg1,out1) 

!Why stop ? stop 
end PROGRAM main 

!%%%%%%%%%% 
subroutine subrtn1(arg1,out1) 
use DataTypeModule 
implicit none 
double precision    , Intent(in ) :: arg1 
double precision, DIMENSION(4), Intent( out) :: out1 
!!--> type(DatCube) :: DataCube 

out1 = DataCube(Arg1)%NGrid !!<-- ?? 

return 
end subroutine subrtn1 

這個「答案」更多的是給你的想法,而不是一個權威的編譯「答案」。由於數據看起來像是要共享的,我將它們放入標記爲PUBLIC的MODULE中。