массив переменной длины в производном типе - PullRequest
0 голосов
/ 09 октября 2018

Я в основном занимаюсь научным программированием на Python, и у меня нет большого опыта работы с Fortran (90/95).Для одного из моих проектов я хочу определить производный тип и перегрузить группу операторов для этого типа.Критически, я хотел бы, чтобы одна из переменных производного типа была массивом переменной длины;по крайней мере, мне нужны две разные длины в разных частях кода.Как мне лучше всего добиться этого эффективно и избежать дублирования кода?

Мой первый подход состоял в том, чтобы использовать выделяемый массив, но при этом использовалось несколько операторов alloc для всего кода, включая перегруженные операторы.Это также приводило к трудностям при использовании кода в приложении MPI.

Мой текущий подход состоит в том, чтобы два определяют тип одного и того же имени в двух отдельных модулях и используют один или другой в разных частях кода.Перегруженные операторы могут быть разделены с помощью файла заголовка (mytype_operators.h в примере ниже).

    module mod1
      type mytype
        real :: x1
        real,dimension(1) :: x2
      end type mytype
#include "mytype_operators.h"
    end module mod1

    module mod2
      type mytype
        real :: x1
        real,dimension(10) :: x2
      end type mytype
#include "mytype_operators.h"
    end module mod2

К сожалению, в коде есть один модуль с подпрограммами, которые я хотел бы использовать для обоих типов.В настоящее время у меня есть две копии этого кода;один с "use mod1", другой с "use mod2".Могу ли я улучшить это и избежать дублирования кода?

1 Ответ

0 голосов
/ 10 октября 2018

Ваш случай очень подходит для использования функции Fortran, представленной в стандарте 2003 года (и принятой намного позже компиляторами) с именем параметризованные производные типы .Прежде всего, вы должны проверить состояние соответствия вашего компилятора, чтобы узнать, поддерживается ли он полностью.

Эта функция позволяет передавать пользовательские параметры при объявлении или создании производного типа, поэтому внутренняя функциональность будет соответствующим образом скорректирована.,Они хороши для того, чтобы различные варианты поведения группировались в одно имя типа, возможно, со значительными различиями в кодировании или хранении.Существует 2 типа параметров:

  • kind параметры ведут себя подобно спецификатору типа внутренних типов.Добрые параметры всех переменных должны быть известны во время компиляции и рассматриваться практически как постоянные значения.Удобство состоит в том, что вы можете легко изменить его (во времени кода), изменив только значение в объявлении или конструкции.Это обычно используется для специализации типа компонентов встроенного типа.
  • len параметры ведут себя подобно спецификатору len внутреннего типа символа.Вы можете определить параметры len во время компиляции или во время выполнения, и параметр len переменной не может измениться, пока вы не объявите его размещаемым.Более того, вы можете иметь аргументы с предполагаемыми len-параметрами в процедурах и избежать многословия кода.Это обычно используется в качестве параметра "длины" или "измерения" для производного типа, потому что вы можете использовать их в объявлении границ массива и длины символа.

В общем, используются параметры типаимитировать функциональность встроенных типов в производных типах, но вы также можете проявить «творческий подход» и использовать его для других целей, таких как пространство измерений типа матрицы преобразования;для пользовательского «типа объединения» (например, перечисление);как природа физической величины в типе данных «единицы измерения» (действительное значение, помеченное единичным «массой», напрямую не совместимо с «температурным», но с ними можно обращаться почти так же, как вкод);"arity" типа кортежа ...

module mod1
  type :: mytype(n)
    integer, len :: n
    real :: x1
    real, dimension(n) :: x2
  end type mytype
contains
  ! your operations here...
end module mod1

И используйте его так:

program test_pdt
  use mod1
  implicit none

  type(mytype(10)) :: mt10
  type(mytype(1)) :: mt1
  integer :: i

  mt10%x1 = 40.0
  mt10%x2 = [(0.5 * i, i = 1, 10)]
  mt1 = mytype(1)(20.0, [30.0])

  call sub(mt10)
  call sub1(mt1)

contains
  subroutine sub(m)
    ! accepts values with any "n" parameter
    type(mytype(*)) :: m
    ! you can also use them in declarations
    integer, dimension(m%n + 1) :: y
    type(mytype(m%n)) :: w
    print *, m%n, w%n, size(y)
  end

  subroutine sub1(m)
    type(mytype(1)) :: m  ! only accepts values with n=1
    print *, m%x1, m%x2, m%n
  end
end

Предупреждение: это особенность, несмотря на то, что было объявлено многонесколько лет назад был добавлен в большинство компиляторов совсем недавно, и вы должны знать, что в реализации все еще есть некоторые ошибки.Вероятно, с регулярным использованием у вас все будет в порядке, но в некоторых случаях я часто сталкиваюсь с ложными синтаксическими ошибками, а иногда даже с ICE.

...