I'm trying to make flexible user interface for numerical solver. The problem is that I cannot formulate how to implement dynamic choosing of initial condition geometry (rectangular, sphere etc). I've tried to use abstract class initial_conditions_geometry
as a parent with child classes rectangular
and sphere
which specify certain attributes and implement method in_bounds
for geometry:
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
Here is initial_conditions_layer
class definition, which encompasses initial condition geometry and distribution:
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
The question is: how can manage to create constuctor for initial_conditions_layer
that dynamically (depending on geometry type in some text file) sets layer_geometry
type (rectangular, sphere etc) ?
Edit Maybe it is useful to add some of my attempts to solve this problem. I've tried to organize constructor for initial_conditions_layer object as follows:
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
But this requires associate_name in select type construct. Associate_name should be a pointer to initial_conditions_geometry, but one cannot set target attribute to derived type field.
What you have is quite close to working, and I think you merely have a misunderstanding.
But this requires associate_name in select type construct. Associate_name should be a pointer to initial_conditions_geometry, but one cannot set target attribute to derived type field.
An associate-name
is required in this case but, regardless of the =>
syntax, no pointer is involved. You could then, without other changes, have
select type(clg => constructor%layer_geometry)
type is(rectangular)
clg = rectangular()
type is(sphere)
clg = sphere()
end select
Alternatively, in this simple case it is possible to do away with the select type
construct completely, and handle things in the select case
you already have.
Using sourced allocation with each constructor:
select case(layer_geometry_name)
case('rectangular')
allocate(constructor%layer_geometry, source=rectangular())
case('sphere')
allocate(constructor%layer_geometry, source=sphere())
end select
Or even
select case(layer_geometry_name)
case('rectangular')
constructor%layer_geometry = rectangular()
case('sphere')
constructor%layer_geometry = sphere()
end select
if you have the compiler support for intrinsic assignment to polymorphic variables (or by using defined assignment).