GCC Code Coverage Report


Directory: src/fortran/lib/
File: mod_viability.f90
Date: 2025-04-05 12:17:58
Exec Total Coverage
Lines: 84 84 100.0%
Functions: 0 0 -%
Branches: 182 234 77.8%

Line Branch Exec Source
1 module raffle__viability
2 !! Module to determine the viability of a set of gridpoints
3 !!
4 !! This module contains procedures to determine the viability of a set of
5 !! points and update the viability based on new atoms being added to the cell.
6 #ifdef _OPENMP
7 use omp_lib
8 #endif
9 use raffle__constants, only: real32
10 use raffle__misc_linalg, only: modu, inverse_3x3
11 use raffle__geom_extd, only: extended_basis_type
12 use raffle__dist_calcs, only: &
13 get_min_dist_between_point_and_atom, get_min_dist
14 use raffle__evaluator, only: evaluate_point
15 use raffle__distribs_container, only: distribs_container_type
16 implicit none
17
18
19 private
20
21 public :: get_gridpoints_and_viability, update_gridpoints_and_viability
22
23
24 contains
25
26 !###############################################################################
27 8 function get_gridpoints_and_viability(distribs_container, grid, bounds, &
28 basis, &
29 8 species_index_list, &
30
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 radius_list, atom_ignore_list, grid_offset) result(points)
31 !! Return a list of viable gridpoints and their viability for each species.
32 !!
33 !! This function returns the viability of all viable gridpoints.
34 implicit none
35
36 ! Arguments
37 type(distribs_container_type), intent(in) :: distribs_container
38 !! Distribution function (gvector) container.
39 type(extended_basis_type), intent(in) :: basis
40 !! Structure to add atom to.
41 integer, dimension(3), intent(in) :: grid
42 !! Number of gridpoints in each direction.
43 real(real32), dimension(2,3), intent(in) :: bounds
44 !! Bounds of the unit cell.
45 real(real32), dimension(:), intent(in) :: radius_list
46 !! List of radii for each pair of elements.
47 integer, dimension(:), intent(in) :: species_index_list
48 !! List of species indices to add atoms to.
49 integer, dimension(:,:), intent(in) :: atom_ignore_list
50 !! List of atoms to ignore (i.e. indices of atoms not yet placed).
51 real(real32), dimension(3), intent(in) :: grid_offset
52 !! Offset for gridpoints.
53 real(real32), dimension(:,:), allocatable :: points
54 !! List of gridpoints.
55
56 ! Local variables
57 integer :: i, j, k, l, is, ia
58 !! Loop indices.
59 integer :: num_points
60 !! Number of gridpoints.
61 real(real32) :: min_radius
62 !! Minimum radius.
63 real(real32), dimension(3) :: grid_scale, offset
64 !! Grid scale and offset.
65 real(real32), dimension(3) :: point
66 !! Gridpoint.
67 integer, dimension(3) :: idx_lw, idx_up, idx, extent, atom_idx
68 !! Gridpoint indices.
69 integer, dimension(3) :: grid_wo_bounds
70 !! Grid size of cell without bounds.
71 8 integer, dimension(:,:), allocatable :: idx_list
72 !! Temporary list of gridpoints.
73 real(real32), dimension(3,3) :: grid_matrix
74 !! Grid conversion matrix.
75
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 logical, dimension(product(grid)) :: viable
76 !! Temporary list of boolean values for gridpoints.
77
78
79 !---------------------------------------------------------------------------
80 ! get the minimum radius for the gridpoints
81 !---------------------------------------------------------------------------
82
6/10
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 3 times.
29 min_radius = minval(radius_list) * distribs_container%radius_distance_tol(1)
83
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 grid_scale = ( bounds(2,:) - bounds(1,:) ) / real(grid, real32)
84
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 grid_wo_bounds = nint( real(grid) / ( bounds(2,:) - bounds(1,:) ) )
85
86
87 !---------------------------------------------------------------------------
88 ! get the grid offset in the unit cell
89 ! i.e. the grid must perfectly intersect the
90 ! grid_offset fractional coordinate
91 !---------------------------------------------------------------------------
92
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = ( grid_offset - bounds(1,:) ) / grid_scale
93
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = offset - nint(offset)
94
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = bounds(1,:) + offset * grid_scale
95
96
97 !---------------------------------------------------------------------------
98 ! get the extent of a sphere in terms of the grid
99 !---------------------------------------------------------------------------
100
4/4
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 72 times.
✓ Branch 4 taken 24 times.
104 grid_matrix = transpose(inverse_3x3(basis%lat))
101 extent = ceiling( [ &
102 sum( abs( grid_matrix(1,:) ) ), &
103 sum( abs( grid_matrix(2,:) ) ), &
104 sum( abs( grid_matrix(3,:) ) ) &
105
10/10
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 18 times.
104 ] * min_radius * real(grid, real32) )
106
107 ! precompute sphere stencil
108 8 num_points = 0
109
9/16
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 8 times.
32 allocate(idx_list(1:3, product( extent * 2 + [ 1, 1, 1] )))
110
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 8 times.
102 do i = -extent(1), extent(1), 1
111
2/2
✓ Branch 0 taken 1264 times.
✓ Branch 1 taken 94 times.
1366 do j = -extent(2), extent(2), 1
112
2/2
✓ Branch 0 taken 19078 times.
✓ Branch 1 taken 1264 times.
20436 do k = -extent(3), extent(3), 1
113
2/2
✓ Branch 0 taken 57234 times.
✓ Branch 1 taken 19078 times.
76312 point = matmul( [ i, j, k ] / real(grid,real32), basis%lat)
114
8/8
✓ Branch 0 taken 57234 times.
✓ Branch 1 taken 19078 times.
✓ Branch 2 taken 53442 times.
✓ Branch 3 taken 3792 times.
✓ Branch 4 taken 5798 times.
✓ Branch 5 taken 47644 times.
✓ Branch 6 taken 7398 times.
✓ Branch 7 taken 11680 times.
77576 if ( norm2(point) .lt. min_radius ) then
115 7398 num_points = num_points + 1
116
2/2
✓ Branch 0 taken 22194 times.
✓ Branch 1 taken 7398 times.
29592 idx_list(:, num_points) = [ i, j, k]
117 end if
118 end do
119 end do
120 end do
121
122 !---------------------------------------------------------------------------
123 ! apply stencil to exclude gridpoints too close to atoms
124 !---------------------------------------------------------------------------
125
2/2
✓ Branch 0 taken 177656 times.
✓ Branch 1 taken 8 times.
177664 viable = .true.
126 !$omp parallel do default(shared) private(i,is,ia,l,atom_idx,idx)
127
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
18 do is = 1, basis%nspec
128
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 10 times.
106 atom_loop: do ia = 1, basis%spec(is)%num
129
2/2
✓ Branch 0 taken 594 times.
✓ Branch 1 taken 40 times.
634 do l = 1, size(atom_ignore_list,dim=2), 1
130
6/6
✓ Branch 0 taken 1167 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 546 times.
✓ Branch 3 taken 621 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 546 times.
1255 if(all(atom_ignore_list(:,l).eq.[is,ia])) cycle atom_loop
131 end do
132
133 ! get the atom position in terms of the grid indices
134 atom_idx = &
135
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 nint( ( basis%spec(is)%atom(ia,1:3) - offset )/ grid_scale )
136
137 ! if any one of the indicies is always outside of the grid, skip
138
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_lw = atom_idx - extent
139
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_lw = modulo( idx, grid_wo_bounds )
140
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_up = atom_idx + extent
141
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_up = modulo( idx, grid_wo_bounds )
142
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 do i = 1, 3
143 if( &
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 idx_lw(i) .gt. grid(i) .and. idx_up(i) .lt. grid(i) &
145 40 ) cycle atom_loop
146 end do
147
148 !$omp parallel do default(shared) private(i,idx)
149
2/2
✓ Branch 0 taken 45606 times.
✓ Branch 1 taken 40 times.
45656 do i = 1, num_points
150
2/2
✓ Branch 0 taken 136818 times.
✓ Branch 1 taken 45606 times.
182424 idx = idx_list(:,i) + atom_idx
151
2/2
✓ Branch 0 taken 136818 times.
✓ Branch 1 taken 45606 times.
182424 idx = modulo( idx, grid_wo_bounds )
152
4/6
✓ Branch 0 taken 136818 times.
✓ Branch 1 taken 45606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 136818 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 45606 times.
182424 if( any( idx .ge. grid ) ) cycle
153 viable( &
154 idx(3) * grid(2) * grid(1) + &
155 idx(2) * grid(1) + &
156 idx(1) + 1 &
157 45646 ) = .false.
158 end do
159 !$omp end parallel do
160 end do atom_loop
161 end do
162 !$omp end parallel do
163
164 !---------------------------------------------------------------------------
165 ! get the viable gridpoints in the unit cell
166 !---------------------------------------------------------------------------
167
4/4
✓ Branch 0 taken 177656 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 137170 times.
✓ Branch 3 taken 40486 times.
177664 num_points = count(viable)
168
10/20
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 8 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 8 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 8 times.
8 allocate( points( 4 + basis%nspec, num_points) )
169 8 j = 0
170
2/2
✓ Branch 0 taken 177656 times.
✓ Branch 1 taken 8 times.
177664 do i = 1, size(viable)
171
2/2
✓ Branch 0 taken 40486 times.
✓ Branch 1 taken 137170 times.
177656 if(.not. viable(i)) cycle
172 137170 j = j + 1
173 137170 idx(1) = mod( i - 1, grid(1) )
174 137170 idx(2) = mod( ( i - 1 ) / grid(1), grid(2) )
175 137170 idx(3) = ( i - 1 ) / ( grid(1) * grid(2) )
176
2/2
✓ Branch 0 taken 411510 times.
✓ Branch 1 taken 137170 times.
548688 points(1:3,j) = offset + grid_scale * real(idx, real32)
177 end do
178
179
180 !---------------------------------------------------------------------------
181 ! run evaluate_point for a set of points in the unit cell
182 !---------------------------------------------------------------------------
183 !$omp parallel do default(shared) private(i,is)
184
2/2
✓ Branch 0 taken 137170 times.
✓ Branch 1 taken 8 times.
137178 do i = 1, num_points
185 8 do concurrent ( is = 1 : size(species_index_list,1) )
186 points(4,i) = &
187 modu( get_min_dist(&
188 basis, [ points(1:3,i) ], .false., &
189 ignore_list = atom_ignore_list &
190
4/4
✓ Branch 0 taken 1060740 times.
✓ Branch 1 taken 353580 times.
✓ Branch 2 taken 1060740 times.
✓ Branch 3 taken 353580 times.
2475060 ) )
191 points(4+is,i) = &
192 evaluate_point( distribs_container, &
193 points(1:3,i), species_index_list(is), basis, &
194 atom_ignore_list, radius_list &
195
2/2
✓ Branch 0 taken 353580 times.
✓ Branch 1 taken 137170 times.
490750 )
196 end do
197 end do
198 !$omp end parallel do
199
200
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 end function get_gridpoints_and_viability
201 !###############################################################################
202
203
204 !###############################################################################
205 25 subroutine update_gridpoints_and_viability( &
206 points, distribs_container, basis, &
207 25 species_index_list, &
208
3/6
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
50 atom, radius_list, atom_ignore_list &
209 )
210 !! Update the list of viable gridpoints and their viability for each
211 !! species.
212 !!
213 !! This subroutine updates the viability of all viable gridpoints.
214 implicit none
215
216 ! Arguments
217 real(real32), dimension(:,:), allocatable, intent(inout) :: points
218 !! List of gridpoints.
219 type(distribs_container_type), intent(in) :: distribs_container
220 !! Distribution function (gvector) container.
221 type(extended_basis_type), intent(in) :: basis
222 !! Structure to add atom to.
223 integer, dimension(2), intent(in) :: atom
224 !! Index of atom to add.
225 real(real32), dimension(:), intent(in) :: radius_list
226 !! List of radii for each pair of elements.
227 integer, dimension(:), intent(in) :: species_index_list
228 !! List of species indices to add atoms to.
229 integer, dimension(:,:), intent(in) :: atom_ignore_list
230 !! List of atoms to ignore (i.e. indices of atoms not yet placed).
231
232 ! Local variables
233 integer :: i, is
234 !! Loop indices.
235 integer :: num_points
236 !! Number of gridpoints.
237 real(real32) :: min_radius
238 !! Minimum radius.
239 real(real32) :: distance
240 !! Distance between atom and gridpoint.
241 25 integer, dimension(:), allocatable :: idx
242 !! List of indices of viable gridpoints.
243 50 logical, dimension(size(points,dim=2)) :: viable
244 !! Temporary list of gridpoints.
245 real(real32), dimension(3) :: diff
246 !! Difference between atom and gridpoint (direct coorindates).
247 25 real(real32), dimension(:,:), allocatable :: points_tmp
248 !! Temporary list of gridpoints.
249
250
251 !---------------------------------------------------------------------------
252 ! run evaluate_point for a set of points in the unit cell
253 !---------------------------------------------------------------------------
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
26 if(.not.allocated(points)) return
255 25 num_points = size(points,dim=2)
256
2/2
✓ Branch 0 taken 108747 times.
✓ Branch 1 taken 25 times.
108772 viable = .true.
257
5/10
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✓ Branch 7 taken 25 times.
✓ Branch 8 taken 25 times.
✗ Branch 9 not taken.
75 min_radius = minval(radius_list) * distribs_container%radius_distance_tol(1)
258 associate( atom_pos => [ basis%spec(atom(1))%atom(atom(2),1:3) ] )
259 !$omp parallel do default(shared) private(i,is,diff,distance)
260
6/6
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 108747 times.
✓ Branch 5 taken 25 times.
108922 do i = 1, num_points
261
2/2
✓ Branch 0 taken 326241 times.
✓ Branch 1 taken 108747 times.
434988 diff = atom_pos - points(1:3,i)
262
4/4
✓ Branch 0 taken 326241 times.
✓ Branch 1 taken 108747 times.
✓ Branch 2 taken 303604 times.
✓ Branch 3 taken 22637 times.
434988 diff = diff - ceiling(diff - 0.5_real32)
263 108747 distance = modu( matmul( diff, basis%lat ) )
264
2/2
✓ Branch 0 taken 12855 times.
✓ Branch 1 taken 95892 times.
108747 if( distance .lt. min_radius )then
265 12855 viable(i) = .false.
266 12855 cycle
267
1/2
✓ Branch 0 taken 95892 times.
✗ Branch 1 not taken.
95892 elseif( distance .le. distribs_container%cutoff_max(1) )then
268 95892 do concurrent( is = 1 : size(species_index_list,1) )
269 points(4+is,i) = &
270 evaluate_point( distribs_container, &
271 points(1:3,i), species_index_list(is), basis, &
272 atom_ignore_list, radius_list &
273
2/2
✓ Branch 0 taken 95892 times.
✓ Branch 1 taken 95892 times.
191784 )
274 end do
275 end if
276 95917 points(4,i) = min( points(4,i), distance )
277 end do
278 !$omp end parallel do
279 end associate
280
281
4/4
✓ Branch 0 taken 108747 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 95892 times.
✓ Branch 3 taken 12855 times.
108772 num_points = count(viable)
282
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
25 if(num_points.lt.1)then
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(points)
284 1 return
285 end if
286
287
8/12
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 107945 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 107945 times.
✓ Branch 8 taken 24 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
215914 idx = pack([(i, i = 1, size(viable))], viable)
288
7/14
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 95892 times.
✓ Branch 11 taken 24 times.
✓ Branch 12 taken 479460 times.
✓ Branch 13 taken 95892 times.
575376 points_tmp = points(:, idx)
289
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 call move_alloc(points_tmp, points)
290
291
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1 times.
25 end subroutine update_gridpoints_and_viability
292 !###############################################################################
293
294 end module raffle__viability
295