PSCF v1.4.0
BinaryStructureFactor.tpp
1#ifndef RP_BINARY_STRUCTURE_FACTOR_TPP
2#define RP_BINARY_STRUCTURE_FACTOR_TPP
3
4#include "BinaryStructureFactor.h"
5
6#include <pscf/interaction/Interaction.h>
7#include <pscf/mesh/MeshIterator.h>
8#include <pscf/mesh/Mesh.h>
9#include <pscf/math/IntVec.h>
10
11#include <util/param/ParamComposite.h>
12#include <util/containers/Array.h>
13#include <util/misc/FileMaster.h>
14#include <util/format/Dbl.h>
15#include <util/format/Int.h>
16#include <util/global.h>
17
18#include <iostream>
19#include <complex>
20
21namespace Pscf {
22namespace Rp {
23
24 using namespace Util;
25 using namespace Pscf::Prdc;
26
27 /*
28 * Constructor.
29 */
30 template <int D, class T>
32 typename T::Simulator& simulator,
33 typename T::System& system)
34 : AnalyzerT(simulator, system),
35 kMeshDimensions_(),
36 nWave_(0),
37 nBunch_(0),
38 writeWaveData_(false),
39 isInitialized_(false)
40 {
41 ParamComposite::setClassName("BinaryStructureFactor");
42 AnalyzerT::setFileMaster(system.fileMaster());
43 }
44
45 /*
46 * Read parameters from file, and allocate memory.
47 */
48 template <int D, class T>
50 {
51 // Precondition: Require that the system has two monomer types
52 UTIL_CHECK(system().mixture().nMonomer() == 2);
53
54 AnalyzerT::readInterval(in);
55 AnalyzerT::readOutputFileName(in);
56 writeWaveData_ = false;
57 ParamComposite::readOptional(in, "writeWaveData", writeWaveData_);
58 isInitialized_ = true;
59 }
60
61 /*
62 * Allocate memory arrays with dimensions that depend only on mesh.
63 */
64 template <int D, class T>
66 {
67 UTIL_CHECK(isInitialized_);
68
69 // Compute and compute mesh dimensions
70 Mesh<D> const & mesh = system().domain().mesh();
71 IntVec<D> const & rMeshDimensions = mesh.dimensions();
72 FFTT::computeKMesh(rMeshDimensions, kMeshDimensions_, nWave_);
73
74 // If needed, allocate arrays indexed by wave id
75 if (!wm_.isAllocated()){
76 UTIL_CHECK(!wk_.isAllocated());
77 UTIL_CHECK(!waveBunchIds_.isAllocated());
78 UTIL_CHECK(!waveWeights_.isAllocated());
79 wm_.allocate(rMeshDimensions);
80 wk_.allocate(rMeshDimensions);
81 waveBunchIds_.allocate(nWave_);
82 waveWeights_.allocate(nWave_);
83 if (writeWaveData_) {
84 UTIL_CHECK(!waveAccumulators_.isAllocated());
85 waveAccumulators_.allocate(nWave_);
86 }
87 }
88 UTIL_CHECK(wm_.capacity() == mesh.size());
89 UTIL_CHECK(wk_.capacity() == nWave_);
90 UTIL_CHECK(waveBunchIds_.capacity() == nWave_);
91 UTIL_CHECK(waveWeights_.capacity() == nWave_);
92 if (writeWaveData_) {
93 UTIL_CHECK(waveAccumulators_.capacity() == nWave_);
94 }
95 }
96
97 /*
98 * Allocate and initialize data structures that involve wave bunches.
99 */
100 template <int D, class T>
102 Array<double> const & kSq,
103 Array<bool> const & implicit)
104 {
105 UTIL_CHECK(kSq.capacity() == nWave_);
106 UTIL_CHECK(implicit.capacity() == nWave_);
107
108 // Sort waves in WaveList and set nBunch_
109 typename T::WaveList& waveList = system().waveList();
110 UTIL_CHECK(waveList.isRealField());
111 if (!waveList.hasKSq()) {
112 waveList.computeKSq();
113 }
114 UTIL_CHECK(waveList.kSize() == nWave_);
115 waveList.sortWaves();
116 nBunch_ = waveList.nBunch();
117 UTIL_CHECK(nBunch_ > 0);
118
119 // If needed, allocate or re-allocate arrays indexed by bunch id
120 if (bunchAccumulators_.isAllocated()) {
121 int const m = bunchAccumulators_.capacity();
122 UTIL_CHECK(bunchWavenumbers_.capacity() == m);
123 UTIL_CHECK(bunchValues_.capacity() == m);
124 if (m < nBunch_) {
125 bunchAccumulators_.deallocate();
126 bunchWavenumbers_.deallocate();
127 bunchValues_.deallocate();
128 }
129 }
130 if (!bunchAccumulators_.isAllocated()) {
131 UTIL_CHECK(!bunchWavenumbers_.isAllocated());
132 UTIL_CHECK(!bunchValues_.isAllocated());
133 bunchAccumulators_.allocate(nBunch_);
134 bunchWavenumbers_.allocate(nBunch_);
135 bunchValues_.allocate(nBunch_);
136 }
137 int m = bunchAccumulators_.capacity();
138 UTIL_CHECK(m >= nBunch_);
139 UTIL_CHECK(bunchWavenumbers_.capacity() == m);
140 UTIL_CHECK(bunchValues_.capacity() == m);
141
142 // Initialize all arrays
143 for (int ib = 0; ib < m; ++ib) {
144 bunchAccumulators_[ib].clear();
145 bunchWavenumbers_[ib] = 0.0;
146 bunchValues_[ib] = 0.0;
147 }
148 for (int iw = 0; iw < nWave_; ++iw) {
149 waveBunchIds_[iw] = -1;
150 waveWeights_[iw] = 0.0;
151 }
152 if (writeWaveData_) {
153 for (int iw = 0; iw < nWave_; ++iw) {
154 waveAccumulators_[iw].clear();
155 }
156 }
157
158 // Define references to WaveList data structures
159 Array< int > const & sortedIds = waveList.sortedIds();
160 UTIL_CHECK(sortedIds.capacity() == nWave_);
161 GArray< Pair<int> > const & bunches = waveList.sortedBunches();
162 UTIL_CHECK(bunches.size() == nBunch_);
163
164 // Set bunchWavenumbers_, waveBunchIds_, and waveWeights_
165 double wavenumberSq, newWavenumber, oldWavenumber;
166 double count, sum, tot;
167 int begin, end, k, iw;
168 int nw = 0;
169 for (int ib = 0; ib < nBunch_; ++ib) {
170 begin = bunches[ib][0];
171 end = bunches[ib][1];
172
173 // Compute bunchWavenumbers_[ib] from first wave in bunch
174 iw = sortedIds[begin]; // wave id of first wave in bunch
175 wavenumberSq = kSq[iw];
176 UTIL_CHECK(wavenumberSq >= 0.0);
177 newWavenumber = std::sqrt(wavenumberSq);
178 bunchWavenumbers_[ib] = newWavenumber;
179 if (ib > 0) {
180 UTIL_CHECK(newWavenumber - oldWavenumber > 1.0E-8);
181 }
182 oldWavenumber = newWavenumber;
183
184 // Set bunchIds, unnormalized weights for all waves in this bunch
185 sum = 0.0;
186 for (k = begin; k < end; ++k) {
187 iw = sortedIds[k];
188 // Check that each wave is only processed once
189 UTIL_CHECK(waveBunchIds_[iw] == -1);
190 UTIL_CHECK(std::abs(waveWeights_[iw]) < 1.0E-8);
191 waveBunchIds_[iw] = ib;
192 if (implicit[iw]) {
193 count = 2.0;
194 } else {
195 count = 1.0;
196 }
197 // count = 1.0; // Uncomment to weight waves equally
198 waveWeights_[iw] = count;
199 sum += count;
200 UTIL_CHECK(std::abs(kSq[iw] - wavenumberSq) < 1.0E-8);
201 }
202
203 // Normalize weights for all waves in this bunch
204 tot = 0.0;
205 for (k = begin; k < end; ++k) {
206 iw = sortedIds[k];
207 waveWeights_[iw] /= sum;
208 tot += waveWeights_[iw];
209 ++nw;
210 }
211 UTIL_CHECK(std::abs(tot - 1.0) < 1.0E-8);
212
213 }
214 UTIL_CHECK(nw == nWave_);
215
216 }
217
218 /*
219 * Compute W_{-} and it Fourier transform.
220 */
221 template <int D, class T>
223 {
224 // Preconditions
225 UTIL_CHECK(isInitialized_);
226 UTIL_CHECK(nWave_ > 0);
227 UTIL_CHECK(wk_.capacity() == nWave_);
228
229 // Compute W_{-}(r)
230 typename T::RField const & wa = system().w().rgrid(0);
231 typename T::RField const & wb = system().w().rgrid(1);
232 VecOp::subVV(wm_, wa, wb);
233 VecOp::mulEqS(wm_, 0.5);
234
235 // Fourier transform W_{-}(r)
236 system().domain().fft().forwardTransform(wm_, wk_);
237 }
238
239 /*
240 * Compute structure factors for all wavevectors and bunches.
241 */
242 template <int D, class T>
245 {
246 // Preconditions
247 UTIL_CHECK(isInitialized_);
248 UTIL_CHECK(nBunch_ > 0);
249 UTIL_CHECK(nWave_ >= nBunch_);
250 int m = bunchAccumulators_.capacity();
251 UTIL_CHECK(m >= nBunch_);
252 UTIL_CHECK(bunchWavenumbers_.capacity() >= m);
253 UTIL_CHECK(bunchValues_.capacity() >= m);
254 UTIL_CHECK(waveBunchIds_.capacity() == nWave_);
255 UTIL_CHECK(waveWeights_.capacity() == nWave_);
256 UTIL_CHECK(wk.capacity() == nWave_);
257
258 // Initialize bunch average values to zero
259 for (int ib = 0; ib < nBunch_; ++ib) {
260 bunchValues_[ib] = 0.0;
261 }
262
263 // Set coefficients a_ and b_
264 double const vSystem = system().domain().unitCell().volume();
265 double const vMonomer = system().mixture().vMonomer();
266 double const chi = system().interaction().chi(0,1);
267 double a_ = vSystem / (chi * chi * vMonomer * vMonomer);
268 double b_ = 0.5 / (chi * vMonomer);
269
270 // Compute structure factors for all waves, add to bunchValues_
271 double value;
272 int ib;
273 for (int iw = 0; iw < nWave_; ++iw) {
274 value = a_ * absSq( wk[iw] );
275 value -= b_;
276 if (writeWaveData_) {
277 waveAccumulators_[iw].sample(value);
278 }
279 ib = waveBunchIds_[iw];
280 bunchValues_[ib] += waveWeights_[iw] * value;
281 }
282
283 // Pass bunchValues_ to bunchAccumulators_
284 for (ib = 0; ib < nBunch_; ++ib) {
285 bunchAccumulators_[ib].sample(bunchValues_[ib]);
286 }
287
288 }
289
290 /*
291 * Output final results to output file.
292 */
293 template <int D, class T>
295 {
296 std::string filename;
297 std::ofstream file;
298
299 // Output spherical average values of S(q) for wavector bunches
300 filename = AnalyzerT::outputFileName();
301 if (writeWaveData_) {
302 filename += "_ave";
303 }
304 AnalyzerT::fileMaster().openOutputFile(filename, file);
305 for (int i = 0; i < nBunch_; ++i) {
306 file << Dbl(bunchWavenumbers_[i], 18, 8);
307 file << Dbl(bunchAccumulators_[i].average(), 18, 8);
308 file << std::endl;
309 }
310 file.close();
311
312 // Optionally output S(q) values for individual waves
313 if (writeWaveData_) {
314 filename = AnalyzerT::outputFileName();
315 filename += "_wave";
316 AnalyzerT::fileMaster().openOutputFile(filename, file);
317 MeshIterator<D> iter(kMeshDimensions_);
318 IntVec<D> p;
319 int iw, j;
320 for (iter.begin(); !iter.atEnd(); ++iter) {
321 iw = iter.rank();
322 p = iter.position();
323 for (j = 0; j < D; ++j) {
324 file << Int(p[j], 5);
325 }
326 file << Dbl(waveAccumulators_[iw].average(), 18, 8);
327 file << std::endl;
328 }
329 file.close();
330 }
331
332 }
333
334}
335}
336#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
IntVec< D > dimensions() const
Get an IntVec<D> of the grid dimensions.
Definition Mesh.h:217
int size() const
Get total number of grid points.
Definition Mesh.h:229
void readParameters(std::istream &in) override
Read parameters from file.
void output() override
Output results to predefined output file.
BinaryStructureFactor(typename T::Simulator &simulator, typename T::System &system)
Constructor.
void allocate()
Allocate member arrays with dimensions that depend only on mesh.
void computeS(Array< typename T::Complex > const &wk)
Complete calculation of current structure factors.
void findWaveBunches(Array< double > const &kSq, Array< bool > const &implicit)
Allocate and initialize data structures involving wave bunches.
void computeW()
Compute member variables wm_ and wk_.
Array container class template.
Definition Array.h:40
int capacity() const
Return allocated size.
Definition Array.h:144
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
An automatically growable array, analogous to a std::vector.
Definition GArray.h:34
int size() const
Return logical size of this array (i.e., current number of elements).
Definition GArray.h:450
Wrapper for an int, for formatted ostream output.
Definition Int.h:37
void setClassName(const char *className)
Set class name string.
ScalarParam< Type > & readOptional(std::istream &in, const char *label, Type &value)
Add and read a new optional ScalarParam < Type > object.
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
double absSq(fftw_complex const &a)
Return square of absolute magnitude of an fftw_complex number.
Definition cpu/complex.h:73
double sum(Array< double > const &in)
Compute sum of array elements (real).
Definition Reduce.cpp:20
void mulEqS(Array< double > &a, double b)
Vector-scalar in-place multiplication, a[i] *= b (real).
Definition VecOp.cpp:265
void subVV(Array< double > &a, Array< double > const &b, Array< double > const &c)
Vector-vector subtraction, a[i] = b[i] - c[i] (real)
Definition VecOp.cpp:95
Periodic fields and crystallography.
Definition complex.cpp:11
Class templates for real-valued periodic fields.
PSCF package top-level namespace.