forked from openmc-dev/openmc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeometry_header.F90
322 lines (263 loc) · 12.9 KB
/
geometry_header.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
module geometry_header
use constants, only: HALF, TWO, THREE, INFINITY
implicit none
!===============================================================================
! UNIVERSE defines a geometry that fills all phase space
!===============================================================================
type Universe
integer :: id ! Unique ID
integer :: type ! Type
integer :: n_cells ! # of cells within
integer, allocatable :: cells(:) ! List of cells within
real(8) :: x0 ! Translation in x-coordinate
real(8) :: y0 ! Translation in y-coordinate
real(8) :: z0 ! Translation in z-coordinate
end type Universe
!===============================================================================
! LATTICE abstract type for ordered array of universes.
!===============================================================================
type, abstract :: Lattice
integer :: id ! Universe number for lattice
character(len=104) :: name = "" ! User-defined name
real(8), allocatable :: pitch(:) ! Pitch along each axis
integer, allocatable :: universes(:,:,:) ! Specified universes
integer :: outside ! Material to fill area outside
integer :: outer ! universe to tile outside the lat
logical :: is_3d ! Lattice has cells on z axis
integer, allocatable :: offset(:,:,:,:) ! Distribcell offsets
contains
procedure(lattice_are_valid_indices_), deferred :: are_valid_indices
procedure(lattice_get_indices_), deferred :: get_indices
procedure(lattice_get_local_xyz_), deferred :: get_local_xyz
end type Lattice
abstract interface
!===============================================================================
! ARE_VALID_INDICES returns .true. if the given lattice indices fit within the
! bounds of the lattice. Returns false otherwise.
function lattice_are_valid_indices_(this, i_xyz) result(is_valid)
import Lattice
class(Lattice), intent(in) :: this
integer, intent(in) :: i_xyz(3)
logical :: is_valid
end function lattice_are_valid_indices_
!===============================================================================
! GET_INDICES returns the indices in a lattice for the given global xyz.
function lattice_get_indices_(this, global_xyz) result(i_xyz)
import Lattice
class(Lattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer :: i_xyz(3)
end function lattice_get_indices_
!===============================================================================
! GET_LOCAL_XYZ returns the translated local version of the given global xyz.
function lattice_get_local_xyz_(this, global_xyz, i_xyz) result(local_xyz)
import Lattice
class(Lattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer, intent(in) :: i_xyz(3)
real(8) :: local_xyz(3)
end function lattice_get_local_xyz_
end interface
!===============================================================================
! RECTLATTICE extends LATTICE for rectilinear arrays.
!===============================================================================
type, extends(Lattice) :: RectLattice
integer :: n_cells(3) ! Number of cells along each axis
real(8), allocatable :: lower_left(:) ! Global lower-left corner of lat
contains
procedure :: are_valid_indices => valid_inds_rect
procedure :: get_indices => get_inds_rect
procedure :: get_local_xyz => get_local_rect
end type RectLattice
!===============================================================================
! HEXLATTICE extends LATTICE for hexagonal (sometimes called triangular) arrays.
!===============================================================================
type, extends(Lattice) :: HexLattice
integer :: n_rings ! Number of radial ring cell positoins
integer :: n_axial ! Number of axial cell positions
real(8), allocatable :: center(:) ! Global center of lattice
contains
procedure :: are_valid_indices => valid_inds_hex
procedure :: get_indices => get_inds_hex
procedure :: get_local_xyz => get_local_hex
end type HexLattice
!===============================================================================
! LATTICECONTAINER pointer array for storing lattices
!===============================================================================
type LatticeContainer
class(Lattice), allocatable :: obj
end type LatticeContainer
!===============================================================================
! CELL defines a closed volume by its bounding surfaces
!===============================================================================
type Cell
integer :: id ! Unique ID
character(len=104) :: name = "" ! User-defined name
integer :: type ! Type of cell (normal, universe,
! lattice)
integer :: universe ! universe # this cell is in
integer :: fill ! universe # filling this cell
integer :: instances ! number of instances of this cell in
! the geom
integer, allocatable :: material(:) ! Material within cell. Multiple
! materials for distribcell
! instances. 0 signifies a universe
integer, allocatable :: offset(:) ! Distribcell offset for tally
! counter
integer, allocatable :: region(:) ! Definition of spatial region as
! Boolean expression of half-spaces
integer, allocatable :: rpn(:) ! Reverse Polish notation for region
! expression
logical :: simple ! Is the region simple (intersections
! only)
integer :: distribcell_index ! Index corresponding to this cell in
! distribcell arrays
real(8), allocatable :: sqrtkT(:) ! Square root of k_Boltzmann *
! temperature in MeV. Multiple for
! distribcell
! Rotation matrix and translation vector
real(8), allocatable :: translation(:)
real(8), allocatable :: rotation(:)
real(8), allocatable :: rotation_matrix(:,:)
end type Cell
! array index of universe 0
integer :: BASE_UNIVERSE
contains
!===============================================================================
function valid_inds_rect(this, i_xyz) result(is_valid)
class(RectLattice), intent(in) :: this
integer, intent(in) :: i_xyz(3)
logical :: is_valid
is_valid = all(i_xyz > 0 .and. i_xyz <= this % n_cells)
end function valid_inds_rect
!===============================================================================
function valid_inds_hex(this, i_xyz) result(is_valid)
class(HexLattice), intent(in) :: this
integer, intent(in) :: i_xyz(3)
logical :: is_valid
is_valid = (all(i_xyz > 0) .and. &
&i_xyz(1) < 2*this % n_rings .and. &
&i_xyz(2) < 2*this % n_rings .and. &
&i_xyz(1) + i_xyz(2) > this % n_rings .and. &
&i_xyz(1) + i_xyz(2) < 3*this % n_rings .and. &
&i_xyz(3) <= this % n_axial)
end function valid_inds_hex
!===============================================================================
function get_inds_rect(this, global_xyz) result(i_xyz)
class(RectLattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer :: i_xyz(3)
real(8) :: xyz(3) ! global_xyz alias
xyz = global_xyz
i_xyz(1) = ceiling((xyz(1) - this % lower_left(1))/this % pitch(1))
i_xyz(2) = ceiling((xyz(2) - this % lower_left(2))/this % pitch(2))
if (this % is_3d) then
i_xyz(3) = ceiling((xyz(3) - this % lower_left(3))/this % pitch(3))
else
i_xyz(3) = 1
end if
end function get_inds_rect
!===============================================================================
function get_inds_hex(this, global_xyz) result(i_xyz)
class(HexLattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer :: i_xyz(3)
real(8) :: xyz(3) ! global xyz relative to the center
real(8) :: alpha ! Skewed coord axis
real(8) :: xyz_t(3) ! Local xyz
real(8) :: d, d_min ! Squared distance from cell centers
integer :: i, j, k ! Iterators
integer :: k_min ! Minimum distance index
xyz(1) = global_xyz(1) - this % center(1)
xyz(2) = global_xyz(2) - this % center(2)
! Index z direction.
if (this % is_3d) then
xyz(3) = global_xyz(3) - this % center(3)
i_xyz(3) = ceiling(xyz(3)/this % pitch(2) + HALF*this % n_axial)
else
xyz(3) = global_xyz(3)
i_xyz(3) = 1
end if
! Convert coordinates into skewed bases. The (x, alpha) basis is used to
! find the index of the global coordinates to within 4 cells.
alpha = xyz(2) - xyz(1) / sqrt(THREE)
i_xyz(1) = floor(xyz(1) / (sqrt(THREE) / TWO * this % pitch(1)))
i_xyz(2) = floor(alpha / this % pitch(1))
! Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but
! the array is offset so that the indices never go below 1).
i_xyz(1) = i_xyz(1) + this % n_rings
i_xyz(2) = i_xyz(2) + this % n_rings
! Calculate the (squared) distance between the particle and the centers of
! the four possible cells. Regular hexagonal tiles form a centroidal
! Voronoi tessellation so the global xyz should be in the hexagonal cell
! that it is closest to the center of. This method is used over a
! method that uses the remainders of the floor divisions above because it
! provides better finite precision performance. Squared distances are
! used becasue they are more computationally efficient than normal
! distances.
k = 1
d_min = INFINITY
do i = 0, 1
do j = 0, 1
xyz_t = this % get_local_xyz(global_xyz, i_xyz + [j, i, 0])
d = xyz_t(1)**2 + xyz_t(2)**2
if (d < d_min) then
d_min = d
k_min = k
end if
k = k + 1
end do
end do
! Select the minimum squared distance which corresponds to the cell the
! coordinates are in.
if (k_min == 2) then
i_xyz(1) = i_xyz(1) + 1
else if (k_min == 3) then
i_xyz(2) = i_xyz(2) + 1
else if (k_min == 4) then
i_xyz(1) = i_xyz(1) + 1
i_xyz(2) = i_xyz(2) + 1
end if
end function get_inds_hex
!===============================================================================
function get_local_rect(this, global_xyz, i_xyz) result(local_xyz)
class(RectLattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer, intent(in) :: i_xyz(3)
real(8) :: local_xyz(3)
real(8) :: xyz(3) ! global_xyz alias
xyz = global_xyz
local_xyz(1) = xyz(1) - (this % lower_left(1) + &
(i_xyz(1) - HALF)*this % pitch(1))
local_xyz(2) = xyz(2) - (this % lower_left(2) + &
(i_xyz(2) - HALF)*this % pitch(2))
if (this % is_3d) then
local_xyz(3) = xyz(3) - (this % lower_left(3) + &
(i_xyz(3) - HALF)*this % pitch(3))
else
local_xyz(3) = xyz(3)
end if
end function get_local_rect
!===============================================================================
function get_local_hex(this, global_xyz, i_xyz) result(local_xyz)
class(HexLattice), intent(in) :: this
real(8), intent(in) :: global_xyz(3)
integer, intent(in) :: i_xyz(3)
real(8) :: local_xyz(3)
real(8) :: xyz(3) ! global_xyz alias
xyz = global_xyz
! x_l = x_g - (center + pitch_x*cos(30)*index_x)
local_xyz(1) = xyz(1) - (this % center(1) + &
sqrt(THREE) / TWO * (i_xyz(1) - this % n_rings) * this % pitch(1))
! y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y)
local_xyz(2) = xyz(2) - (this % center(2) + &
(i_xyz(2) - this % n_rings) * this % pitch(1) + &
(i_xyz(1) - this % n_rings) * this % pitch(1) / TWO)
if (this % is_3d) then
local_xyz(3) = xyz(3) - this % center(3) &
+ (HALF*this % n_axial - i_xyz(3) + HALF) * this % pitch(2)
else
local_xyz(3) = xyz(3)
end if
end function get_local_hex
end module geometry_header