I have a Structure of arrays using the declared type in Fortran
eg
type t_data
integer :: N
real, allocatable :: x(:)
real, allocatable :: z(:)
real, allocatable :: y(:)
contains
procedure :: copy
procedure :: SWAP
procedure :: copy_element
end type
! constructor
interface t_data
module procedure constructor
end interface
contains
subroutine copy(this, old)
class(t_data), intent(inout) :: this
type(t_data), intent(in) :: old
do i = 1, old% N
this% x(i) = old% x(i)
etc ..
end do
end subroutine
subroutine copy(this, old)
class(t_data), intent(inout) :: this
type(t_data), intent(in) :: old
do i = 1, old% N
this% x(i) = old% x(i)
etc ..
end do
end subroutine
function constructor(size_)
integer, intent(in) :: size_
type(t_data), :: constructor
allocate(constructor% x(size_))
allocate(constructor% y(size_) )
! etc
end function
subroutine swap(this, from, i1,i2)
class(t_particle_data), intent(inout) :: this
type(t_particle_data), intent(in) :: from
integer, intent(in) :: i1, i2
this% x(i1) = from% x(i2)
! etc
end subroutine
These are a set of examples of procedures that need to do same operations on all arrays of the declared type t_data
. My question is how to make it more maintainable to tackle the situation when we for example later want to add a new component to the declared type. Currently, when I add a new array to my t_data
, I need to go through all those procedures, constructors, deconstructors, and add the component.
I am asking if there is a way to make this more easier.
MY APPLICATION
Please note that these data type is used for particle simulation. Initially I allocate t_data with a large number. However, later during my simulation I might need more particles. Hence, I allocate a new t_data with more memory and copy over the old t_data
up to its old size.
subroutine NEW_ALLOC(new, old)
type(t_data), intent(out) :: new
type(t_data), intent(inout) :: old
nsize = old% N * 2 ! allocate twice the old size
new = T_DATA(nsize)
call new% copy(old)
!DEALLCOte OLD
end subroutine
Does anybody has/is it possible to make this in a more clever way. I do not mind mixing this with C/C++?
My question is how to make it more maintainable to tackle the situation when we for example later want to add a new component to the declared type.
Here's how I would tackle the situation, and how many Fortran programmers have tackled the situation. I don't see the compelling need to have a derived type containing 3 arrays of coordinates, and approaching the problem that way does, as OP fears, require that adding another dimension to the problem requires code revision, such as adding a member array real, allocatable :: w(:)
to t_data
and recoding all the type-bound procedures operating on the type.
So drop that approach in favour of
TYPE t_data
REAL, DIMENSION(:,:), ALLOCATABLE :: elements
END TYPE t_data
let's have a couple of instances for exposition
TYPE(t_data) :: t1 ,t2, t3
and we can allocate the elements
member of any of these this way
ALLOCATE(t1%elements(3,10))
which could just as easily be
ALLOCATE(t1%elements(6,100))
or whatever you wish. This has the advantage over the original derived type design that the dimensions of elements
can be determined at run-time. It also makes it difficult to have different lengths for each of the coordinate arrays.
Now, copying t1
is as simple as
t2 = t1
Modern Fortran even takes care of automatically allocating the elements
of t2
. So I don't see any need for defining procedures for copying whole instances of t_data
. As for swapping data around, slicing and dicing, this is as simple as
t2%elements(1,:) = t1%elements(2,:)
even
t2%elements(1,:) = t1%elements(1,6:1:-1)
or
t2%elements(1,:) = t1%elements(1,[1,3,5,2,4,6])
It should be obvious how to wrap these into a swap
routine. But if not, ask another question.
Next, to the point about needing to allocate more space for elements during execution. First a temporary array
REAL, DIMENSION(:,:), ALLOCATABLE :: temp
then a little code like this, to double the size of elements
.
ALLOCATE(temp(3,2*n))
temp(:,1:n) = t2%elements(:,1:n)
CALL MOVE_ALLOC(to=t2%elements,from=temp)
Again, you might care to wrap this into a procedure and if you need help doing that, ask for it.
Finally, the lesson of all this is not to share how I would program the problem, but to share the idea to program in Fortran .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.