21 use,
intrinsic :: iso_fortran_env
75 class(mesh_t),
intent(in) :: mesh
76 real(real64),
intent(in) :: centroids(:, :)
77 integer,
intent(out) :: ip_to_ic(:)
79 integer :: ip, ic, icen
80 integer :: n_centroids
81 real(real64) :: min_dist, dist
82 real(real64),
allocatable :: point(:)
83 real(real64),
parameter :: tol = 1.0e-13_real64
91 assert(
size(ip_to_ic) == mesh%np)
93 n_centroids =
size(centroids, 2)
94 safe_allocate(point(1:
size(centroids, 1)))
100 point = mesh%x(:, ip)
102 min_dist = sum((centroids(:, 1) - point(:))**2)
103 do ic = 2, n_centroids
104 dist = sum((centroids(:, ic) - point(:))**2)
105 if (dist < min_dist - tol)
then
114 safe_deallocate_a(point)
134 class(mesh_t),
intent(in) :: mesh
135 real(real64),
intent(in) :: weight(:)
136 integer,
intent(in) :: ip_to_ic(:)
137 real(real64),
contiguous,
intent(inout) :: centroids(:, :)
140 integer :: n_centroids, ic, ip
141 real(real64) :: one_over_denom
142 real(real64),
allocatable :: denominator(:)
148 assert(mesh%np ==
size(weight))
150 n_centroids =
size(centroids, 2)
151 safe_allocate(denominator(1:n_centroids))
153 do ic = 1, n_centroids
154 centroids(:, ic) = 0._real64
155 denominator(ic) = 0._real64
162 centroids(:, ic) = centroids(:, ic) + (mesh%x(:, ip) * weight(ip))
163 denominator(ic) = denominator(ic) + weight(ip)
168 call mesh%allreduce(centroids)
169 call mesh%allreduce(denominator)
175 do ic = 1, n_centroids
176 one_over_denom = 1._real64 / denominator(ic)
177 centroids(:, ic) = centroids(:, ic) * one_over_denom
181 safe_deallocate_a(denominator)
192 real(real64),
intent(in) :: points(:, :)
193 real(real64),
intent(in) :: updated_points(:, :)
194 real(real64),
intent(in) :: tol
195 logical,
intent(out) :: points_differ(:)
198 real(real64),
allocatable :: diff(:)
202 n_dim =
size(points, 1)
203 allocate(diff(n_dim))
206 do ip = 1,
size(points, 2)
207 diff(:) = abs(updated_points(:, ip) - points(:, ip))
208 points_differ(ip) = any(diff > tol)
223 real(real64),
intent(in) :: points(:, :)
224 real(real64),
intent(in) :: updated_points(:, :)
225 real(real64),
intent(in) :: tol
226 logical,
intent(in) :: points_differ(:)
228 integer,
allocatable :: indices(:)
229 integer :: i, j, n_unconverged, ndim
230 character(len=50) :: f_string
231 real(real64),
allocatable :: diff(:)
235 indices = pack([(i, i=1,
size(points_differ))], points_differ)
236 n_unconverged =
size(indices)
237 ndim =
size(points, 1)
240 write(f_string,
'(A, I1, A, I1, A, I1, A)')
'(', &
241 & ndim,
'(F16.10, X), ', &
242 & ndim,
'(F16.10, X), ', &
243 & ndim,
'(F16.10, X), F16.10)'
245 write(
message(1),
'(a)')
"# Current Point , Prior Point , |ri - r_{i-1}| , tol"
247 do j = 1, n_unconverged
249 diff(:) = abs(updated_points(:, i) - points(:, i))
250 write(
message(1), f_string) updated_points(:, i), points(:, i), diff, tol
253 write(
message(1), *)
"Summary:", n_unconverged,
"of out",
size(points, 2),
"are not converged"
290 subroutine weighted_kmeans(space, mesh, weight, centroids, n_iter, centroid_tol, discretize, inertia)
291 class(
space_t),
intent(in) :: space
292 class(
mesh_t),
intent(in) :: mesh
293 real(real64),
intent(in) :: weight(:)
294 real(real64),
contiguous,
intent(inout) :: centroids(:, :)
296 integer,
optional,
intent(in ) :: n_iter
297 real(real64),
optional,
intent(in ) :: centroid_tol
298 logical,
optional,
intent(in ) :: discretize
299 real(real64),
optional,
intent(out) :: inertia
301 logical :: discretize_centroids
302 integer :: n_iterations, n_centroid, i
304 integer,
allocatable :: ip_to_ic(:)
305 real(real64),
allocatable :: prior_centroids(:, :)
306 logical,
allocatable :: points_differ(:)
315 assert(n_iterations >= 1)
317 assert(
size(weight) == mesh%np)
319 assert(
size(centroids, 1) == space%dim)
321 assert(.not. space%is_periodic())
324 n_centroid =
size(centroids, 2)
325 safe_allocate_source(prior_centroids(space%dim,
size(centroids, 2)), centroids)
326 safe_allocate(ip_to_ic(1:mesh%np))
327 safe_allocate(points_differ(1:n_centroid))
329 write(
message(1),
'(a)')
'Debug: Performing weighted Kmeans clustering '
332 do i = 1, n_iterations
333 write(
message(1),
'(a, I3)')
'Debug: Iteration ', i
341 if (any(points_differ))
then
342 prior_centroids = centroids
344 write(
message(1),
'(a)')
'Debug: All centroid points converged'
352 if (discretize_centroids)
then
356 if (
present(inertia))
then
360 safe_deallocate_a(prior_centroids)
361 safe_deallocate_a(ip_to_ic)
362 safe_deallocate_a(points_differ)
374 class(
mesh_t),
intent(in ) :: mesh
375 real(real64),
contiguous,
intent(out) :: centroids(:, :)
376 integer(int64),
intent(inout),
optional :: seed_value
379 integer(int32) :: n_centroids
380 integer(int64),
allocatable :: centroid_idx(:)
381 integer(int64) :: ipg
386 n_centroids =
size(centroids, 2)
387 safe_allocate(centroid_idx(1:n_centroids))
393 do ic = 1, n_centroids
394 ipg = centroid_idx(ic)
398 safe_deallocate_a(centroid_idx)
415 class(
mesh_t),
intent(in) :: mesh
416 real(real64),
intent(in) :: centroids(:, :)
417 real(real64),
intent(in) :: weight(:)
418 integer,
intent(in) :: ip_to_ic(:)
419 real(real64),
intent(out) :: inertia
427 inertia = inertia + weight(ip) * sum((centroids(:, ic) - mesh%x(:, ip))**2)
431 call mesh%allreduce(inertia)
type(debug_t), save, public debug
subroutine report_differences_in_grids(points, updated_points, tol, points_differ)
Report differences returned from compute_grid_difference.
subroutine, public weighted_kmeans(space, mesh, weight, centroids, n_iter, centroid_tol, discretize, inertia)
Weighted K-means clustering.
subroutine, public sample_initial_centroids(mesh, centroids, seed_value)
Sample initial centroids from the full mesh.
subroutine, public assign_points_to_centroids_finite_bc(mesh, centroids, ip_to_ic)
Assign each grid point to the closest centroid. A centroid and its set of nearest grid points defines...
subroutine, public update_centroids(mesh, weight, ip_to_ic, centroids)
Compute a new set of centroids.
subroutine compute_centroid_inertia(mesh, centroids, weight, ip_to_ic, inertia)
Compute the inertia of all centroids.
subroutine compute_grid_difference(points, updated_points, tol, points_differ)
Compute the difference in two grids as .
This module defines the meshes, which are used in Octopus.
subroutine, public mesh_discretize_values_to_mesh(mesh, values)
Assign a set of values to their nearest discrete points on the mesh.
real(real64) function, dimension(1:mesh%box%dim), public mesh_x_global(mesh, ipg)
Given a global point index, this function returns the coordinates of the point.
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
subroutine, public fisher_yates_shuffle(m, n, seed, values)
Return m random numbers from a range of with no replacement.
This module is intended to contain "only mathematical" functions and procedures.
Describes mesh distribution to nodes.