Fortran:将任意“结构”传递给模块子例程

2024-02-07

我正在尝试编写一个通用子例程以实现最小化。由于我想要一个通用的子例程,目标函数可以有不同的参数,不仅在名称上,而且在维度上。所以我需要一种方法来传递该参数结构(我使用“结构”一词,因为我的想法是使用类似于 Matlab 中的结构类型变量的东西)。 我设法使用派生数据类型,它工作得很好,但是当我在同一个程序中有两个不同的目标函数时,问题就出现了。这是示例代码:

在主程序main.f90中:

MODULE MYPAR
  IMPLICIT NONE
  TYPE PARPASS1    !! Parameter passing structure 1
     INTEGER       :: a
     REAL          :: X(2,2)
  END TYPE PARPASS1

  TYPE PARPASS2    !! Parameter passing structure 2
     REAL          :: b
     REAL          :: Y(3)
  END TYPE PARPASS2
END MODULE MYPAR

PROGRAM MAIN

  USE MYPAR
  USE MYLIB
  IMPLICIT NONE

  INTEGER        :: am
  REAL           :: bm,Xm(2,2),Ym(3),sol1,sol2
  TYPE(PARPASS1) :: PARAM1
  TYPE(PARPASS2) :: PARAM2

  am = 1
  bm = 3.5
  Xm(1,:) = [1.0, 2.0]
  Xm(2,:) = [0.5, 2.5]
  Ym(1:3) = [0.25,0.50,0.75]

  PARAM1%a = am
  PARAM1%X = Xm
  PARAM2%b = bm
  PARAM2%Y = Ym

  CALL MYSUB(sol1,OBJ1,PARAM1)
  CALL MYSUB(sol2,OBJ2,PARAM2)
  PRINT *,sol1
  PRINT *,sol2

CONTAINS

  SUBROUTINE OBJ1(sumval,PARAM)
    REAL,INTENT(OUT)          :: sumval
    TYPE(PARPASS1),INTENT(IN) :: PARAM
    INTEGER                   :: a
    REAL,ALLOCATABLE          :: X(:,:)
    a = PARAM%a
    X = PARAM%X
    sumval = a+X(1,1)+X(2,2)
  END SUBROUTINE OBJ1

  SUBROUTINE OBJ2(divval,PARAM)
    REAL,INTENT(OUT)          :: divval
    TYPE(PARPASS2),INTENT(IN) :: PARAM
    REAL                      :: b
    REAL,ALLOCATABLE          :: Y(:)
    b = PARAM%b
    Y = PARAM%Y
    divval = b / (Y(1)+Y(2))
  END SUBROUTINE OBJ2

END PROGRAM MAIN

还有一个名为 mylib.90 的模块

MODULE MYLIB

  USE MYPAR
  IMPLICIT NONE

CONTAINS

  SUBROUTINE MYSUB(sol,FN,PARAM)
    REAL,INTENT(OUT)           :: sol
    TYPE(PARPASS1), INTENT(IN) :: PARAM
    CALL FN(sol,PARAM)
    sol = 2*sol
  END SUBROUTINE MYSUB

END MODULE MYLIB

显然,如果我评论这些行CALL MYSUB(sol2,OBJ2,PARAM2) and PRINT *,sol2,我的代码运行顺利。这是我在拥有两个“目标函数”之前所拥有的,但现在当我拥有它们时,它不起作用,因为 MYSUB 中的派生类型变量 PARPASS1 不能是任意的。

有任何想法吗?


您可以使用接口并重载子例程 MYSUB:

MODULE MYLIB

  USE MYPAR
  IMPLICIT NONE

  interface MYSUB
    module procedure MYSUB_PARPASS1, MYSUB_PARPASS2
  end interface

CONTAINS

  SUBROUTINE MYSUB_PARPASS1(sol,FN,PARAM)
    REAL,INTENT(OUT)           :: sol
    TYPE(PARPASS1), INTENT(IN) :: PARAM
    CALL FN(sol,PARAM)
    sol = 2*sol
  END SUBROUTINE MYSUB_PARPASS1

  SUBROUTINE MYSUB_PARPASS2(sol,FN,PARAM)
    REAL,INTENT(OUT)           :: sol
    TYPE(PARPASS2), INTENT(IN) :: PARAM
    CALL FN(sol,PARAM)
    sol = 2*sol
  END SUBROUTINE MYSUB_PARPASS2   

END MODULE MYLIB

