PSCF v1.4.0
cpu/WaveList.tpp
1#ifndef PRDC_CPU_WAVE_LIST_TPP
2#define PRDC_CPU_WAVE_LIST_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field
6*
7* Copyright 2015 - 2025, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "WaveList.h"
12
13#include <prdc/cpu/FFT.h>
14#include <prdc/crystal/UnitCell.h>
15#include <prdc/crystal/shiftToMinimum.h>
16#include <prdc/crystal/hasVariableAngle.h>
17
18#include <pscf/mesh/MeshIterator.h>
19#include <pscf/mesh/Mesh.h>
20#include <pscf/math/Sort.h>
21
22namespace Pscf {
23namespace Prdc {
24namespace Cpu {
25
26 /*
27 * Constructor.
28 */
29 template <int D>
31 : kSize_(0),
32 nBunch_(0),
33 isAllocated_(false),
34 hasMinImages_(false),
35 hasKSq_(false),
36 hasdKSq_(false),
37 isSorted_(false),
38 isRealField_(isRealField),
39 unitCellPtr_(nullptr),
40 meshPtr_(nullptr)
41 {}
42
43 /*
44 * Destructor.
45 */
46 template <int D>
49
50 /*
51 * Allocate memory used by WaveList.
52 */
53 template <int D>
54 void WaveList<D>::allocate(Mesh<D> const & m, UnitCell<D> const & c)
55 {
56 UTIL_CHECK(m.size() > 0);
57 UTIL_CHECK(c.nParameter() > 0);
58 UTIL_CHECK(!isAllocated_);
59
60 // Create permanent associations with mesh and unit cell
61 unitCellPtr_ = &c;
62 meshPtr_ = &m;
63
64 // Local copies of properties
65 int nParams = unitCell().nParameter();
66 IntVec<D> const & meshDimensions = mesh().dimensions();
67
68 // Compute kMeshDimensions_ and kSize_
69 if (isRealField_) {
70 FFT<D>::computeKMesh(meshDimensions, kMeshDimensions_, kSize_);
71 } else {
72 kMeshDimensions_ = meshDimensions;
73 kSize_ = mesh().size();
74 }
75
76 // Allocate memory
77 minImages_.allocate(kSize_);
78 kSq_.allocate(kMeshDimensions_);
79 dKSq_.allocate(nParams);
80 for (int i = 0; i < nParams; i++) {
81 dKSq_[i].allocate(kMeshDimensions_);
82 }
83
84 // Allocate and set up implicitInverse_ array if isRealField_ == true
85 // (only depends on mesh dimensions, only used for real fields)
86 if (isRealField_) {
87 implicitInverse_.allocate(kSize_);
88
89 MeshIterator<D> kItr(kMeshDimensions_);
90 int rank;
91
92 for (kItr.begin(); !kItr.atEnd(); ++kItr) {
93 rank = kItr.rank();
94 implicitInverse_[rank] =
95 FFT<D>::hasImplicitInverse(kItr.position(), meshDimensions);
96 }
97 }
98
100 isAllocated_ = true;
101 }
102
103 /*
104 * Clear all data that depends on unit cell parameters.
105 */
106 template <int D>
108 {
109 hasKSq_ = false;
110 hasdKSq_ = false;
111 if (unitCell().nParameter() > 1) {
112 isSorted_ = false;
113 sortedBunches_.clear();
114 nBunch_ = 0;
115 }
116 if (hasVariableAngle<D>(unitCell().lattice())) {
117 hasMinImages_ = false;
118 }
119 }
120
121 /*
122 * Compute minimum image vectors for all wavevectors.
123 */
124 template <int D>
126 {
127 if (hasMinImages_) return; // min images already calculated
128
129 // Precondition
130 UTIL_CHECK(isAllocated_);
131 UTIL_CHECK(unitCell().lattice() != UnitCell<D>::Null);
132 UTIL_CHECK(unitCell().isInitialized());
133 UTIL_CHECK(minImages_.capacity() == kSize_);
134
135 MeshIterator<D> kItr(kMeshDimensions_);
136 int rank;
137 for (kItr.begin(); !kItr.atEnd(); ++kItr) {
138 rank = kItr.rank();
139 minImages_[rank] = shiftToMinimum(kItr.position(),
140 mesh().dimensions(), unitCell());
141 kSq_[rank] = unitCell().ksq(minImages_[rank]);
142 }
143
144 hasMinImages_ = true;
145 hasKSq_ = true;
146 }
147
148 /*
149 * Compute array of value of |k|^2
150 */
151 template <int D>
153 {
154 // If kSq_ is valid, return immediately without recomputing
155 if (hasKSq_) return;
156
157 // If necessary, compute minimum images.
158 if (!hasMinImages_) {
159 computeMinimumImages(); // computes both min images and kSq
160 return;
161 }
162
163 // Preconditions
164 UTIL_CHECK(isAllocated_);
165 UTIL_CHECK(unitCell().nParameter() > 0);
166 UTIL_CHECK(unitCell().lattice() != UnitCell<D>::Null);
167 UTIL_CHECK(unitCell().isInitialized());
168
169 // Compute kSq_
170 MeshIterator<D> kItr(kMeshDimensions_);
171 int rank;
172 for (kItr.begin(); !kItr.atEnd(); ++kItr) {
173 rank = kItr.rank();
174 kSq_[rank] = unitCell().ksq(minImages_[rank]);
175 }
176
177 hasKSq_ = true;
178 }
179
180 /*
181 * Compute derivatives of |k|^2 w/ respect to unit cell parameters.
182 */
183 template <int D>
185 {
186 if (hasdKSq_) return; // dKSq already calculated
187
188 // Compute minimum images if needed
189 if (!hasMinImages_) {
191 }
192
193 // Preconditions
194 UTIL_CHECK(isAllocated_);
195 UTIL_CHECK(unitCell().nParameter() > 0);
196 UTIL_CHECK(unitCell().lattice() != UnitCell<D>::Null);
197 UTIL_CHECK(unitCell().isInitialized());
198
199 MeshIterator<D> kItr(kMeshDimensions_);
200 int i, rank;
201 for (i = 0 ; i < unitCell().nParameter(); ++i) {
202 RField<D>& dksq = dKSq_[i];
203 for (kItr.begin(); !kItr.atEnd(); ++kItr) {
204 rank = kItr.rank();
205 dksq[rank] = unitCell().dksq(minImages_[rank], i);
206 if (isRealField_) {
207 if (implicitInverse_[rank]) {
208 dksq[rank] *= 2.0;
209 }
210 }
211 }
212 }
213
214 hasdKSq_ = true;
215 }
216
217 /*
218 * Sort waves by magnitude.
219 */
220 template <int D>
222 {
223 if (isSorted_) return;
224
225 // Compute wavenumbers if needed
226 UTIL_CHECK(isAllocated_);
227 if (!hasKSq_) {
228 computeKSq();
229 }
230
231 // Construct sorted array of items
232 std::vector< Sort::Item<double> > items;
234 for (int i = 0; i < kSize_; ++i) {
235 item.value = kSq_[i];
236 item.id = i;
237 items.push_back(item);
238 }
239 UTIL_CHECK((int)items.size() == kSize_);
240 Sort::sort(items);
241
242 // Fill sortedIds_ array with ids
243 if (!sortedIds_.isAllocated()) {
244 sortedIds_.allocate(kSize_);
245 }
246 UTIL_CHECK(sortedIds_.capacity() == kSize_);
247 for (int i = 0; i < kSize_; ++i) {
248 sortedIds_[i] = items[i].id;
249 }
250
251 // Construct sortedBunches_ array and set nBunch_
252 double epsilon = 1.0E-8;
253 sortedBunches_.clear();
254 Sort::findBunches(items, sortedBunches_, epsilon);
255 nBunch_ = sortedBunches_.size();
256
257 // Fill bunchIds_ array
258 UTIL_CHECK(nBunch_ > 0);
259 if (!bunchIds_.isAllocated()) {
260 bunchIds_.allocate(kSize_);
261 }
262 UTIL_CHECK(bunchIds_.capacity() == kSize_);
263 int begin, end, ib, iw;
264 for (ib = 0; ib < nBunch_; ++ib) {
265 begin = sortedBunches_[ib][0];
266 end = sortedBunches_[ib][1];
267 UTIL_CHECK(end > begin);
268 for (iw = begin; iw < end; ++iw) {
269 bunchIds_[sortedIds_[iw]] = ib;
270 }
271 }
272 UTIL_CHECK(end == kSize_);
273
274 isSorted_ = true;
275 }
276
277}
278}
279}
280#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Iterator over points in a Mesh<D>.
int rank() const
Get the rank of current element.
void begin()
Set iterator to the first point in the mesh.
bool atEnd() const
Is this the end (i.e., one past the last point)?
IntVec< D > position() const
Get current position in the grid, as integer vector.
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
int size() const
Get total number of grid points.
Definition Mesh.h:229
static bool hasImplicitInverse(IntVec< D > const &wavevector, IntVec< D > const &meshDimensions)
Does this wavevector have implicit inverse in DFT or real data?
Definition cpu/FFT.h:272
static void computeKMesh(IntVec< D > const &rMeshDimensions, IntVec< D > &kMeshDimensions, int &kSize)
Compute dimensions and size of k-space mesh for DFT of real data.
Definition cpu/FFT.tpp:264
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:27
void computeKSq()
Compute square norm |k|^2 for all wavevectors.
void sortWaves()
Sort waves in order of ascending wavevector norm.
void computeMinimumImages()
Compute minimum images of wavevectors, and also calculates kSq.
bool isRealField() const
Is this WaveList set up for use with real-valued fields?
void allocate(Mesh< D > const &m, UnitCell< D > const &c)
Allocate memory and set association with a Mesh and UnitCell object.
void computedKSq()
Compute derivatives of |k|^2 w/ respect to unit cell parameters.
void clearUnitCellData()
Clear all internal data that depends on lattice parameters.
WaveList(bool isRealField=true)
Constructor.
int nParameter() const
Get the number of parameters in the unit cell.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
void findBunches(std::vector< Item< T > > const &items, GArray< Bunch > &bunches, T epsilon)
Identify "bunches" of equal values within a sorted vector.
Definition Sort.cpp:29
void sort(std::vector< Item< T > > &items)
Sort a std::vector< Item<T> > by ascending item value.
Definition Sort.cpp:22
Fields and FFTs for periodic boundary conditions (CPU)
Definition complex.cpp:12
Periodic fields and crystallography.
Definition complex.cpp:11
bool hasVariableAngle(typename UnitCell< D >::LatticeSystem lattice)
Return true if lattice type has variable angle parameters.
PSCF package top-level namespace.
Struct with value and index, to keep track of permutation.
Definition Sort.h:37