麻烦的行是
因此,我一直在搜索3-4天,但找不到该问题的答案。它与特定派生类型的可分配数组有关。这都是计算流体动力学求解器的一部分。但是,实际应用并不重要。让我提供一些(快速)编程上下文。
假设我们有一个简单的模块,它定义了固定大小的派生类型,而主程序分配了许多类型的数组:
module types
integer, parameter :: equations = 10
type array_t
double precision :: variable(equations) ! variables to solve
double precision :: gradient(equations,3) ! gradient of variables in x,y,z direction
double precision :: limiter(equations) ! limiter of variables
end type
end module
program test
use types
implicit none
type(array_t), allocatable :: array(:)
integer :: elements
elements = 100
allocate(array(elements))
end program
当然,可以使用每个编译器来编译此代码段。由于array_t的大小是固定的,并且在编译时是已知的,因此我们只需要在单行中分配结构array(定义结构中array_t的重复次数)。
关于存储位置,变量将按以下方式存储:
array(1)%variable(1) ! element 1
array(1)%variable(2)
...
...
array(1)%gradient(1,1) ! the rest of this 2D array will be written column-major in fortran
array(1)%gradient(2,1)
array(1)%gradient(3,1)
...
...
array(1)%limiter(1)
array(1)%limiter(2)
...
...
array(2)%variable(1) ! element 2
array(2)%variable(2)
...
...
在此示例中,我们设置参数equations = 10。在求解器中,我们始终将此大小保留为最大值(10):所有派生类型都具有求解器可能需要的最大尺寸。不幸的是,这意味着我们可能会分配比实际需要更多的内存-某些模拟可能只需要5或6个方程,而不是10-。此外,当我们求解较少的方程式时,派生的类型维数保持固定为10的事实使求解器变慢-未使用的内存位置将减少内存带宽-。
我想做的是利用具有allocatable属性的派生类型。这样,我可以仅使用所需数量的方程式(即array_t的维数)分配结构,这些方程式将在运行时(而不是在编译时)定义,并会根据模拟参数进行更改。
看下面的代码片段:
module types
integer, save:: equations
type array_t
double precision, allocatable :: variable(:) ! variables to solve
double precision, allocatable :: gradient(:,:) ! gradient
double precision, allocatable :: limiter(:) ! limiter of variables
end type
end module
program test
use types
implicit none
type(array_t), allocatable :: array(:)
integer :: i,elements
equations = 10
elements = 100
allocate(array(elements))
do i=1,elements
allocate(array(i)%variable(equations))
allocate(array(i)%gradient(equations,3))
allocate(array(i)%limiter(equations))
enddo
end program
到目前为止,这是唯一方法我设法使它起作用。解算器运行并收敛,这意味着语法不仅可编译,而且等效于使用固定大小。
然而,即使对于相同数量的方程,求解器的速度也明显较慢。
这意味着存在内存未对齐。基于测量的运行时,似乎变量的存储方式与使用固定大小时的存储方式不同。
在第二种方法中,变量如何存储在全局存储器中?我想实现与第一种方法相同的模式。我感觉就像分配结构的第一行
allocate(array(elements))
不知道要分配什么,所以它分配了大块内存(以适应以后将要分配的可分配类型),或者只是将索引array(1)分配给array(elements)而没有其他分配(这意味着结构的实际内容稍后会在循环中存储。
如何使第二种方法像第一种方法一样存储变量?
EDIT#1
由于参数化派生类型具有吸引力,我认为发布一些其他详细信息将很有用。
参数化派生类型将在将数组分配到主程序内部的情况下工作(例如我发布的示例代码)。>>
但是,我的“现实世界”案例更像以下情况:
(file_modules.f90) module types integer, parameter :: equations = 10 type array_t double precision :: variable(equations) ! variables to solve double precision :: gradient(equations,3) ! gradient pf variables double precision :: limiter(equations) ! limiter of variables end type end module module flow_solution use types type (array_t), allocatable, save :: cell_solution(:) end module (file_main.f90) program test use flow_solution implicit none integer :: elements elements = 100 allocate(cell_solution(elements)) end program
这些(如您所愿)是通过Makefile单独编译和链接的。如果我使用参数化派生类型,则无法编译模块文件,因为在编译时类型的大小'n'不知道。
EDIT#2
] >>我被建议提供带有参数化派生类型的工作和非工作代码的示例。
工作示例
:module types integer, parameter :: equations=10 type array_t(n) integer, len :: n double precision :: variable(n) ! variables to solve double precision :: gradient(n,n) ! gradient double precision :: limiter(n) ! limiter of variables end type end module module flow_solution use types type(array_t(equations)), allocatable, save :: flowsol(:) end module program test use flow_solution implicit none integer :: i,elements elements = 100 allocate(flowsol(elements)) end program
非工作示例
:
module types integer, save :: equations type array_t(n) integer, len :: n double precision :: variable(n) ! variables to solve double precision :: gradient(n,n) ! gradient double precision :: limiter(n) ! limiter of variables end type end module module flow_solution use types type(array_t(equations)), allocatable, save :: flowsol(:) end module program test use flow_solution implicit none integer :: i,elements equations = 10 elements = 100 allocate(flowsol(elements)) end program
编译器(错误)错误:
test.f90(16): error #6754: An automatic object must not appear in a SAVE statement or be declared with the SAVE attribute. [FLOWSOL] type(array_t(equations)), allocatable, save :: flowsol(:) ---------------------------------------------------^ test.f90(16): error #6841: An automatic object must not appear in the specification part of a module. [FLOWSOL] type(array_t(equations)), allocatable, save :: flowsol(:) ---------------------------------------------------^ compilation aborted for test.f90 (code 1)
我应该以其他方式声明/分配数组吗?
因此,我一直在搜索3-4天,但找不到该问题的答案。它与特定派生类型的可分配数组有关。这都是...的全部部分]]
麻烦的行是
type(array_t(equations)), allocatable, save :: flowsol(:)
这里,您希望将长度参数化的类型保存为对象。作为编译器对象,保存的对象不能是自动对象。
现在,为什么flowsol
是自动对象?它是自动的,因为其类型为array_t(equations)
:equations
不是常数。相反,您希望推迟type参数(与数组的形状一样):
type(array_t(:)), allocatable, save :: flowsol(:)
当您要分配这样的对象时,您需要提供长度类型参数值:
allocate(array_t(equations) :: flowsol(elements))
麻烦的行是