然后你可以使用 MYSUB 来调用它,它会根据 PARAM 的 TYPE 来区分功能

编辑:好的,这个怎么样:

MODULE MYPAR
  IMPLICIT NONE

  type, abstract :: PARPASS
   contains
     procedure(func), deferred :: OBJ
  end type PARPASS

  TYPE, extends(PARPASS) :: PARPASS1    !! Parameter passing structure 1
     INTEGER       :: a
     REAL          :: X(2,2)
   contains
     procedure :: OBJ => OBJ1
  END TYPE PARPASS1

  TYPE, extends(PARPASS) :: PARPASS2    !! Parameter passing structure 2
     REAL          :: b
     REAL          :: Y(3)
   contains
     procedure :: OBJ => OBJ2
  END TYPE PARPASS2

  abstract interface
     subroutine func(this, val) !Interface for the subroutine you want to implement
       import
       class(PARPASS), intent(in) :: this
       real, intent(out) :: val
     end subroutine func
  end interface

contains

   subroutine OBJ1(this, val)
    class(PARPASS1),INTENT(IN) :: this
    real, intent(out)          :: val
    INTEGER                    :: a
    REAL,ALLOCATABLE           :: X(:,:)
    a = this%a
    X = this%X
    val = a+X(1,1)+X(2,2)
  END subroutine OBJ1

  subroutine OBJ2(this, val)
    class(PARPASS2),INTENT(IN) :: this
    real, intent(out)          :: val
    REAL                       :: b
    REAL,ALLOCATABLE           :: Y(:)
    b = this%b
    Y = this%Y
    val = b / (Y(1)+Y(2))

  END subroutine OBJ2

END MODULE MYPAR


MODULE MYLIB

  USE MYPAR
  IMPLICIT NONE

CONTAINS

  SUBROUTINE MYSUB(sol, param)
    REAL,INTENT(OUT)           :: sol
    class(PARPASS), INTENT(IN) :: PARAM
    call param%obj(sol)
    sol = 2*sol
  END SUBROUTINE MYSUB

END MODULE MYLIB

PROGRAM MAIN

  USE MYPAR
  USE MYLIB
  IMPLICIT NONE

  INTEGER        :: am
  REAL           :: bm,Xm(2,2),Ym(3),sol1,sol2
  TYPE(PARPASS1) :: PARAM1
  TYPE(PARPASS2) :: PARAM2

  am = 1
  bm = 3.5
  Xm(1,:) = [1.0, 2.0]
  Xm(2,:) = [0.5, 2.5]
  Ym(1:3) = [0.25,0.50,0.75]

  PARAM1%a = am
  PARAM1%X = Xm
  PARAM2%b = bm
  PARAM2%Y = Ym

  CALL MYSUB(sol1, PARAM1)
  CALL MYSUB(sol2, PARAM2)
  PRINT *,sol1
  PRINT *,sol2

END PROGRAM MAIN

