marray_compound.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: marray_compound.f90 #
5 !# #
6 !# Copyright (C) 2018 #
7 !# Tobias Illenseer <tillense@astrophysik.uni-kiel.de> #
8 !# #
9 !# This program is free software; you can redistribute it and/or modify #
10 !# it under the terms of the GNU General Public License as published by #
11 !# the Free Software Foundation; either version 2 of the License, or (at #
12 !# your option) any later version. #
13 !# #
14 !# This program is distributed in the hope that it will be useful, but #
15 !# WITHOUT ANY WARRANTY; without even the implied warranty of #
16 !# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or #
17 !# NON INFRINGEMENT. See the GNU General Public License for more #
18 !# details. #
19 !# #
20 !# You should have received a copy of the GNU General Public License #
21 !# along with this program; if not, write to the Free Software #
22 !# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
23 !# #
24 !#############################################################################
25 !----------------------------------------------------------------------------!
34 !----------------------------------------------------------------------------!
36  USE marray_base_mod
37  IMPLICIT NONE
38  !--------------------------------------------------------------------------!
39  PRIVATE
41  TYPE(marray_base), POINTER :: item => null()
42  TYPE(compound_item), POINTER :: next => null()
43  INTEGER :: extent,entry_num
44  END TYPE
46  TYPE, EXTENDS(marray_base) :: marray_compound
47  PRIVATE
48  TYPE(compound_item), POINTER :: list => null()
49  INTEGER :: num_entries = 0
50  CONTAINS
51  PROCEDURE :: assignpointers
52  PROCEDURE :: assignmarray_0
53  PROCEDURE :: appendmarray
54  PROCEDURE :: lastitem
55  PROCEDURE :: firstitem
56  PROCEDURE :: nextitem
57  PROCEDURE :: getitem
58  PROCEDURE :: appenditem
59  PROCEDURE :: destroy
60  END TYPE
61  INTERFACE marray_compound
62  MODULE PROCEDURE createmarray_compound
63  END INTERFACE
64  !--------------------------------------------------------------------------!
65  PUBLIC :: marray_compound
66 
67 CONTAINS
68 
78  FUNCTION createmarray_compound(n) RESULT(new_cp)
79  IMPLICIT NONE
80  !-------------------------------------------------------------------!
81  TYPE(marray_compound) :: new_cp
82  INTEGER, OPTIONAL, INTENT(IN) :: n
83  !-------------------------------------------------------------------!
84  IF (PRESENT(n)) THEN
85  IF (n.LE.0) THEN
86  print *,"ERROR in CreateMArray_compound: n should be larger than 0"
87  stop 1
88  ELSE
89  ! create empty mesh array of rank 2 with first dimension set to n
90  new_cp = marray_base(n,0)
91  new_cp%RANK = 2
92  END IF
93  ELSE
94  ! default is rank 1 mesh array
95  new_cp = marray_base(0)
96  new_cp%RANK = 1
97  END IF
98  END FUNCTION createmarray_compound
99 
101  SUBROUTINE assignpointers(this)
102  IMPLICIT NONE
103  !------------------------------------------------------------------------!
104  CLASS(marray_compound),INTENT(INOUT) :: this
105  !------------------------------------------------------------------------!
106  TYPE(compound_item), POINTER :: p
107  INTEGER :: m,n
108  !------------------------------------------------------------------------!
109  ! set the multi-dim. pointers of the compound
110  CALL this%marray_base%AssignPointers()
111  ! go through the list of items and set the 1D
112  ! and multi-dim. pointers for each item
113  p => this%FirstItem()
114  m = 0
115  n = 0
116  DO WHILE (ASSOCIATED(p))
117  m = m + n
118  n = p%extent
119  ! point to the 1D data segment in the new array
120  p%item%data1d(1:n) => this%data1d(m+1:m+n)
121  ! restore all multi-dim. pointers
122  CALL p%item%AssignPointers()
123  p => this%NextItem(p)
124  END DO
125  END SUBROUTINE assignpointers
126 
128  SUBROUTINE assignmarray_0(this,ma)
129  IMPLICIT NONE
130  !------------------------------------------------------------------------!
131  CLASS(marray_compound),INTENT(INOUT) :: this
132  CLASS(marray_base),INTENT(IN) :: ma
133  !------------------------------------------------------------------------!
134  TYPE(compound_item), POINTER :: p
135  !------------------------------------------------------------------------!
136  CALL this%marray_base%AssignMArray_0(ma)
137  SELECT TYPE(src => ma)
138  CLASS IS(marray_compound)
139  p => src%FirstItem()
140  IF (.NOT.ASSOCIATED(p).OR.src%num_entries.LT.1) THEN
141  this%num_entries = 0
142  NULLIFY(this%list)
143  ELSE
144  IF (.NOT.ASSOCIATED(this%list)) THEN
145  ! p is associated but this%list isn't
146  ! => generate new this%list with data from p, i.e. src
147  this%num_entries = 0
148  DO
149  CALL this%AppendItem(p%item)
150  IF (ASSOCIATED(p%next)) THEN
151  p => p%next
152  ELSE
153  EXIT
154  END IF
155  END DO
156  ! finally reassign all pointers
157  CALL this%AssignPointers()
158  ELSE
159  ! p and this%list are both associated
160  IF (src%num_entries.NE.this%num_entries) THEN
161  print *,"ERROR in marray_compound::AssignMArray_0: src%num_entries != dest%num_entries"
162  stop 1
163  END IF
164  END IF
165  END IF
166 ! IF (ASSOCIATED(src%data1d).AND.SIZE(src%data1d).GT.0) &
167 ! PRINT *,"marray_compound::AssignMArray_0 ma",src%data1d(LBOUND(src%data1d,1)),src%data1d(UBOUND(src%data1d,1))
168 ! IF (ASSOCIATED(this%data1d).AND.SIZE(this%data1d).GT.0) &
169 ! PRINT *,"marray_compound::AssignMArray_0 this",this%data1d(LBOUND(this%data1d,1)),this%data1d(UBOUND(this%data1d,1))
170  CLASS DEFAULT
171  ! do nothing, is this ok ???
172  END SELECT
173  END SUBROUTINE assignmarray_0
174 
175 
176  SUBROUTINE appendmarray(this,ma)
177  IMPLICIT NONE
178  !-------------------------------------------------------------------!
179  CLASS(marray_compound), INTENT(INOUT) :: this
180  TYPE(marray_base), POINTER :: ma
181  !-------------------------------------------------------------------!
182  INTEGER :: m,n,err
183  REAL, DIMENSION(:),POINTER,CONTIGUOUS :: data1d
184  !-------------------------------------------------------------------!
185  IF (.NOT.(ASSOCIATED(ma%data1d).AND.ASSOCIATED(this%data1d))) THEN
186  print *,"ERROR in marray_compound::AppendMArray: at least one of this%data1d,ma%data1d is not associated"
187  stop 1
188  ELSE
189  ! check the rank of the compound (either 1 or 2)
190  SELECT CASE(this%RANK)
191  CASE(1) ! rank 1 compound
192  this%DIMS(1) = this%DIMS(1) + ma%DIMS(1)*ma%DIMS(2) ! 1st dimension (excluding mesh
193  ! dimensions) is collapsed into one index; if ma is a scalar, then this is 1;
194  ! if ma is rank 1, then this is the vector component index;
195  ! if ma is rank 2, the two indices are collapsed into one index
196  CASE(2) ! rank 2 compound
197  ! check if the 1st dimension (excluding mesh dimensions) are the same for
198  ! both compound and mesh array added to the compound
199  IF (this%DIMS(1).NE.ma%DIMS(1)) THEN
200  print *,"ERROR in marray_compound::AppendMArray: this%dims(1) != ma%dims(1)"
201  stop 1
202  ELSE
203  ! this%DIMS(1) remains the same
204  this%DIMS(2) = this%DIMS(2) + ma%DIMS(2) ! extend the last dimension of the compound;
205  ! so far only scalars and vectors can be added to rank 2 compounds
206  END IF
207  CASE DEFAULT
208  ! this should not happen
209  END SELECT
210  IF (ASSOCIATED(this%data1d)) THEN
211  m = SIZE(this%data1d(:))
212  IF (m.EQ.0) DEALLOCATE(this%data1d) ! associated but size 0
213  ELSE
214  m = 0
215  END IF
216  IF (m.GT.0) THEN
217  n = SIZE(ma%data1d(:))
218  ! allocate new contiguous data block for old+new data and for meta data
219  ALLOCATE(data1d(m+n),stat=err)
220  IF (err.NE.0) THEN
221  print *,"ERROR in marray_compound::AppendMArray: memory allocation failed"
222  stop 1
223  END IF
224  ! copy the data, new data is appended to the old compound
225  data1d(1:m) = this%data1d(1:m)
226  data1d(m+1:m+n) = ma%data1d(1:n)
227  ! append ma to the list of items
228  CALL this%AppendItem(ma)
229  ! free old data
230  DEALLOCATE(ma%data1d,this%data1d)
231  ! set 1D compound pointer to the new data
232  this%data1d(1:) => data1d(1:)
233  ELSE ! i.e., .NOT.ASSOCIATED(this%data1d)
234  ! append ma to an empty compound => just assign the data pointer ...
235  this%data1d(1:) => ma%data1d(1:)
236  ! ... and append ma to the list of compound items
237  CALL this%AppendItem(ma)
238  END IF
239  ! go through the whole compound and restore all 1D and multi-dim. pointers
240  CALL this%AssignPointers()
241  ! print debug info
242 ! PRINT '(3(A,I2),I2)',"item no. ",this%num_entries, " appended to rank ",this%RANK," &
243 ! compound with dims ",this%DIMS(1:2)
244 ! PRINT '(A,I6,A,I2,A,2(I3))', " size", SIZE(this%data1d), &
245 ! " item%rank", ma%RANK, &
246 ! " item%dims", ma%DIMS(:)
247 ! SELECT CASE(this%RANK)
248 ! CASE(1)
249 ! PRINT '(A,4(I6))', " shape4d", SHAPE(this%data4d)
250 ! CASE(2)
251 ! PRINT '(A,5(I6))', " shape5d", SHAPE(this%data5d)
252 ! END SELECT
253  END IF
254  END SUBROUTINE appendmarray
255 
257  FUNCTION firstitem(this) RESULT(item)
258  IMPLICIT NONE
259  !-------------------------------------------------------------------!
260  CLASS(marray_compound) :: this
261  TYPE(compound_item), POINTER :: item
262  !-------------------------------------------------------------------!
263  item => this%list
264  END FUNCTION firstitem
265 
267  FUNCTION lastitem(this) RESULT(item)
268  IMPLICIT NONE
269  !-------------------------------------------------------------------!
270  CLASS(marray_compound) :: this
271  TYPE(compound_item), POINTER :: item
272  !-------------------------------------------------------------------!
273  item => this%list
274  IF (.NOT.ASSOCIATED(item)) RETURN
275  DO WHILE (ASSOCIATED(item%next))
276  item => item%next
277  END DO
278  END FUNCTION lastitem
279 
281  FUNCTION nextitem(this,item) RESULT(next)
282  IMPLICIT NONE
283  !-------------------------------------------------------------------!
284  CLASS(marray_compound) :: this
285  TYPE(compound_item), POINTER :: item,next
286  !-------------------------------------------------------------------!
287  IF (ASSOCIATED(item)) THEN
288  next => item%next
289  ELSE
290  next => null()
291  END IF
292  END FUNCTION nextitem
293 
295  FUNCTION getitem(this,list_entry) RESULT(ma)
296  IMPLICIT NONE
297  !-------------------------------------------------------------------!
298  CLASS(marray_compound) :: this
299  TYPE(compound_item), POINTER :: list_entry
300  TYPE(marray_base), POINTER :: ma
301  !-------------------------------------------------------------------!
302  ma => list_entry%item
303  END FUNCTION getitem
304 
306  SUBROUTINE appenditem(this,ma)
307  IMPLICIT NONE
308  !-------------------------------------------------------------------!
309  CLASS(marray_compound) :: this
310  TYPE(marray_base), POINTER :: ma
311  !-------------------------------------------------------------------!
312  TYPE(compound_item), POINTER :: p
313  INTEGER :: err
314  !-------------------------------------------------------------------!
315  IF (ASSOCIATED(ma).AND.ASSOCIATED(ma%data1d).AND.SIZE(ma%data1d).GT.0) THEN
316  p => this%LastItem()
317  IF (.NOT.ASSOCIATED(p)) THEN
318  ! list is empty => create it
319  ALLOCATE(this%list,stat=err)
320  CALL abortonerror()
321  p => this%list
322  this%num_entries = 1 ! first entry in the list
323  ELSE
324  ! list exists => create a new entry at the end
325  ALLOCATE(p%next,stat=err)
326  CALL abortonerror()
327  p => p%next
328  this%num_entries = this%num_entries + 1 ! one entry added
329  END IF
330  ! assign item pointer and store size of 1D data
331  p%item => ma
332  p%extent = SIZE(ma%data1d)
333  p%entry_num = this%num_entries
334  NULLIFY(p%next)
335  END IF
336 
337  CONTAINS
338  SUBROUTINE abortonerror()
339  IF (err.NE.0) THEN
340  print *,"ERROR in marray_compound::AppendItem: memory allocation failed"
341  stop 1
342  END IF
343  END SUBROUTINE
344  END SUBROUTINE appenditem
345 
347  SUBROUTINE destroy(this)
348  IMPLICIT NONE
349  !-------------------------------------------------------------------!
350  CLASS(marray_compound) :: this
351  !-------------------------------------------------------------------!
352  TYPE(compound_item), POINTER :: p,q
353  !-------------------------------------------------------------------!
354  ! free list memory
355  p => this%FirstItem()
356  DO WHILE (ASSOCIATED(p))
357  q => p
358  p => this%NextItem(p)
359  DEALLOCATE(q)
360  END DO
361  ! call deconstructor of the base class
362  CALL this%marray_base%Destroy()
363  END SUBROUTINE destroy
364 
365 END MODULE marray_compound_mod
subroutine appendmarray(this, ma)
subroutine assignpointers(this)
assign pointers of different shapes to the 1D data
subroutine abortonerror()
derived class for compound of mesh arrays
base class for mesh arrays
Definition: marray_base.f90:36
subroutine appenditem(this, ma)
append an item to the list of compound elements
type(marray_base) function, pointer getitem(this, list_entry)
get pointer to the mesh array from a given item
basic mesh array class
Definition: marray_base.f90:64
subroutine destroy(this)
deconstructor of the mesh array
type(compound_item) function, pointer firstitem(this)
get the first item from the list of compound elements
type(compound_item) function, pointer nextitem(this, item)
get the next item from the list of compound elements
type(marray_compound) function createmarray_compound(n)
constructor for compound of mesh arrays
type(compound_item) function, pointer lastitem(this)
get the last item from the list of compound elements
subroutine assignmarray_0(this, ma)
assigns one mesh array to another mesh array