Variables Fortran模块和全局变量
我正在尝试创建一个可以全局访问主程序和所有子例程的数据结构。数据结构是通过读取一些.dat文件构建的 这种全局可访问性似乎适合于模块。到目前为止,我的模块解决方案包括:1)全局定义数据类型;2) 在模块中包括(包含)一组子程序以打开/读取.dat文件;3)从.dat文件构造数据类型 理想情况下,我希望在模块中构建此数据结构一次,然后使此单一数据结构可以全局访问。我不希望每次调用模块过程时都打开/读取.dat文件 比如说。是否有方法将数据结构声明为主程序中的全局变量,然后调用模块过程构建一次数据结构 @罗斯。源代码:Variables Fortran模块和全局变量,variables,module,fortran,global,Variables,Module,Fortran,Global,我正在尝试创建一个可以全局访问主程序和所有子例程的数据结构。数据结构是通过读取一些.dat文件构建的 这种全局可访问性似乎适合于模块。到目前为止,我的模块解决方案包括:1)全局定义数据类型;2) 在模块中包括(包含)一组子程序以打开/读取.dat文件;3)从.dat文件构造数据类型 理想情况下,我希望在模块中构建此数据结构一次,然后使此单一数据结构可以全局访问。我不希望每次调用模块过程时都打开/读取.dat文件 比如说。是否有方法将数据结构声明为主程序中的全局变量,然后调用模块过程构建一次数据结
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
一次读取和多次访问的数据非常常见。下面是一个简单的例子,说明这是如何工作的。模块
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
编辑:这里发生的一个关键部分是x
和i
存储在阅读模块和主程序都可以访问的地方。在这个简单的示例中,我选择将其存储在my_data
中,但可以想象它可能在其他地方。您发布的示例代码已被删除(请将其编辑到您的问题中),从不存储您阅读的数据。在读取数据一次后存储数据是至关重要的
编辑2:在编辑的源代码中,将数据读入主程序中声明的变量
DataCube
。然后,尝试访问变量DataCube
中的数据,该变量在子例程subrtn1
中声明这些变量不相同。必须声明一次,然后从多个位置访问它。最好的方法是将其包含在模块中,如我在示例中所示。但是,您也可以将其作为参数传递给例程,但这会变得很麻烦。您可以将该模块假定为私有模块或假定为公共模块。我会带你去的
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
模块数据类型模块
隐式无
私有的分配(NGrd(4))
调用DataArraySizes()!!-->(NGrd)
I=1,UBOUND(nGrd,1)!类型(DatCube)::DataCube
out1=DataCube(Arg1)%NGrid!!我不明白你困惑的根源。为什么不在程序开始时调用read_data
一次,然后使用来自任何地方的变量呢?@Ross。每次我调用模块过程(从主程序或各种子例程),它都会打开/读取.dat文件并构造数据结构。这是一个巨大的时间水槽。我想调用模块过程(构造数据结构)一次,并将此数据结构设置为主程序和所有子例程可访问的全局变量。我不想将此数据结构作为参数传递给每个子例程,因为我有许多嵌套过程。好吧,这是以前发布的源代码的不同版本,但它看起来更小,所以这很好。@Ross。这里的要点是:我想从.dat文件构造一个全局可访问的数据结构。我不想将该数据结构作为参数传递给从主程序调用的(嵌套)子例程过程。我不想每次调用模块子程序时都阅读.dat文件。我已经阅读并理解了您的问题。请阅读并尝试理解答案。在您的示例中,从主程序调用的(嵌套)子例程是否可以访问数据x,i,而不将x和i作为参数传递?@jkedmond,前提是它们可以访问相应的模块。@VladimirF。你的意思是,只要我在特定的子例程中添加声明“仅使用我的数据:读取数据,x,I”,我就不必将x和I作为参数传递?为什么要调用读取???你不必这么做。他们与访问x
和i
无关……请耐心等待。我对堆栈交换和FORTRAN编程都是新手。