首页 > 解决方案 > 在 Fortran 中为特定声明类型概括您的操作

问题描述

我有一个使用 Fortran 中声明的类型的数组结构

例如

 type t_data 

    integer :: N
    real, allocatable :: x(:)
    real, allocatable :: z(:)      
    real, allocatable :: y(:)

    contains 

    procedure :: copy
    procedure :: SWAP 
    procedure :: copy_element

 end type 

 ! constructor 
 interface t_data
    module procedure constructor 
 end interface  

 contains 

 subroutine copy(this, old) 
    class(t_data), intent(inout)    :: this
    type(t_data), intent(in)        :: old
    do i = 1, old% N
       this% x(i) = old% x(i) 
       etc .. 
    end do
 end subroutine 

 subroutine copy(this, old) 
    class(t_data), intent(inout)    :: this
    type(t_data), intent(in)        :: old
    do i = 1, old% N
       this% x(i) = old% x(i) 
       etc .. 
    end do
 end subroutine 

 function constructor(size_) 
    integer, intent(in) :: size_ 
    type(t_data), :: constructor
    allocate(constructor% x(size_)) 
    allocate(constructor% y(size_) ) 
    ! etc 
 end function 

 subroutine swap(this, from, i1,i2) 
    class(t_particle_data), intent(inout) :: this
    type(t_particle_data), intent(in)    :: from
    integer, intent(in)                  :: i1, i2

    this% x(i1) = from% x(i2) 
    ! etc 
 end subroutine

这些是一组需要对声明类型的所有数组执行相同操作的过程示例t_data。我的问题是如何使它更易于维护以解决例如我们稍后想要将新组件添加到声明的类型时的情况。目前,当我向 my 添加一个新数组时t_data,我需要遍历所有这些过程、构造函数、解构函数并添加组件。

我在问是否有办法让这更容易。

我的应用程序

请注意,这些数据类型用于粒子模拟。最初我分配了大量的 t_data 。然而,在我的模拟后期,我可能需要更多的粒子。因此,我分配了一个具有更多内存的新 t_data 并将旧的复制t_data到其旧大小。

   subroutine NEW_ALLOC(new, old)
   type(t_data), intent(out) :: new  
   type(t_data), intent(inout) :: old  

   nsize = old% N * 2 ! allocate twice the old size 

   new = T_DATA(nsize) 
   call new% copy(old) 
   !DEALLCOte OLD
   end subroutine 

有没有人/是否有可能以更聪明的方式做到这一点。我不介意将它与 C/C++ 混合?

标签: c++fortrangeneric-programmingstructure-of-arrays

解决方案


我的问题是如何使它更易于维护以解决例如我们稍后想要将新组件添加到声明的类型时的情况。

以下是我将如何解决这种情况,以及有多少 Fortran 程序员已经解决了这种情况。我不认为有一个包含 3 个坐标数组的派生类型的迫切需要,并且像 OP 所担心的那样,以这种方式解决问题需要向问题添加另一个维度需要代码修改,例如添加一个成员数组real, allocatable :: w(:)t_data并重新编码在该类型上运行的所有类型绑定过程。

所以放弃这种方法,转而使用

TYPE t_data
   REAL, DIMENSION(:,:), ALLOCATABLE :: elements
END TYPE t_data

让我们举几个例子来说明

TYPE(t_data) :: t1 ,t2, t3

elements我们可以通过这种方式分配其中任何一个的成员

ALLOCATE(t1%elements(3,10))

这也很容易

ALLOCATE(t1%elements(6,100))

或任何你想要的。与原始派生类型设计相比,这具有elements可以在运行时确定尺寸的优势。这也使得难以为每个坐标数组设置不同的长度。

现在,复制t1就像

t2 = t1

现代 Fortran 甚至负责自动分配elements. t2所以我认为不需要定义复制整个t_data. 至于交换数据,切片和切块,这很简单

t2%elements(1,:) = t1%elements(2,:)

甚至

t2%elements(1,:) = t1%elements(1,6:1:-1)

或者

t2%elements(1,:) = t1%elements(1,[1,3,5,2,4,6])

如何将这些包装到swap例程中应该很明显。但如果不是,请再问一个问题。

接下来,关于在执行期间需要为元素分配更多空间。首先是一个临时数组

REAL, DIMENSION(:,:), ALLOCATABLE :: temp

然后像这样的小代码,将elements.

ALLOCATE(temp(3,2*n))
temp(:,1:n) = t2%elements(:,1:n)
CALL MOVE_ALLOC(to=t2%elements,from=temp)

同样,您可能希望将其包装到一个过程中,如果您需要帮助,请寻求帮助。

最后,这一切的教训不是分享我将如何编程问题,而是分享Fortran中编程的想法。


推荐阅读