2012-07-20 3 views
3

Я пишу библиотеку для импорта геометрий многих типов (сфер, плоскостей, поверхностей NURBS, stl-файлов ...) в научный код Fortran. Подобная проблема кажется сложной для ООП, потому что просто определить type :: geom, а затем type,extends(geom) :: analytic и так далее. У меня есть проблема с файлом IO.Файл IO с использованием полиморфных типов данных в Fortran

Мое решение на данном этапе состоит в том, чтобы написать параметры, определяющие фигуры, в том числе некоторые флаги, которые говорят мне, какая форма. Когда я читаю, я создаю экземпляр class(geom) :: object (так как я не знаю заранее, какой подтип будет), но как я могу его прочитать?

Я не могу получить доступ к каким-либо конкретным компонентам подтипа. Я читал, что downcasting verboten, и, кроме того, новый allocate(subtype :: class) не работает. Новый READ(FORMATTED), похоже, не реализован ifort или gfortran. то есть

module geom_mod 
    type :: geom 
    end type 
    type,extends(geom) :: sphere 
    integer :: type 
    real(8) :: center(3),radius 
    contains 
    generic :: READ(FORMATTED)=> read_sphere ! not implemented anywhere 
    end type 
contains 
    subroutine read_geom(object) 
    class(geom),intent(out),pointer :: object  
    integer :: type 

    read(10,*) object%type ! can't access the subtype data yet 

    read(10,*) type 
    backspace(10) 
    if(type==1) then 
     allocate(sphere :: object)! downcast? 
     read(10,*) object   ! doesn't work 
    end if 

    end read_geom 
end module 

Я все об этом не так? Я мог бы взломать это, используя что-то другое, кроме полиморфизма, но это кажется чище везде. Помощь была бы весьма признательна.

EDIT: пример программы с использованием модуля IanH в

program test 
    use geom_mod 
    implicit none 
    class(geom),allocatable :: object 

    open(10) 
    write(10,*) '1' 
    write(10,*) sphere(center=0,radius=1) 
    rewind(10) 

    call read(object) ! works ! 
end program test 
+0

Вашего входного файла должен иметь (по крайней мере) две записи для моего примера кода - первая запись с целым числом для типа, вторая с данными сферы. Вы действительно получаете segfault или это состояние конца файла? – IanH

+0

Я добавил в тип сферы строку 'integer :: type = 1', которая просто путала проблему. Я не знаю, почему это приводит к ошибке seg, но когда я придерживаюсь вашего модуля как есть, он работает. Благодаря! – weymouth

+0

Кажется, что seg fault связан с наличием каких-либо переменных в производном типе со значениями по умолчанию. Поэтому, если я устанавливаю «radius = 1» в определении типа, я получаю ошибку seg. – weymouth

ответ

3

Текущий gfortran и ifort не реализуют определенный вход/выход. Я не видел никаких доказательств того, что эта ситуация изменится в ближайшем будущем. Тем не менее, помимо разрешения некоторых синтаксических ярлыков, функция которых на самом деле не спасает вас от работы.

Один из подходов к этой ситуации - вызвать «фабрику» для расширений геометрии, которая использует данные в файле, чтобы назначить аргумент правильному типу, а затем передать процедуру привязки типа, которая читается в типе данные. Например:

module geom_mod 
    implicit none 
    integer, parameter :: dp = kind(1.0d0) 
    type, abstract :: geom 
    contains 
    procedure(read_geom), deferred :: read 
    end type geom 

    abstract interface 
    subroutine read_geom(object) 
     import :: geom 
     implicit none 
     class(geom), intent(out) :: object 
    end subroutine read_geom 
    end interface 

    type, extends(geom) :: sphere 
    real(dp) :: center(3), radius 
    contains 
    procedure :: read => read_sphere 
    end type sphere 
contains 
    subroutine read(object) 
    class(geom), intent(out), allocatable :: object 
    integer :: type 
    read (10, *) type 
    ! Create (and set the dynamic type of object) based on type. 
    select case (type) 
    case (1)  ; allocate(sphere :: object) 
    case default ; stop 'Unsupported type index' 
    end select 
    call object%read 
    end subroutine read 

    subroutine read_sphere(object) 
    class(sphere), intent(out) :: object 
    read (10, *) object%center, object%radius 
    end subroutine read_sphere 
end module geom_mod 

Текущий ifort (12.1.5) имеют проблемы с целью (уходит) полиморфные аргументами, которые могут потребоваться обходные путями, но общий подход остается тем же самым.

(Обратите внимание, что процедура чтение не является типом связанной подпрограммы - читать использование объекта общего GeoM «» вызова чтения (объекта) «» в обычном эталонной подпрограмме стиля.)