ITM Grid Service Library: Fortran 90
|
00001 module itm_grid_structured 00002 00003 !> Service routines for accssing structured grids and associated data 00004 00005 use itm_types 00006 use itm_assert 00007 use itm_combinations 00008 00009 use itm_grid_common 00010 use itm_grid_object 00011 use itm_grid_access 00012 use itm_grid_subgrid 00013 use itm_grid_data 00014 use itm_grid_transform 00015 00016 implicit none 00017 00018 !> Definition of default subgrids 00019 integer, parameter :: GRID_STRUCT_SUBGRID_0D = 1 ! all 0d objects 00020 integer, parameter :: GRID_STRUCT_SUBGRID_1D = 2 ! all 1d objects 00021 integer, parameter :: GRID_STRUCT_SUBGRID_2D = 3 ! all 2d objects 00022 integer, parameter :: GRID_STRUCT_SUBGRID_3D = 4 ! all 3d objects 00023 integer, parameter :: GRID_STRUCT_SUBGRID_4D = 5 ! all 4d objects 00024 integer, parameter :: GRID_STRUCT_SUBGRID_5D = 6 ! all 5d objects 00025 integer, parameter :: GRID_STRUCT_SUBGRID_6D = 7 ! all 6d objects 00026 00027 ! Same as above, with human-readable names 00028 integer, parameter :: GRID_STRUCT_NODES = GRID_STRUCT_SUBGRID_0D ! all 0d objects 00029 integer, parameter :: GRID_STRUCT_EDGES = GRID_STRUCT_SUBGRID_1D ! all 1d objects 00030 integer, parameter :: GRID_STRUCT_FACES = GRID_STRUCT_SUBGRID_2D ! all 2d objects 00031 integer, parameter :: GRID_STRUCT_CELLS = GRID_STRUCT_SUBGRID_3D ! all 3d objects 00032 00033 00034 interface gridStructWriteData 00035 module procedure gridStructWriteData1d, gridStructWriteData2d , gridStructWriteData3d ,& 00036 & gridStructWriteData4d, gridStructWriteData5d, gridStructWriteData6d 00037 end interface 00038 00039 interface gridStructReadData 00040 module procedure gridStructReadData1d, gridStructReadData2d, gridStructReadData3d , & 00041 & gridStructReadData4d, gridStructReadData5d, gridStructReadData6d 00042 end interface 00043 00044 private computeMeasure 00045 00046 contains 00047 00048 !> Write a n-dimensional structured grid 00049 !> into a grid descriptor, as well as the default subgrids for objects of all dimensions. 00050 !> 00051 !> The dimension n of the grid is taken as size(coordtype). 00052 !> 00053 !> @param grid Grid descriptor to fill 00054 !> \param coordtype Dimension(n). Defines coordinate types / labels for the 00055 !> individual axes. See the 00056 !> constants defined in itm_grid.f90 (COORDTYPE_*) 00057 !> \param gshape Dimension(n). Shape of the grid. In dimension i the grid 00058 !> has shape(i) grid points. 00059 !> @param x Dimension( maxval( gshape(n) ), n ). 00060 !> Grid node coordinates in the individual dimensions. 00061 !> The node positions in space i are given by 00062 !> x( 1 : gshape( i ), id ). 00063 !> @param createSubgrids Optional flag controlling whether default subgrids 00064 !> are created. Default is .true. 00065 !> @param periodicSpaces Optional integer array containing the indices 00066 !> of the coordinate directions that are periodic. This will 00067 !> result in the last node in these coordinate directions to 00068 !> be connected to the first node by an edge. Note that if periodic 00069 !> spaces are present, no metric information is computed. 00070 !> @param uid A unique identifier number for the 00071 00072 !> @see gridSetupStructuredSep 00073 subroutine gridSetupStructured( grid, coordtype, gshape, x, id, createSubgrids, periodicSpaces, uid, computeMeasures ) 00074 type(type_complexgrid), intent(out) :: grid 00075 integer, dimension(:), intent(in) :: coordtype 00076 integer, dimension(size(coordtype)), intent(in) :: gshape 00077 real(R8), dimension(:, :), intent(in) :: x 00078 character(*), intent(in), optional :: id 00079 logical, intent(in), optional :: createSubgrids 00080 integer, intent(in), optional :: periodicSpaces(:) 00081 integer, intent(in), optional :: uid 00082 logical, intent(in), optional :: computeMeasures 00083 00084 ! internal 00085 integer :: idim, ndim, iSg, iObj 00086 type(GridObject) :: obj 00087 integer, allocatable :: classes(:,:) 00088 logical :: lCreateSubgrids = .true., periodic 00089 logical :: lComputeMeasures = .true. 00090 00091 if (present(createSubgrids)) lCreateSubgrids = createSubgrids 00092 if (present(computeMeasures)) lcomputeMeasures = computeMeasures 00093 00094 call assert( size( coordtype ) == size( gshape ), & 00095 & "gridWriteStructured: size of coordtype and gshape don't match" ) 00096 call assert( maxval( shape( x ) ) == maxval( gshape ), & 00097 & "gridWriteStructured: shape of x seems to be inconsistent with gshape" ) 00098 00099 if (present(id)) then 00100 allocate( grid%id(1) ) 00101 grid%id(1) = id 00102 end if 00103 00104 ndim = size(coordtype) 00105 allocate( grid % spaces(ndim) ) 00106 00107 ! ... fill in the grid data 00108 do idim = 1, ndim 00109 periodic = .false. 00110 if (present(periodicSpaces)) then 00111 periodic = any(periodicSpaces == idim) 00112 end if 00113 call gridSetupStruct1dSpace( grid % spaces(idim), & 00114 & coordtype( idim ), x( 1 : gshape(idim) ,idim ), periodic ) 00115 end do 00116 00117 ! Create subgrids & store metric information for implicitly defined objects 00118 if (lCreateSubgrids) then 00119 00120 call gridCreateDefaultSubGrids(grid, id) 00121 00122 ! ...also set up measures for subgrids with objects of dimension > 1 00123 ! ...but only if there are no periodic spaces 00124 if (lComputeMeasures .and. .not. present(periodicSpaces) ) then 00125 00126 allocate(grid%metric%measure(ndim - 1)) 00127 00128 do idim = 0, ndim 00129 iSg = idim + 1 00130 ! Store measures for implicitly defined objects (dim > 1) 00131 if (idim > 1) then 00132 grid%metric%measure(idim-1)%subgrid = iSg 00133 allocate( grid%metric%measure(idim-1)%scalar( gridSubGridSize(grid%subgrids(iSg)) ) ) 00134 ! loop over all objects in subgrid 00135 do iObj = 1, gridSubGridSize( grid%subgrids(iSg) ) 00136 obj = subGridGetObject( grid%subgrids(iSg), iObj ) 00137 grid%metric%measure(idim-1)%scalar(iObj) = computeMeasure( grid, obj ) 00138 end do 00139 end if 00140 end do 00141 end if 00142 00143 end if 00144 00145 end subroutine gridSetupStructured 00146 00147 ! Compute measure (length, area, volume, ...) for an object in a structured grid 00148 real(R8) function computeMeasure( grid, obj ) result( m ) 00149 type(type_complexgrid), intent(in) :: grid 00150 type(GridObject), intent(in) :: obj 00151 00152 ! internal 00153 integer :: iSp 00154 00155 call assert( objectDim(obj) > 0 ) 00156 00157 m = 1.0_R8 00158 do iSp = 1,gridNSpace( grid ) 00159 if (obj%cls(iSp) == 1) then 00160 ! TODO: add support for multiple geometries 00161 m = m * grid%spaces(iSp)%objects(2)%measure(obj%ind(iSp),1) 00162 end if 00163 end do 00164 end function computeMeasure 00165 00166 !> Write a n-dimensional structured grid into a grid descriptor (alternate version 00167 !> with separate dimension vectors) 00168 00169 !> Alternate wrapper for gridSetupStructured, which makes it easier 00170 !> to give the node positions as individual arrays 00171 00172 !> @see gridSetupStructured 00173 subroutine gridSetupStructuredSep( grid, ndim, c1, x1, c2, x2, c3, x3, c4, x4, c5, x5, c6, x6, id, createSubgrids, periodicSpaces, uid, computeMeasures ) 00174 type(type_complexgrid), intent(out) :: grid 00175 integer, intent(in) :: ndim 00176 real(R8), intent(in), dimension(:) :: x1 ! have to have at least one dimension 00177 integer, intent(in) :: c1 ! have to have at least one dimension 00178 real(R8), intent(in), dimension(:), optional :: x2, x3, x4, x5, x6 00179 integer, intent(in),optional :: c2, c3, c4, c5, c6 00180 character(*), intent(in), optional :: id 00181 logical, intent(in), optional :: createSubgrids 00182 integer, intent(in), optional :: periodicSpaces(:) 00183 integer, intent(in), optional :: uid 00184 logical, intent(in), optional :: computeMeasures 00185 00186 00187 ! internal 00188 integer :: lndim, nmax, i 00189 real(R8), dimension(:,:), allocatable :: x 00190 integer, dimension(:), allocatable :: gshape, coordtype 00191 00192 00193 lndim = 1 00194 nmax = size( x1 ) 00195 00196 if ( present( x2 ) ) then 00197 lndim = 2 00198 nmax = max( nmax, size( x2 ) ) 00199 call assert( present( c2 ), "gridSetupStructuredSep: x2 given, but not c2" ) 00200 end if 00201 if ( present( x3 ) ) then 00202 lndim = 3 00203 nmax = max( nmax, size( x3 ) ) 00204 call assert( present( c3 ), "gridSetupStructuredSep: x3 given, but not c3" ) 00205 end if 00206 if ( present( x4 ) ) then 00207 lndim = 4 00208 nmax = max( nmax, size( x4 ) ) 00209 call assert( present( c4 ), "gridSetupStructuredSep: x4 given, but not c4" ) 00210 end if 00211 if ( present( x5 ) ) then 00212 lndim = 5 00213 nmax = max( nmax, size( x5 ) ) 00214 call assert( present( c5 ), "gridSetupStructuredSep: x5 given, but not c5" ) 00215 end if 00216 if ( present( x6 ) ) then 00217 lndim = 6 00218 nmax = max( nmax, size( x6 ) ) 00219 call assert( present( c6 ), "gridSetupStructuredSep: x6 given, but not c6" ) 00220 end if 00221 00222 call assert( lndim == ndim, "gridWriteStructured: error in call, ndim does not match number of arguments" ) 00223 00224 ! allocate and assemble temporary data structure 00225 allocate( x( nmax, ndim ) ) 00226 allocate( gshape( ndim ) ) 00227 allocate( coordtype( ndim ) ) 00228 00229 do i = 1, ndim 00230 00231 select case( i ) 00232 case( 1 ) 00233 x( 1:size( x1 ), 1 ) = x1 00234 gshape(1) = size( x1 ) 00235 coordtype(1) = c1 00236 case( 2 ) 00237 x( 1:size( x2 ), 2 ) = x2 00238 gshape(2) = size( x2 ) 00239 coordtype(2) = c2 00240 case( 3 ) 00241 x( 1:size( x3 ), 3 ) = x3 00242 gshape(3) = size( x3 ) 00243 coordtype(3) = c3 00244 case( 4 ) 00245 x( 1:size( x4 ), 4 ) = x4 00246 gshape(4) = size( x4 ) 00247 coordtype(4) = c4 00248 case( 5 ) 00249 x( 1:size( x5 ), 5 ) = x5 00250 gshape(5) = size( x5 ) 00251 coordtype(5) = c5 00252 case( 6 ) 00253 x( 1:size( x6 ), 6 ) = x6 00254 gshape(6) = size( x6 ) 00255 coordtype(6) = c6 00256 end select 00257 00258 end do 00259 00260 ! write 00261 call gridSetupStructured( grid, coordtype, gshape, x, id, createSubgrids, periodicSpaces, uid, computeMeasures ) 00262 00263 end subroutine gridSetupStructuredSep 00264 00265 00266 !> Set up a 1d structured space. 00267 !> 00268 !> Helper routine used by gridSetupStructured. Sets up a space descriptor for the case 00269 !> of a simple 1d structured grid with standard connectivity 00270 00271 subroutine gridSetupStruct1dSpace( space, coordtype, nodes, periodic ) 00272 type(type_complexgrid_space), intent(inout) :: space !> The space descriptor to fill 00273 integer, intent(in) :: coordtype !> The coordinate type of the space 00274 real(R8), intent(in), dimension(:) :: nodes !> The node positions in the space (assumed to be in increasing order) 00275 logical, intent(in), optional :: periodic 00276 00277 ! internal 00278 integer, parameter :: NDIM = 1 ! this is a 1d grid 00279 00280 logical :: lperiodic = .false. 00281 integer :: i, nobjects, iNb 00282 00283 if (present(periodic)) lperiodic = periodic 00284 00285 ! Set coordinate types 00286 ! (dimension of space = NDIM = size( coordtype ) 00287 allocate( space % coordtype(NDIM, 1) ) 00288 space % coordtype(:,1) = (/ coordtype /) 00289 00290 ! Allocate object definition arrays 00291 allocate( space % objects(NDIM + 1) ) 00292 00293 ! Set up node information 00294 ! Geometry: normal geometry representation, third dimension unused. 00295 ! TODO: support multiple geometries 00296 allocate( space % objects(1) % geo(size(nodes), NDIM, 1, 1) ) 00297 space % objects(1) % geo(:, 1, 1, 1) = nodes 00298 ! space % nodes % xpoints, altgeo, alias: unused for this grid 00299 00300 ! Allocate arrays for 1d-objects (edges) 00301 nobjects = size(nodes) - 1 00302 ! In the periodic case we have one additional edge 00303 if (lperiodic) nobjects = nobjects + 1 00304 ! Boundary array (2 boundaries per object) 00305 allocate( space % objects(2) % boundary( nobjects, 2 ) ) 00306 ! connectivity array (2 boundaries per object, maximum of 1 neighbour per object) 00307 allocate( space % objects(2) % neighbour( nobjects, 2, 1 ) ) 00308 00309 ! Additional object geometry information (space % objects % geo) currently unused for this grid 00310 00311 ! Fill in object definitions (i.e. what objects compose an object) 00312 ! First set all to undefined 00313 space % objects(2) % boundary = GRID_UNDEFINED 00314 ! Now fill in the nodes defining the edges 00315 do i = 1, nobjects 00316 ! left point of edge 00317 space % objects(2) % boundary( i, 1 ) = i 00318 ! right point of edge 00319 space % objects(2) % boundary( i, 2 ) = i + 1 00320 ! wrap around right edge if exceed node count in periodic case 00321 if (space % objects(2) % boundary( i, 2 ) > size(nodes)) then 00322 space % objects(2) % boundary( i, 2 ) = 1 00323 end if 00324 end do 00325 00326 ! Fill in connectivity information 00327 ! first set all to undefined 00328 space%objects(2)%neighbour = GRID_UNDEFINED 00329 00330 ! first edge: 00331 00332 if (.not. lperiodic) then 00333 ! standard case: no left neighbour 00334 space%objects(2)%neighbour( 1, 1, 1 ) = GRID_UNDEFINED 00335 else 00336 ! periodic case: left neighbour is last edge in space 00337 space%objects(2)%neighbour( 1, 1, 1 ) = nobjects 00338 end if 00339 space%objects(2)%neighbour( 1, 2, 1 ) = 2 00340 00341 ! edges: left + right neighbour 00342 do i = 1, nobjects 00343 ! Left neighbour 00344 iNb = i - 1 00345 if ( iNb < 1 ) then 00346 iNb = GRID_UNDEFINED 00347 if (lperiodic) iNb = nobjects 00348 end if 00349 space%objects(2)%neighbour( i, 1, 1 ) =iNb 00350 00351 ! Right neighbour 00352 iNb = i + 1 00353 if ( iNb > nobjects ) then 00354 iNb = GRID_UNDEFINED 00355 if (lperiodic) iNb = 1 00356 end if 00357 space%objects(2)%neighbour( i, 2, 1 ) = iNb 00358 end do 00359 00360 ! Measures: store length of edges - only in non-periodic case 00361 if (.not. lperiodic) then 00362 allocate(space%objects(2)%measure( nobjects, 1 )) 00363 ! TODO: support multiple geometries 00364 space%objects(2)%measure(:,1) = nodes(2:ubound(nodes,1)) - nodes(1:ubound(nodes,1)-1) 00365 end if 00366 00367 end subroutine gridSetupStruct1dSpace 00368 00369 00370 !> Test whether the given grid descriptor contains a structured 00371 !> grid in the sense of this service module. 00372 logical function gridIsStructured( grid ) result ( isStruct ) 00373 type(type_complexgrid), intent(in) :: grid 00374 00375 ! internal 00376 integer :: is 00377 00378 isStruct = .true. 00379 00380 ! Consists of 1d spaces? 00381 !!$ do is = 1, size( grid % spaces ) 00382 !!$ if ( gridSpaceNDim( grid%spaces(is) ) /= 1 ) isStruct = .false. 00383 !!$ end do 00384 isStruct = all(gridSpaceNDims(grid) == 1) 00385 00386 00387 ! 1d spaces have default simple connectivity? 00388 ! TODO: implement connectivity test 00389 00390 end function gridIsStructured 00391 00392 00393 !> Return the axes description of a structured grid. Essentially the equivalent read routine to gridSetupStructured. 00394 !> 00395 !> @param grid The grid descriptor to read from 00396 !> @param coordtype The coordinate types of the individual axes/spaces 00397 !> @param gshape Number of grid nodes on the individual axes/spaces 00398 !> @param x The position of the grid nodes. x(i,s) is the position of node i in space s. 00399 !> All nodes in space s are given by x( 1:gshape(s), s ) 00400 !> @see gridSetupStructured 00401 subroutine gridStructGetAxes( grid, coordtype, gshape, x ) 00402 type(type_complexgrid), intent(in) :: grid 00403 integer, dimension(:), allocatable, intent(out) :: coordtype, gshape 00404 real(R8), dimension(:,:), allocatable, intent(out) :: x 00405 00406 ! internal 00407 integer :: id, ndim 00408 00409 call assert( gridIsStructured( grid ), "gridStructGetAxes: not a structured grid" ) 00410 00411 ndim = gridNDim( grid ) 00412 00413 allocate( coordtype( ndim ) ) 00414 allocate( gshape( ndim ) ) 00415 00416 coordtype = gridCoordTypes( grid ) 00417 do id = 1, ndim 00418 gshape( id ) = gridSpaceNNodes( grid%spaces(id) ) 00419 end do 00420 00421 allocate( x( 1 : maxval( gshape ), ndim ) ) 00422 00423 x = 0.0_R8 00424 do id = 1, ndim 00425 ! TODO: support multiple geometries 00426 x( 1 : gshape( id ), id ) = grid % spaces( id ) % objects(1) % geo(:, 1, 1, 1) 00427 end do 00428 00429 end subroutine gridStructGetAxes 00430 00431 00432 !> Return the shape (number of points in every dimension) of a structured grid. 00433 !> 00434 !> @param grid The grid descriptor to read from 00435 !> @param gshape Number of grid nodes on the individual axes/spaces 00436 !> @see gridSetupStructured 00437 subroutine gridStructGetShape( grid, gshape ) 00438 type(type_complexgrid), intent(in) :: grid 00439 integer, dimension(:), allocatable, intent(out) :: gshape 00440 00441 ! internal 00442 integer :: id, ndim 00443 00444 call assert( gridIsStructured( grid ), "gridStructGetShape: not a structured grid" ) 00445 00446 ndim = gridNDim( grid ) 00447 00448 allocate( gshape( ndim ) ) 00449 00450 do id = 1, ndim 00451 gshape( id ) = gridSpaceNNodes( grid%spaces(id) ) 00452 end do 00453 00454 end subroutine gridStructGetShape 00455 00456 00457 ! Below here are some service routines to assemble object descriptors for structured grids 00458 00459 !> Return an object descriptor for a cell in an n-dimensional 00460 !> structured grid for the canonical coordinates given in index. 00461 !> 00462 !> @param Index of the cell (=indices of the composing faces) 00463 !> @return The object descriptor 00464 00465 function gridStructGetCell( index ) result( object ) 00466 type(GridObject) :: object 00467 integer, dimension(:), intent(in) :: index 00468 00469 allocate( object % cls( size( index ) ) ) 00470 allocate( object % ind( size( index ) ) ) 00471 00472 object % cls = 1 00473 object % ind = index 00474 00475 end function gridStructGetCell 00476 00477 !> Return a descriptor for a grid node with the given index. 00478 !> 00479 !> @param index Index of the grid node 00480 !> @return The object descriptor 00481 00482 function gridStructGetNode( index ) result( object ) 00483 type(GridObject) :: object 00484 integer, dimension(:), intent(in) :: index 00485 00486 allocate( object % cls( size( index ) ) ) 00487 allocate( object % ind( size( index ) ) ) 00488 00489 object % cls = 0 00490 object % ind = index 00491 00492 end function gridStructGetNode 00493 00494 !> Return a descriptor for an (one-dimensional) edge, the start 00495 !> point of which is given by node with the given index and which 00496 !> extends to the next point in the increasing coordinate direction 00497 !> of dimension dim. 00498 !> 00499 !> @param index Index of starting node of the edge 00500 !> @param dim Index of the dimension along which the edge is aligned 00501 !> @return The object descriptor 00502 00503 function gridStructGetEdge( index, dim ) result( object ) 00504 type(GridObject) :: object 00505 integer, dimension(:), intent(in) :: index 00506 integer, intent(in) :: dim 00507 00508 allocate( object % cls( size( index ) ) ) 00509 allocate( object % ind( size( index ) ) ) 00510 00511 object % cls = 0 00512 object % cls( dim ) = 1 00513 object % ind = index 00514 00515 end function gridStructGetEdge 00516 00517 !> Return a descriptor for a (two-dimensional) face. The lower-right 00518 !> node of the face is given by index, and the face extends along the 00519 !> two coordinate directions given in dims. 00520 !> 00521 !> @param index Index of lower-right node. 00522 !> @param dims The dimensions along which the face extends 00523 !> @return The object descriptor 00524 00525 function gridStructGetFace( index, dims ) result( object ) 00526 type(GridObject) :: object 00527 integer, dimension(:), intent(in) :: index 00528 integer, intent(in), dimension(2) :: dims 00529 00530 allocate( object % cls( size( index ) ) ) 00531 allocate( object % ind( size( index ) ) ) 00532 00533 object % cls = 0 00534 object % cls( dims(1) ) = 1 00535 object % cls( dims(2) ) = 1 00536 object % ind = index 00537 00538 end function gridStructGetFace 00539 00540 ! Note: in the gridStructWrite routines, grid is currently unused but might be used in the future 00541 00542 subroutine gridStructWriteData1d( grid, cpofield, subgrid, data ) 00543 type(type_complexgrid), intent(in) :: grid 00544 integer, intent(in) :: subgrid 00545 type(type_complexgrid_scalar), intent(inout) :: cpofield 00546 real(R8), dimension(:), intent(in) :: data 00547 00548 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00549 end subroutine gridStructWriteData1d 00550 00551 subroutine gridStructWriteData2d( grid, cpofield, subgrid, data ) 00552 type(type_complexgrid), intent(in) :: grid 00553 integer, intent(in) :: subgrid 00554 type(type_complexgrid_scalar), intent(inout) :: cpofield 00555 real(R8), dimension(:,:), intent(in) :: data 00556 00557 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00558 end subroutine gridStructWriteData2d 00559 00560 subroutine gridStructWriteData3d( grid, cpofield, subgrid, data ) 00561 type(type_complexgrid), intent(in) :: grid 00562 integer, intent(in) :: subgrid 00563 type(type_complexgrid_scalar), intent(inout) :: cpofield 00564 real(R8), dimension(:,:,:), intent(in) :: data 00565 00566 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00567 end subroutine gridStructWriteData3d 00568 00569 subroutine gridStructWriteData4d( grid, cpofield, subgrid, data ) 00570 type(type_complexgrid), intent(in) :: grid 00571 integer, intent(in) :: subgrid 00572 type(type_complexgrid_scalar), intent(inout) :: cpofield 00573 real(R8), dimension(:,:,:,:), intent(in) :: data 00574 00575 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00576 end subroutine gridStructWriteData4d 00577 00578 subroutine gridStructWriteData5d( grid, cpofield, subgrid, data ) 00579 type(type_complexgrid), intent(in) :: grid 00580 integer, intent(in) :: subgrid 00581 type(type_complexgrid_scalar), intent(inout) :: cpofield 00582 real(R8), dimension(:,:,:,:,:), intent(in) :: data 00583 00584 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00585 end subroutine gridStructWriteData5d 00586 00587 subroutine gridStructWriteData6d( grid, cpofield, subgrid, data ) 00588 type(type_complexgrid), intent(in) :: grid 00589 integer, intent(in) :: subgrid 00590 type(type_complexgrid_scalar), intent(inout) :: cpofield 00591 real(R8), dimension(:,:,:,:,:,:), intent(in) :: data 00592 00593 call gridWriteDataScalar( cpofield, subgrid, reshape(data, (/ size( data ) /)) ) 00594 end subroutine gridStructWriteData6d 00595 00596 00597 00598 !> Body of the data read routine for data arrays with arbitrary rank 00599 subroutine gridStructReadDataBody( grid, cpofield, subgrid, gshape ) 00600 type(type_complexgrid), intent(in) :: grid 00601 integer, intent(in) :: subgrid 00602 type(type_complexgrid_scalar), intent(in) :: cpofield 00603 integer, dimension(:), intent(in) :: gshape 00604 00605 ! internal 00606 integer :: ndata, i 00607 00608 ! check whether inputs make basic sense 00609 call assert( gridIsStructured( grid ), "gridStructReadDataBody: grid not structured" ) 00610 call assert( cpofield%subgrid == subgrid, "gridStructReadDataBody: subgrid does not match" ) 00611 call assert( associated( cpofield%scalar ), "gridStructReadDataBody: cpofield%scalar not associated" ) 00612 00613 ndata = product( gshape ) 00614 call assert( ndata == gridSubGridSize(grid%subgrids(subgrid)), & 00615 & "gridStructReadDataBody: data size does not match subgrid size" ) 00616 00617 ! Actual reading the data is deferred to the rank-specific routines, to avoid unnecessary copying 00618 00619 end subroutine gridStructReadDataBody 00620 00621 ! FIXME: cpofield -> cpodata 00622 subroutine gridStructReadData1d( grid, cpofield, subgrid, data ) 00623 type(type_complexgrid), intent(in) :: grid 00624 integer, intent(in) :: subgrid 00625 type(type_complexgrid_scalar), intent(in) :: cpofield 00626 real(R8), dimension(:), intent(out) :: data 00627 00628 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00629 data = reshape( cpofield%scalar, shape(data) ) 00630 end subroutine gridStructReadData1d 00631 00632 subroutine gridStructReadData2d( grid, cpofield, subgrid, data ) 00633 type(type_complexgrid), intent(in) :: grid 00634 integer, intent(in) :: subgrid 00635 type(type_complexgrid_scalar), intent(in) :: cpofield 00636 real(R8), dimension(:,:), intent(out) :: data 00637 00638 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00639 data = reshape( cpofield%scalar, shape(data) ) 00640 end subroutine gridStructReadData2d 00641 00642 subroutine gridStructReadData3d( grid, cpofield, subgrid, data ) 00643 type(type_complexgrid), intent(in) :: grid 00644 integer, intent(in) :: subgrid 00645 type(type_complexgrid_scalar), intent(in) :: cpofield 00646 real(R8), dimension(:,:,:), intent(out) :: data 00647 00648 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00649 data = reshape( cpofield%scalar, shape(data) ) 00650 end subroutine gridStructReadData3d 00651 00652 subroutine gridStructReadData4d( grid, cpofield, subgrid, data ) 00653 type(type_complexgrid), intent(in) :: grid 00654 integer, intent(in) :: subgrid 00655 type(type_complexgrid_scalar), intent(in) :: cpofield 00656 real(R8), dimension(:,:,:,:), intent(out) :: data 00657 00658 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00659 data = reshape( cpofield%scalar, shape(data) ) 00660 end subroutine gridStructReadData4d 00661 00662 subroutine gridStructReadData5d( grid, cpofield, subgrid, data ) 00663 type(type_complexgrid), intent(in) :: grid 00664 integer, intent(in) :: subgrid 00665 type(type_complexgrid_scalar), intent(in) :: cpofield 00666 real(R8), dimension(:,:,:,:,:), intent(out) :: data 00667 00668 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00669 data = reshape( cpofield%scalar, shape(data) ) 00670 end subroutine gridStructReadData5d 00671 00672 subroutine gridStructReadData6d( grid, cpofield, subgrid, data ) 00673 type(type_complexgrid), intent(in) :: grid 00674 integer, intent(in) :: subgrid 00675 type(type_complexgrid_scalar), intent(in) :: cpofield 00676 real(R8), dimension(:,:,:,:,:,:), intent(out) :: data 00677 00678 call gridStructReadDataBody( grid, cpofield, subgrid, shape(data) ) 00679 data = reshape( cpofield%scalar, shape(data) ) 00680 end subroutine gridStructReadData6d 00681 00682 00683 ! Routines for structured curvilinear grids 00684 00685 subroutine gridSetupStructuredCurvilinear3d( grid, coordtype, x, y, z, id, createSubgrids) 00686 type(type_complexgrid), intent(out) :: grid 00687 integer, dimension(3), intent(in) :: coordtype 00688 real(R8), dimension(:,:,:), intent(in) :: x, y ,z 00689 character(*), intent(in), optional :: id 00690 logical, intent(in), optional :: createSubgrids 00691 00692 ! internal 00693 type(type_complexgrid) :: structgrid 00694 !real(R8), dimension(maxval(shape(x)), 3) :: structx 00695 real(R8), dimension(:, :), allocatable :: structx 00696 integer :: ix, iy, iz, iNode 00697 logical :: lCreateSubgrids = .true., periodic 00698 00699 if (present(createSubgrids)) lCreateSubgrids = createSubgrids 00700 00701 !write (*,*) shape(x) 00702 !write (*,*) maxval(shape(x)) 00703 allocate( structx(maxval(shape(x)), 3) ) 00704 00705 ! First set up a 3d structured grid 00706 call gridSetupStructured( structgrid, coordtype, shape(x), structx, id, createSubgrids=.true. ) 00707 00708 ! transform it into an equivalent grid with one space 00709 call transformGridToSingleSpace( structgrid, grid ) 00710 00711 ! Now set the node positions properly. The nodes are in "fortran order", i.e. lowest dimension 00712 ! iterating the fastest 00713 iNode = 0 00714 do iz = 1, size(x, 3) 00715 do iy = 1, size(x, 2) 00716 do ix = 1, size(x, 1) 00717 iNode = iNode + 1 00718 ! TODO: support multiple geometry types 00719 grid%spaces(1)%objects(1)%geo(iNode, 1, 1, 1) = x(ix, iy, iz) 00720 grid%spaces(1)%objects(1)%geo(iNode, 2, 1, 1) = y(ix, iy, iz) 00721 grid%spaces(1)%objects(1)%geo(iNode, 3, 1, 1) = z(ix, iy, iz) 00722 end do 00723 end do 00724 end do 00725 00726 ! Create subgrids 00727 if (lCreateSubgrids) then 00728 call gridCreateDefaultSubGrids(grid, id) 00729 ! TODO: what about the metrics? 00730 end if 00731 00732 end subroutine gridSetupStructuredCurvilinear3d 00733 00734 end module itm_grid_structured