21 use,
intrinsic :: iso_fortran_env
77 class(mesh_t),
intent(in) :: mesh
78 real(real64),
intent(in) :: centroids(:, :)
79 integer,
intent(out) :: ip_to_ic(:)
81 integer :: ip, ic, icen
82 integer :: n_centroids
83 real(real64) :: min_dist, dist
84 real(real64),
allocatable :: point(:)
85 real(real64),
parameter :: tol = 1.0e-13_real64
93 assert(
size(ip_to_ic) == mesh%np)
95 n_centroids =
size(centroids, 2)
96 safe_allocate(point(1:
size(centroids, 1)))
102 point = mesh%x(ip, :)
104 min_dist = sum((centroids(:, 1) - point(:))**2)
105 do ic = 2, n_centroids
106 dist = sum((centroids(:, ic) - point(:))**2)
107 if (dist < min_dist - tol)
then
116 safe_deallocate_a(point)
136 class(mesh_t),
intent(in) :: mesh
137 real(real64),
intent(in) :: weight(:)
138 integer,
intent(in) :: ip_to_ic(:)
139 real(real64),
contiguous,
intent(inout) :: centroids(:, :)
142 integer :: n_centroids, ic, ip
143 real(real64) :: one_over_denom
144 real(real64),
allocatable :: denominator(:)
150 assert(mesh%np ==
size(weight))
152 n_centroids =
size(centroids, 2)
153 safe_allocate(denominator(1:n_centroids))
155 do ic = 1, n_centroids
156 centroids(:, ic) = 0._real64
157 denominator(ic) = 0._real64
164 centroids(:, ic) = centroids(:, ic) + (mesh%x(ip, :) * weight(ip))
165 denominator(ic) = denominator(ic) + weight(ip)
170 call mesh%allreduce(centroids)
171 call mesh%allreduce(denominator)
177 do ic = 1, n_centroids
178 one_over_denom = 1._real64 / denominator(ic)
179 centroids(:, ic) = centroids(:, ic) * one_over_denom
183 safe_deallocate_a(denominator)
194 real(real64),
intent(in) :: points(:, :)
195 real(real64),
intent(in) :: updated_points(:, :)
196 real(real64),
intent(in) :: tol
197 logical,
intent(out) :: points_differ(:)
200 real(real64),
allocatable :: diff(:)
204 n_dim =
size(points, 1)
205 allocate(diff(n_dim))
208 do ip = 1,
size(points, 2)
209 diff(:) = abs(updated_points(:, ip) - points(:, ip))
210 points_differ(ip) = any(diff > tol)
225 real(real64),
intent(in) :: points(:, :)
226 real(real64),
intent(in) :: updated_points(:, :)
227 real(real64),
intent(in) :: tol
228 logical,
intent(in) :: points_differ(:)
230 integer,
allocatable :: indices(:)
231 integer :: i, j, n_unconverged, ndim
232 character(len=50) :: f_string
233 real(real64),
allocatable :: diff(:)
237 indices = pack([(i, i=1,
size(points_differ))], points_differ)
238 n_unconverged =
size(indices)
239 ndim =
size(points, 1)
242 write(f_string,
'(A, I1, A, I1, A, I1, A)')
'(', &
243 & ndim,
'(F16.10, X), ', &
244 & ndim,
'(F16.10, X), ', &
245 & ndim,
'(F16.10, X), F16.10)'
247 write(
message(1),
'(a)')
"# Current Point , Prior Point , |ri - r_{i-1}| , tol"
249 do j = 1, n_unconverged
251 diff(:) = abs(updated_points(:, i) - points(:, i))
252 write(
message(1), f_string) updated_points(:, i), points(:, i), diff, tol
255 write(
message(1), *)
"Summary:", n_unconverged,
"of out",
size(points, 2),
"are not converged"
292 subroutine weighted_kmeans(space, mesh, weight, centroids, n_iter, centroid_tol, discretize, inertia)
293 class(
space_t),
intent(in) :: space
294 class(
mesh_t),
intent(in) :: mesh
295 real(real64),
intent(in) :: weight(:)
296 real(real64),
contiguous,
intent(inout) :: centroids(:, :)
298 integer,
optional,
intent(in ) :: n_iter
299 real(real64),
optional,
intent(in ) :: centroid_tol
300 logical,
optional,
intent(in ) :: discretize
301 real(real64),
optional,
intent(out) :: inertia
303 logical :: discretize_centroids
304 integer :: n_iterations, n_centroid, i
306 integer,
allocatable :: ip_to_ic(:)
307 real(real64),
allocatable :: prior_centroids(:, :)
308 logical,
allocatable :: points_differ(:)
317 assert(n_iterations >= 1)
319 assert(
size(weight) == mesh%np)
321 assert(
size(centroids, 1) == space%dim)
323 assert(.not. space%is_periodic())
326 n_centroid =
size(centroids, 2)
327 safe_allocate_source(prior_centroids(space%dim,
size(centroids, 2)), centroids)
328 safe_allocate(ip_to_ic(1:mesh%np))
329 safe_allocate(points_differ(1:n_centroid))
331 write(
message(1),
'(a)')
'Debug: Performing weighted Kmeans clustering '
334 do i = 1, n_iterations
335 write(
message(1),
'(a, I3)')
'Debug: Iteration ', i
343 if (any(points_differ))
then
344 prior_centroids = centroids
346 write(
message(1),
'(a)')
'Debug: All centroid points converged'
354 if (discretize_centroids)
then
358 if (
present(inertia))
then
362 safe_deallocate_a(prior_centroids)
363 safe_deallocate_a(ip_to_ic)
364 safe_deallocate_a(points_differ)
376 class(
mesh_t),
intent(in ) :: mesh
377 real(real64),
contiguous,
intent(out) :: centroids(:, :)
378 integer(int64),
intent(inout),
optional :: seed_value
381 integer(int32) :: n_centroids
382 integer(int64),
allocatable :: centroid_idx(:)
383 integer(int64) :: ipg
388 n_centroids =
size(centroids, 2)
389 safe_allocate(centroid_idx(1:n_centroids))
395 do ic = 1, n_centroids
396 ipg = centroid_idx(ic)
400 safe_deallocate_a(centroid_idx)
417 class(
mesh_t),
intent(in) :: mesh
418 real(real64),
intent(in) :: centroids(:, :)
419 real(real64),
intent(in) :: weight(:)
420 integer,
intent(in) :: ip_to_ic(:)
421 real(real64),
intent(out) :: inertia
429 inertia = inertia + weight(ip) * sum((centroids(:, ic) - mesh%x(ip, :))**2)
433 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)
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)
This module contains some common usage patterns of MPI routines.
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.