Loading [MathJax]/extensions/tex2jax.js
 (git:33f85d8)
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
grid_sphere_cache.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------------*/
2/* CP2K: A general program to perform molecular dynamics simulations */
3/* Copyright 2000-2025 CP2K developers group <https://cp2k.org> */
4/* */
5/* SPDX-License-Identifier: BSD-3-Clause */
6/*----------------------------------------------------------------------------*/
7
8#include "grid_sphere_cache.h"
9#include "grid_common.h"
10#include "grid_library.h"
11#include <assert.h>
12#include <math.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17/*******************************************************************************
18 * \brief Compute the sphere bounds for a given single radius.
19 * \author Ole Schuett
20 ******************************************************************************/
21static int single_sphere_bounds(const double disr_radius, const double dh[3][3],
22 const double dh_inv[3][3], int *bounds) {
23
24 int ibound = 0;
25
26 // The cube contains an even number of grid points in each direction and
27 // collocation is always performed on a pair of two opposing grid points.
28 // Hence, the points with index 0 and 1 are both assigned distance zero via
29 // the formular distance=(2*index-1)/2.
30 const int kgmin = ceil(-1e-8 - disr_radius * dh_inv[2][2]);
31 if (bounds != NULL) {
32 bounds[ibound] = kgmin;
33 }
34 ibound++;
35 for (int kg = kgmin; kg <= 0; kg++) {
36 const int kd = (2 * kg - 1) / 2; // distance from center in grid points
37 const double kr = kd * dh[2][2]; // distance from center in a.u.
38 const double kremain = disr_radius * disr_radius - kr * kr;
39 const int jgmin = ceil(-1e-8 - sqrt(fmax(0.0, kremain)) * dh_inv[1][1]);
40 if (bounds != NULL) {
41 bounds[ibound] = jgmin;
42 }
43 ibound++;
44 for (int jg = jgmin; jg <= 0; jg++) {
45 const int jd = (2 * jg - 1) / 2; // distance from center in grid points
46 const double jr = jd * dh[1][1]; // distance from center in a.u.
47 const double jremain = kremain - jr * jr;
48 const int igmin = ceil(-1e-8 - sqrt(fmax(0.0, jremain)) * dh_inv[0][0]);
49 if (bounds != NULL) {
50 bounds[ibound] = igmin;
51 }
52 ibound++;
53 }
54 }
55 return ibound; // Number of bounds - needed to allocate array.
56}
57
58/*******************************************************************************
59 * \brief Rebuild a cache entry for a given cell and max radius.
60 * \author Ole Schuett
61 ******************************************************************************/
62static void rebuild_cache_entry(const int max_imr, const double drmin,
63 const double dh[3][3],
64 const double dh_inv[3][3],
66 if (entry->max_imr > 0) {
67 free(entry->offsets);
68 free(entry->storage);
69 }
70 entry->max_imr = max_imr;
71
72 // Compute required storage size.
73 entry->offsets = malloc(max_imr * sizeof(int));
74 assert(entry->offsets != NULL);
75 int nbounds_total = 0;
76 for (int imr = 1; imr <= max_imr; imr++) {
77 const double radius = imr * drmin;
78 const int nbounds = single_sphere_bounds(radius, dh, dh_inv, NULL);
79 entry->offsets[imr - 1] = nbounds_total;
80 nbounds_total += nbounds;
81 }
82
83 // Allocate and fill storage.
84 entry->storage = malloc(nbounds_total * sizeof(int));
85 assert(entry->storage != NULL);
86 for (int imr = 1; imr <= max_imr; imr++) {
87 const double radius = imr * drmin;
88 const int offset = entry->offsets[imr - 1];
89 single_sphere_bounds(radius, dh, dh_inv, &entry->storage[offset]);
90 }
91}
92
93/*******************************************************************************
94 * \brief Lookup the sphere bound from cache and compute them as needed.
95 * See grid_sphere_cache.h for details.
96 * \author Ole Schuett
97 ******************************************************************************/
98void grid_sphere_cache_lookup(const double radius, const double dh[3][3],
99 const double dh_inv[3][3], int **sphere_bounds,
100 double *discr_radius) {
101
102 // Prepare the cache.
104
105 // Find or create cache entry for given grid.
106 const double dr0 = dh[0][0], dr1 = dh[1][1], dr2 = dh[2][2];
107 grid_sphere_cache_entry *entry = NULL;
108 bool found = false;
109
110 // Fast path: check prev match.
111 if (cache->prev_match < cache->size) {
112 entry = &cache->entries[cache->prev_match];
113 if (entry->dr[0] == dr0 && entry->dr[1] == dr1 && entry->dr[2] == dr2) {
114 found = true;
115 }
116 }
117
118 // Full search.
119 if (!found) {
120 for (int i = 0; i < cache->size; i++) {
121 entry = &cache->entries[i];
122 if (entry->dr[0] == dr0 && entry->dr[1] == dr1 && entry->dr[2] == dr2) {
123 cache->prev_match = i;
124 found = true;
125 break;
126 }
127 }
128 }
129
130 // If no existing cache entry was found then create a new one.
131 if (!found) {
132 cache->size++;
133 grid_sphere_cache_entry *old_entries = cache->entries;
134 const size_t entry_size = sizeof(grid_sphere_cache_entry);
135 cache->entries = malloc(cache->size * entry_size);
136 assert(cache->entries != NULL);
137 memcpy(cache->entries, old_entries, (cache->size - 1) * entry_size);
138 free(old_entries);
139 cache->prev_match = cache->size - 1;
140 entry = &cache->entries[cache->size - 1];
141 // Initialize new cache entry
142 entry->max_imr = 0;
143 entry->dr[0] = dr0;
144 entry->dr[1] = dr1;
145 entry->dr[2] = dr2;
146 entry->drmin = fmin(dr0, fmin(dr1, dr2));
147 entry->drmin_inv = 1.0 / entry->drmin;
148 }
149
150 // Discretize the radius.
151 const int imr = imax(1, (int)ceil(radius * entry->drmin_inv));
152 *discr_radius = entry->drmin * imr;
153
154 // Rebuild cache entry if requested radius is too large.
155 if (entry->max_imr < imr) {
156 rebuild_cache_entry(imr, entry->drmin, dh, dh_inv, entry);
157 }
158 const int offset = entry->offsets[imr - 1];
159 *sphere_bounds = &entry->storage[offset];
160}
161
162/*******************************************************************************
163 * \brief Free the memory of the sphere cache.
164 * \author Ole Schuett
165 ******************************************************************************/
167 for (int i = 0; i < cache->size; i++) {
168 if (cache->entries[i].max_imr > 0) {
169 free(cache->entries[i].offsets);
170 free(cache->entries[i].storage);
171 }
172 }
173 free(cache->entries);
174 cache->size = 0;
175}
176
177// EOF
static int imax(int x, int y)
Returns the larger of two given integers (missing from the C standard)
static void const int const int i
grid_sphere_cache * grid_library_get_sphere_cache(void)
Returns a pointer to the thread local sphere cache.
void grid_sphere_cache_lookup(const double radius, const double dh[3][3], const double dh_inv[3][3], int **sphere_bounds, double *discr_radius)
Lookup the sphere bound from cache and compute them as needed. See grid_sphere_cache....
static void rebuild_cache_entry(const int max_imr, const double drmin, const double dh[3][3], const double dh_inv[3][3], grid_sphere_cache_entry *entry)
Rebuild a cache entry for a given cell and max radius.
void grid_sphere_cache_free(grid_sphere_cache *cache)
Free the memory of the sphere cache.
static int single_sphere_bounds(const double disr_radius, const double dh[3][3], const double dh_inv[3][3], int *bounds)
Compute the sphere bounds for a given single radius.
Struct holding the sphere cache for one grid as specified by dr[3].
int * storage
double drmin
double dr[3]
int max_imr
double drmin_inv
int * offsets
Struct holding the entire sphere cache, ie. for all grids.
grid_sphere_cache_entry * entries