GCC Code Coverage Report


Directory: src/fortran/lib/
File: mod_viability.f90
Date: 2025-06-15 07:27:34
Exec Total Coverage
Lines: 84 84 100.0%
Functions: 0 0 -%
Branches: 182 232 78.4%

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: 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
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 radius_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 real(real32), dimension(3), intent(in) :: grid_offset
50 !! Offset for gridpoints.
51 real(real32), dimension(:,:), allocatable :: points
52 !! List of gridpoints.
53
54 ! Local variables
55 integer :: i, j, k, l, is, ia
56 !! Loop indices.
57 integer :: num_points
58 !! Number of gridpoints.
59 real(real32) :: min_radius
60 !! Minimum radius.
61 real(real32), dimension(3) :: grid_scale, offset
62 !! Grid scale and offset.
63 real(real32), dimension(3) :: point
64 !! Gridpoint.
65 integer, dimension(3) :: idx_lw, idx_up, idx, extent, atom_idx
66 !! Gridpoint indices.
67 integer, dimension(3) :: grid_wo_bounds
68 !! Grid size of cell without bounds.
69 8 integer, dimension(:,:), allocatable :: idx_list
70 !! Temporary list of gridpoints.
71 real(real32), dimension(3,3) :: grid_matrix
72 !! Grid conversion matrix.
73
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 logical, dimension(product(grid)) :: viable
74 !! Temporary list of boolean values for gridpoints.
75
76
77 !---------------------------------------------------------------------------
78 ! get the minimum radius for the gridpoints
79 !---------------------------------------------------------------------------
80
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 12 times.
✓ Branch 9 taken 1 times.
29 min_radius = minval(radius_list) * distribs_container%radius_distance_tol(1)
81
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 grid_scale = ( bounds(2,:) - bounds(1,:) ) / real(grid, real32)
82
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 grid_wo_bounds = nint( real(grid, real32) / ( bounds(2,:) - bounds(1,:) ) )
83
84
85 !---------------------------------------------------------------------------
86 ! get the grid offset in the unit cell
87 ! i.e. the grid must perfectly intersect the
88 ! grid_offset fractional coordinate
89 !---------------------------------------------------------------------------
90
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = ( grid_offset - bounds(1,:) ) / grid_scale
91
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = offset - nint(offset)
92
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 offset = bounds(1,:) + offset * grid_scale
93
94
95 !---------------------------------------------------------------------------
96 ! get the extent of a sphere in terms of the grid
97 !---------------------------------------------------------------------------
98
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))
99 extent = ceiling( [ &
100 sum( abs( grid_matrix(1,:) ) ), &
101 sum( abs( grid_matrix(2,:) ) ), &
102 sum( abs( grid_matrix(3,:) ) ) &
103
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) )
104
105 ! precompute sphere stencil
106 8 num_points = 0
107
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] )))
108
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 8 times.
114 do i = -extent(1), extent(1), 1
109
2/2
✓ Branch 0 taken 1624 times.
✓ Branch 1 taken 106 times.
1738 do j = -extent(2), extent(2), 1
110
2/2
✓ Branch 0 taken 27226 times.
✓ Branch 1 taken 1624 times.
28956 do k = -extent(3), extent(3), 1
111
2/2
✓ Branch 0 taken 81678 times.
✓ Branch 1 taken 27226 times.
108904 point = matmul( [ i, j, k ] / real(grid,real32), basis%lat)
112
8/8
✓ Branch 0 taken 81678 times.
✓ Branch 1 taken 27226 times.
✓ Branch 2 taken 76806 times.
✓ Branch 3 taken 4872 times.
✓ Branch 4 taken 12608 times.
✓ Branch 5 taken 64198 times.
✓ Branch 6 taken 10542 times.
✓ Branch 7 taken 16684 times.
110528 if ( norm2(point) .lt. min_radius ) then
113 10542 num_points = num_points + 1
114
2/2
✓ Branch 0 taken 31626 times.
✓ Branch 1 taken 10542 times.
42168 idx_list(:, num_points) = [ i, j, k]
115 end if
116 end do
117 end do
118 end do
119
120 !---------------------------------------------------------------------------
121 ! apply stencil to exclude gridpoints too close to atoms
122 !---------------------------------------------------------------------------
123
2/2
✓ Branch 0 taken 223880 times.
✓ Branch 1 taken 8 times.
223888 viable = .true.
124 !$omp parallel do default(shared) private(i,is,ia,l,atom_idx,idx)
125
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
18 do is = 1, basis%nspec
126
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 10 times.
106 atom_loop: do ia = 1, basis%spec(is)%num
127
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 40 times.
88 if(.not. basis%spec(is)%atom_mask(ia)) cycle atom_loop
128
129 ! get the atom position in terms of the grid indices
130 atom_idx = &
131
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 nint( ( basis%spec(is)%atom(ia,1:3) - offset ) / grid_scale )
132
133 ! if any one of the indicies is always outside of the grid, skip
134
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_lw = atom_idx - extent
135
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_lw = modulo( idx, grid_wo_bounds )
136
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_up = atom_idx + extent
137
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 idx_up = modulo( idx, grid_wo_bounds )
138
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 do i = 1, 3
139 if( &
140
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) &
141 40 ) cycle atom_loop
142 end do
143
144 !$omp parallel do default(shared) private(i,idx)
145
2/2
✓ Branch 0 taken 70758 times.
✓ Branch 1 taken 40 times.
70808 do i = 1, num_points
146
2/2
✓ Branch 0 taken 212274 times.
✓ Branch 1 taken 70758 times.
283032 idx = idx_list(:,i) + atom_idx
147
2/2
✓ Branch 0 taken 212274 times.
✓ Branch 1 taken 70758 times.
283032 idx = modulo( idx, grid_wo_bounds )
148
4/6
✓ Branch 0 taken 212274 times.
✓ Branch 1 taken 70758 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 212274 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 70758 times.
283032 if( any( idx .ge. grid ) ) cycle
149 viable( &
150 idx(3) * grid(2) * grid(1) + &
151 idx(2) * grid(1) + &
152 idx(1) + 1 &
153 70798 ) = .false.
154 end do
155 !$omp end parallel do
156 end do atom_loop
157 end do
158 !$omp end parallel do
159
160 !---------------------------------------------------------------------------
161 ! get the viable gridpoints in the unit cell
162 !---------------------------------------------------------------------------
163
4/4
✓ Branch 0 taken 223880 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 163366 times.
✓ Branch 3 taken 60514 times.
223888 num_points = count(viable)
164
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) )
165 8 j = 0
166
2/2
✓ Branch 0 taken 223880 times.
✓ Branch 1 taken 8 times.
223888 do i = 1, size(viable)
167
2/2
✓ Branch 0 taken 60514 times.
✓ Branch 1 taken 163366 times.
223880 if(.not. viable(i)) cycle
168 163366 j = j + 1
169 163366 idx(1) = mod( i - 1, grid(1) )
170 163366 idx(2) = mod( ( i - 1 ) / grid(1), grid(2) )
171 163366 idx(3) = ( i - 1 ) / ( grid(1) * grid(2) )
172
2/2
✓ Branch 0 taken 490098 times.
✓ Branch 1 taken 163366 times.
653472 points(1:3,j) = offset + grid_scale * real(idx, real32)
173 end do
174
175
176 !---------------------------------------------------------------------------
177 ! run evaluate_point for a set of points in the unit cell
178 !---------------------------------------------------------------------------
179 !$omp parallel do default(shared) private(i,is)
180
2/2
✓ Branch 0 taken 163366 times.
✓ Branch 1 taken 8 times.
163374 do i = 1, num_points
181 8 do concurrent ( is = 1 : size(species_index_list,1) )
182 points(4,i) = &
183
10/10
✓ Branch 0 taken 1139328 times.
✓ Branch 1 taken 379776 times.
✓ Branch 2 taken 1139328 times.
✓ Branch 3 taken 379776 times.
✓ Branch 5 taken 1139328 times.
✓ Branch 6 taken 379776 times.
✓ Branch 7 taken 1097291 times.
✓ Branch 8 taken 42037 times.
✓ Branch 9 taken 395216 times.
✓ Branch 10 taken 702075 times.
3797760 norm2( get_min_dist(basis, [ points(1:3,i) ], .false. ) )
184 points(4+is,i) = &
185 evaluate_point( distribs_container, &
186 points(1:3,i), species_index_list(is), basis, radius_list &
187
2/2
✓ Branch 0 taken 379776 times.
✓ Branch 1 taken 163366 times.
543142 )
188 end do
189 end do
190 !$omp end parallel do
191
192
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 end function get_gridpoints_and_viability
193 !###############################################################################
194
195
196 !###############################################################################
197 31 subroutine update_gridpoints_and_viability( &
198 points, distribs_container, basis, &
199 31 species_index_list, &
200
2/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
31 atom, radius_list &
201 )
202 !! Update the list of viable gridpoints and their viability for each
203 !! species.
204 !!
205 !! This subroutine updates the viability of all viable gridpoints.
206 implicit none
207
208 ! Arguments
209 real(real32), dimension(:,:), allocatable, intent(inout) :: points
210 !! List of gridpoints.
211 type(distribs_container_type), intent(in) :: distribs_container
212 !! Distribution function (gvector) container.
213 type(extended_basis_type), intent(in) :: basis
214 !! Structure to add atom to.
215 integer, dimension(2), intent(in) :: atom
216 !! Index of atom to add.
217 real(real32), dimension(:), intent(in) :: radius_list
218 !! List of radii for each pair of elements.
219 integer, dimension(:), intent(in) :: species_index_list
220 !! List of species indices to add atoms to.
221
222 ! Local variables
223 integer :: i, is
224 !! Loop indices.
225 integer :: num_points
226 !! Number of gridpoints.
227 integer :: num_species
228 !! Number of species.
229 real(real32) :: min_radius
230 !! Minimum radius.
231 real(real32) :: distance
232 !! Distance between atom and gridpoint.
233 31 integer, dimension(:), allocatable :: idx
234 !! List of indices of viable gridpoints.
235 62 logical, dimension(size(points,dim=2)) :: viable
236 !! Temporary list of gridpoints.
237 real(real32), dimension(3) :: diff
238 !! Difference between atom and gridpoint (direct coorindates).
239 real(real32), dimension(3) :: atom_pos
240 !! Position of atom in direct coordinates.
241 31 real(real32), dimension(:,:), allocatable :: points_tmp
242 !! Temporary list of gridpoints.
243
244
245 !---------------------------------------------------------------------------
246 ! run evaluate_point for a set of points in the unit cell
247 !---------------------------------------------------------------------------
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if(.not.allocated(points)) return
249 31 num_points = size(points,dim=2)
250
2/2
✓ Branch 0 taken 281526 times.
✓ Branch 1 taken 31 times.
281557 viable = .true.
251 min_radius = max( &
252 distribs_container%cutoff_min(1), &
253 minval(radius_list) * distribs_container%radius_distance_tol(1) &
254
5/10
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 31 times.
✓ Branch 7 taken 31 times.
✓ Branch 8 taken 31 times.
✗ Branch 9 not taken.
93 )
255
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 31 times.
124 atom_pos = basis%spec(atom(1))%atom(atom(2),1:3)
256 31 num_species = size(species_index_list,1)
257 !$omp parallel do default(shared) private(i,is,diff,distance)
258
2/2
✓ Branch 0 taken 281526 times.
✓ Branch 1 taken 31 times.
281557 do i = 1, num_points
259
2/2
✓ Branch 0 taken 844578 times.
✓ Branch 1 taken 281526 times.
1126104 diff = atom_pos - points(1:3,i)
260
2/2
✓ Branch 0 taken 844578 times.
✓ Branch 1 taken 281526 times.
1126104 diff = diff - anint(diff)
261
6/6
✓ Branch 1 taken 844578 times.
✓ Branch 2 taken 281526 times.
✓ Branch 3 taken 811914 times.
✓ Branch 4 taken 32664 times.
✓ Branch 5 taken 368900 times.
✓ Branch 6 taken 443014 times.
1126104 distance = norm2( matmul( diff, basis%lat ) )
262
2/2
✓ Branch 0 taken 32254 times.
✓ Branch 1 taken 249272 times.
281557 if( distance .lt. min_radius )then
263 32254 viable(i) = .false.
264 else
265
1/2
✓ Branch 0 taken 249272 times.
✗ Branch 1 not taken.
249272 if( distance .le. distribs_container%cutoff_max(1) )then
266 249272 do concurrent( is = 1 : num_species )
267 points(4+is,i) = &
268 evaluate_point( distribs_container, &
269 points(1:3,i), species_index_list(is), basis, &
270 radius_list &
271
2/2
✓ Branch 0 taken 249272 times.
✓ Branch 1 taken 249272 times.
498544 )
272 end do
273 end if
274 249272 points(4,i) = min( points(4,i), distance )
275 end if
276 end do
277 !$omp end parallel do
278
279
4/4
✓ Branch 0 taken 281526 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 249272 times.
✓ Branch 3 taken 32254 times.
281557 num_points = count(viable)
280
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
31 if(num_points.lt.1)then
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(points)
282 1 return
283 end if
284
285
8/12
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 3 taken 280724 times.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 280724 times.
✓ Branch 8 taken 30 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 30 times.
✗ Branch 13 not taken.
561478 idx = pack([(i, i = 1, size(viable))], viable)
286
7/14
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 249272 times.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 1246360 times.
✓ Branch 13 taken 249272 times.
1495662 points_tmp = points(:, idx)
287
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 call move_alloc(points_tmp, points)
288
289
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 1 times.
31 end subroutine update_gridpoints_and_viability
290 !###############################################################################
291
292 end module raffle__viability
293