Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 如何在Fortran中将许多临时数组传递给子例程?_Arrays_Fortran - Fatal编程技术网

Arrays 如何在Fortran中将许多临时数组传递给子例程?

Arrays 如何在Fortran中将许多临时数组传递给子例程?,arrays,fortran,Arrays,Fortran,假设我正在编写一个Fortran子程序,它执行模拟的一个时间步,因此将被重复调用。为了完成它的工作,它需要许多临时数组,这些数组在子例程之外没有意义或用处。用户可能希望在程序执行期间(可能同时)执行多个不同大小的模拟,但是对于特定模拟的所有时间步,阵列的尺寸将是相同的 我应该如何处理这些临时数组?我能想到的每一种方法都有问题 如果我要使用子例程的本地数组,它们要么必须放在堆栈上,这将限制它们的大小,要么必须在堆上分配,这将浪费时间,因为每个时间步都会分配和释放数组 或者,调用方可以分配数组。但

假设我正在编写一个Fortran子程序,它执行模拟的一个时间步,因此将被重复调用。为了完成它的工作,它需要许多临时数组,这些数组在子例程之外没有意义或用处。用户可能希望在程序执行期间(可能同时)执行多个不同大小的模拟,但是对于特定模拟的所有时间步,阵列的尺寸将是相同的

我应该如何处理这些临时数组?我能想到的每一种方法都有问题

  • 如果我要使用子例程的本地数组,它们要么必须放在堆栈上,这将限制它们的大小,要么必须在堆上分配,这将浪费时间,因为每个时间步都会分配和释放数组

  • 或者,调用方可以分配数组。但是,如果调用者要将每个数组作为单独的参数传递给子例程,那么调用者必须知道有多少个数组以及每个数组有多大。此外,如果以某种方式修改子例程,从而更改数组的数量或大小,则必须修改对子例程的每次调用

  • 我见过的一种技术是,子例程接受单个大数组,并将其视为连接在一起的几个临时数组。然而,这似乎有风险,因为一个算术错误可能会导致很难找到的bug

  • 最后,我可以将所有临时数组放入一个派生类型,然后编写一个单独的子例程来分配所有数组,并编写另一个子例程来释放它们。这样,只有少数子例程必须知道临时数组。然而,我的理解是,至少在Fortran的最新版本之前,派生类型只能包含指向数组的指针。这将带来与使用指针相关的所有缺点(潜在的bug、别名等)


有没有办法避免这些问题?(或者这些问题中的任何一个没有我想象的那么重要?

您可以在数组上使用save属性

subroutine step(x, t, do_allocattion)
    double precision, intent(in) :: x(:)
    double precision, intent(in) :: t
    logical, intent(in), optional :: do_allocation

    integer :: n
    double precision, allocatable, save :: work1(:), work2(:)
    n = size(x)

    if (present(do_allocation)) then
        if (do_allocation) then
            allocate(work1(n))
            allocate(work2(n))
        end if
    end if

    ! do work on x
end subroutine
编辑:另一种解决方案,因为我混合了指针数组

subroutine step(x, t)
    double precision, intent(in) :: x(:)
    double precision, intent(in) :: t

    integer :: n
    double precision, allocatable, save :: work1(:), work2(:)
    n = size(x)

    if (.not. allocated(work1)) then
        allocate(work1(n))
    end if
    if (.not. allocated(work2)) then
        allocate(work2(n))
    end if

    ! do work on x
end subroutine

编辑:警告:您不能简单地检查“分配性”,因为当程序启动并第一次执行子例程时,它将是未定义的。您可以添加另一个可选参数以解除分配。->指针阵列就是这样。

可分配组件是在2001年发布的“可分配TR”(ISO/IEC TR 15581)中引入的,并在Fortran 2003中纳入了基础语言标准。大多数目前维护的Fortran编译器在几年内为它们提供了良好的支持。这有点超出了最近的范围。默认情况下,我会将其分配为本地数组,并且只有在分析显示存在问题时才使用不同的方法。您所说的“您不能简单地检查“分配性”,因为在程序启动时它将是未定义的”是什么意思?当执行开始时,所有可分配变量的分配状态定义为“未分配”。此外,由于Fortran 95,分配状态“undefined”不存在。您好,我一定是混合了指针数组,正如这里所暗示的:(查找“未定义指针的大危险”)。是的,没有初始化的指针从undefined开始(关联而不是分配)如果我在做多个不同大小的模拟,这能起作用吗?(例如,如果用户同时启动两个模拟会怎样?)如果代码是共享库的一部分,我的第一个想法是定义一个包含可分配数组的派生类型(DT)。DT变量可以在主程序中声明,并作为单个参数传递给例程。
subroutine step(x, t)
    double precision, intent(in) :: x(:)
    double precision, intent(in) :: t

    integer :: n
    double precision, allocatable, save :: work1(:), work2(:)
    n = size(x)

    if (.not. allocated(work1)) then
        allocate(work1(n))
    end if
    if (.not. allocated(work2)) then
        allocate(work2(n))
    end if

    ! do work on x
end subroutine