2017-05-27 39 views
2

私はメインプログラムとすべてのサブルーチンにグローバルにアクセスできるデータ構造を作成しようとしています。データ構造はいくつかの.datファイルを読み込むことで構築されています。Fortranモジュールとグローバル変数

この種のグローバルなアクセシビリティは、モジュールにとって適切なようです。これまでの私のモジュールソリューションには以下が含まれます:1)データ型をグローバルに定義する。 2).datファイルを開く/読み込むためのモジュールにサブルーチンの束をインクルード(包含)する。 3).datファイルからデータ型を構築する。

理想的には、このデータ構造をモジュール内に構築し、この単一のデータ構造をグローバルにアクセス可能にしたいと考えています。私はモジュールのプロシージャを呼び出すたびに.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とiを引数として渡さずにデータx、iにアクセスしますか? – jkedmond

+0

@jkedmond適切なモジュールにアクセスできる場合のみ。 @VladimirF。 –

+0

あなたは、特定のサブルーチンで "use my_data、only:read_data、x、i"宣言を追加する限り、引数としてxとiを渡す必要はないと言っていますか? – jkedmond

-1

モジュールをPRIVATEとみなしたり、PUBLICとみなしたりすることができます。私はプライベートを表示します。

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に入れます。

関連する問題