2015-01-28 2 views
1

Я пытаюсь сделать гибкий пользовательский интерфейс для численного решения. Проблема в том, что я не могу сформулировать, как реализовать динамический выбор геометрии исходного состояния (прямоугольник, сфера и т. Д.). Я пытался использовать абстрактный класс initial_conditions_geometry как родитель с ребенком классов rectangular и sphere, которые указывают определенные атрибуты и реализовать метод in_bounds для геометрии:Динамический выбор типа объекта

type ,abstract :: initial_conditions_geometry 
    contains 
     procedure (in_bounds) ,deferred :: in_bounds 
end type 

abstract interface 
    logical function in_bounds(this,coordinates) 
     import :: rkind 
     import :: initial_conditions_geometry 
     class(initial_conditions_geometry) ,intent(in) :: this 
     real(rkind)  ,dimension (:)  ,intent(in) :: coordinates 
    end function in_bounds 
end interface 

type ,extends(initial_conditions_geometry) :: rectangular 
    integer ,dimension(:,:) ,allocatable :: rectangular_bounds 
contains 
    procedure :: in_bounds => in_bounds_rectangular 
end type 

type ,extends(initial_conditions_geometry) :: sphere 
    integer ,dimension(:,:) ,allocatable :: sphere_bounds 
    integer ,dimension(:) ,allocatable :: sphere_center 
contains 
    procedure :: in_bounds => in_bounds_sphere 
end type 

interface rectangular 
    procedure constructor_rectangular 
end interface 

interface sphere 
    procedure constructor_sphere 
end interface 

Вот initial_conditions_layer определение класса, который включает в себя первоначальную геометрию и распределение условие:

type :: initial_conditions_layer 
    class(initial_conditions_geometry) ,allocatable :: layer_geometry 
    type(initial_conditions_distribution)    :: distributor 
end type 

interface initial_conditions_layer 
    procedure constructor 
end interface 

Возникает вопрос: как можно управлять, чтобы создать constuctor для initial_conditions_layer, динамически (в зависимости от типа геометрии в некотором текстовом файле) устанавливает layer_geometry типа (прямоугольный, сферы и т. д.)?

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

type(initial_conditions_layer) function constructor(dimensions,layer_number,initial_conditions_data_file_unit) 
    integer ,intent(in) :: layer_number 
    integer ,intent(in) :: initial_conditions_data_file_unit 
    integer ,intent(in) :: dimensions 
    character(len=20) :: layer_distribution_type 
    character(len=20) :: layer_geometry_name  

    call get_layer_properties(initial_conditions_data_file_unit,layer_number,layer_geometry_name,layer_distribution_type) 

    select case(layer_geometry_name) 
    case('rectangular') 
     allocate(rectangular::constructor%layer_geometry) 
    case('sphere') 
     allocate(sphere::constructor%layer_geometry) 
    end select 

    select type(constructor%layer_geometry) 
    type is(rectangular) 
     constructor%layer_geometry = rectangular() 
    type is(sphere) 
     constructor%layer_geometry = sphere() 
    end select 
end function 

Но это требует associate_name в выберите тип конструкции. Associate_name должно быть указателем на initial_conditions_geometry, но нельзя установить атрибут target в поле производного типа.

+1

Вы имеете в виду что-то вроде (извините код комментария и неявный материал): 'if (geom.eq.'rectangle ') allocate (rectangular :: layer% layer_geometry)'? Это явно не полный ответ, но мне интересно, не хватает ли я чего-то. – francescalus

+0

Да! Но я не нашел способ реализовать его в конструкции 'select type', потому что для этого требуется указатель' associate-name' .. И я не могу объявить конструктор переменной class (initial_conditions_geometry), allocatable, указатель :: geometry' внутри для этого требуется установить целевой атрибут для 'layer_geometry', но это запрещено стандартом. –

+0

Думаю, вам придется отредактировать свои попытки в вопросе, потому что, боюсь, я не буду следовать. Но в конструкторе для 'initial_conditions_layer', на что вы пытаетесь« выбрать тип »? – francescalus

ответ

1

То, что у вас есть, очень близко к работе, и я думаю, что у вас просто есть недоразумение.

Но для этого требуется имя-ассоциированное имя в конструкции типа выбора. Associate_name должно быть указателем на initial_conditions_geometry, но нельзя установить атрибут target в поле производного типа.

An associate-name требуется в этом случае, но, независимо от синтаксиса =>, не указатель не участвует. Вы могли бы, без других изменений, имеют

select type(clg => constructor%layer_geometry) 
type is(rectangular) 
    clg = rectangular() 
type is(sphere) 
    clg = sphere() 
end select 

С другой стороны, в этом простом случае можно покончить с select type построить полностью, и обращаться с вещами в select case у вас уже есть.

Использование источников выделения с каждым конструктором:

select case(layer_geometry_name) 
case('rectangular') 
    allocate(constructor%layer_geometry, source=rectangular()) 
case('sphere') 
    allocate(constructor%layer_geometry, source=sphere()) 
end select 

или даже

select case(layer_geometry_name) 
case('rectangular') 
    constructor%layer_geometry = rectangular() 
case('sphere') 
    constructor%layer_geometry = sphere() 
end select 

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

+0

Еще раз спасибо, очень полезный ответ! Я проверил все предложенные вами случаи, и все они работают абсолютно нормально! –

+0

Нет, я думаю, что решение с типом выбора является самым мощным, потому что в отладчике можно увидеть параметры 'clg'. В противном случае 'constructor% layer_geometry' получает' прямоугольный' тип, но отладчик все еще не может отображать прямоугольные параметры 'constructor% layer_geometry'. Я пробовал что-то вроде этого, но имел некоторые странные ошибки. Возможно, я исправил их во время разработки, и теперь все в порядке. –

Смежные вопросы