它使用包含过程的抽象类型OBJ然后您的派生类型可以扩展它并实现实际的过程。然后您可以传递任何扩展的类型PARPASS并实现类型绑定过程OBJ到“MYSUB”并从内部调用它,而无需为所有不同的可能性提供单独的接口。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Fortran:将任意“结构”传递给模块子例程 的相关文章

  • fortran 中的多重定义链接错误(ifort - gfortran)

    嗯 我有这个问题 描述很长 但我认为很容易解决 我有三个文件 nrtype f90 它有一些愚蠢的定义 但它被以下文件使用 module nrtype integer parameter I4B SELECTED INT KIND 9 in
  • fortran 77 到 fortran 90 的转换器软件 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有 fortran 77 编码 但我想转换为 fortran 90 在哪里可以下载转换器软件 这是我帮
  • 大多数编译器都会优化 MATMUL(TRANSPOSE(A),B) 吗?

    In a Fortran program I need to compute several expressions like M v MT v MT M M MT etc Here M and v are 2D and 1D arrays
  • 如何为 Fortran 95+ 模块库提供显式接口,并隐藏实现

    我正在使用 gfortran 的 95 扩展 我有一个实用程序模块库 我想链接到其他项目 即作为库或共享对象 dll 但是 在 Fortran 中 我不明白如何在不维护模块接口的两个副本的情况下将接口与 Fortran 中的实现分离 在 C
  • C++/Fortran 中贝塞尔函数的集成 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 如何在 Fortran 或 和 C 中对包含贝塞尔函数的方程进行从 0 到 无穷大 的数值积分 我在matlab中做了 但对于较大的输入和特
  • 在 Fortran 90 中,是否必须事先声明数组维度?

    是否有必要在任何其他代码之前声明数组维度 例如 我编写了以下简化的示例代码 PROGRAM mytest IMPLICIT NONE INTEGER i j k mysum Let array c be a k by k 2 array D
  • Fortran 指针多态性

    我正在尝试使用指针在对象之间创建链接 使用 Fortran 下面是代码片段 module base pars module type abstract public base pars end type end module module
  • OpenMP 因大型数组而崩溃

    我正在使用 Fortran 和 OpenMP 但当我尝试在存在大型数组时使用 OpenMP 并行化循环时 我不断遇到问题 例如 以下代码 PROGRAM main IMPLICIT NONE INTEGER PARAMETER NUMLOO
  • 编译错误:无法打开模块文件

    我有这个代码 PROGRAM xfit driver for routine fit USE nrtype USE nrutil USE nr USE ran state ONLY ran seed IMPLICIT NONE INTEGE
  • Fortran 03/08(gfortran 编译器)中使用无限多态类型进行数组操作

    我想通过以下方式实现有用的数组操作 添加元素 删除元素 通过可分配 指针 二叉树结构实现不同的实现 class 特征 无限多态性 我使用 gfortran 5 0 应该可以处理这样的功能 我需要它 以免为我使用的每种类型重复相同的代码 这应
  • Fortran 函数:指针作为实际参数,目标作为形式

    我正在尝试破译 Fortran 代码 它将指向函数的指针作为实际参数传递 而形式参数则是目标 它在主程序中定义并分配一个 globalDATA 类型的指针 然后调用一个传递该指针的函数 module dataGLOBAL type glob
  • 关于for循环中的fortran continue语句的问题

    我正在分析 Fortran 代码并有一个简单的问题 我想知道下面代码中 100 和 200 处的 继续 语句的作用 它会增加 i 和 j 计数器吗 如果是这样的话 不会if not flg 那么条件包含flg循环中 flg 的 最后一个值
  • 纯 Fortran 过程中的 I/O

    我正在尝试将错误检查合并到我正在编写的纯过程中 我想要这样的东西 pure real function func1 output unit a implicit none integer a output unit if a lt 0 th
  • 如何将mortran代码转换为fortran代码

    我有一些 Mortran 代码 来自 glmnet 我想阅读和编译 我知道在编译时 Mortran首先转换为Fortran 然后编译 如果有预处理器的话 如何安装 Mortran 预处理器 特别是 OS X 上的 Mortran3 我在以下
  • 指定 gfortran 应该在其中查找模块的目录

    我目前基于模块来编译程序 例如主程序foo这取决于模块bar 如下 gfortran c bar f90 gfortran o foo exe foo f90 bar o 当foo f90 and bar f90位于同一目录中 如何指定 g
  • 将数组从 .npy 文件读入 Fortran 90

    我使用 Python 以二维数组 例如 X 的形式生成一些初始数据 然后使用 Fortran 对它们进行一些计算 最初 当数组大小约为 10 000 x 10 000 时 np savetxt 在速度方面表现良好 但是一旦我开始增加数组的维
  • Fortran 在 gdb 中打印可分配数组

    我正在向开源科学代码添加一些功能 我使用很多可分配项 但在正确打印它们时遇到一些问题 例如 我声明并分配 然后使用 real dp allocatable psi n phi some other stuff here allocate p
  • gfortran 支持尾调用消除吗?

    我编写了这个小程序来测试 gfortran 是否执行尾调用消除 program tailrec implicit none print tailrecsum 5 0 contains recursive function tailrecsu
  • forrt1:严重(170):程序异常 - 堆栈溢出

    并提前感谢您的帮助 我已经编译了一个程序 不是我编写的 它在 Mac 上运行得很好 但是当我尝试在 Windows 上执行该程序时 在程序开始执行后不久 我收到以下错误消息 forrt1 严重 170 程序异常 堆栈溢出 我不是 ifort
  • Fortran 递归分段错误

    我必须设计并实现一个 Fortran 例程来确定方格上簇的大小 并且递归地编写子例程似乎非常方便 然而 每当我的晶格大小超过某个值 大约 200 边 时 子例程就会始终出现段错误 这是我的集群检测例程 RECURSIVE SUBROUTIN

随机推荐