PSCF v1.3
rpc/fts/analyzer/BinaryStructureFactorGrid.tpp
1#ifndef RPC_BINARY_STRUCTURE_FACTOR_GRID_TPP
2#define RPC_BINARY_STRUCTURE_FACTOR_GRID_TPP
3
4#include "BinaryStructureFactorGrid.h"
5
6#include <rpc/fts/simulator/Simulator.h>
7#include <rpc/system/System.h>
8#include <rpc/solvers/Mixture.h>
9#include <rpc/field/Domain.h>
10
11#include <prdc/cpu/RField.h>
12#include <prdc/cpu/FFT.h>
13#include <prdc/crystal/shiftToMinimum.h>
14
15#include <pscf/inter/Interaction.h>
16#include <pscf/mesh/MeshIterator.h>
17#include <pscf/math/IntVec.h>
18
19#include <util/param/ParamComposite.h>
20#include <util/misc/FileMaster.h>
21#include <util/misc/ioUtil.h>
22#include <util/format/Dbl.h>
23#include <util/global.h>
24
25#include <iostream>
26#include <complex>
27#include <vector>
28#include <map>
29#include <algorithm>
30
31namespace Pscf {
32namespace Rpc {
33
34 using namespace Util;
35 using namespace Pscf::Prdc;
36
37 /*
38 * Constructor.
39 */
40 template <int D>
44 : Analyzer<D>(),
47 isInitialized_(false),
48 nSamplePerBlock_(1),
49 kMeshDimensions_(0),
50 kSize_(0)
51 { setClassName("BinaryStructureFactorGrid"); }
52
53
54 /*
55 * Read parameters from file, and allocate memory.
56 */
57 template <int D>
59 {
60 // Precondition: Require that the system has two monomer types
61 UTIL_CHECK(system().mixture().nMonomer() == 2);
62
63 readInterval(in);
65 readOptional(in,"nSamplePerBlock", nSamplePerBlock_);
66 }
67
68 /*
69 * BinaryStructureFactorGrid setup
70 */
71 template <int D>
73 {
74 const int nMonomer = system().mixture().nMonomer();
75 IntVec<D> const & dimensions = system().domain().mesh().dimensions();
76
77 // Compute Fourier space kMeshDimensions_ and kSize_
78 FFT<D>::computeKMesh(dimensions, kMeshDimensions_, kSize_);
79
80 if (!isInitialized_){
81 wKGrid_.allocate(nMonomer);
82 wm_.allocate(dimensions);
83 wk_.allocate(dimensions);
84 for (int i = 0; i < nMonomer; ++i) {
85 wKGrid_[i].allocate(dimensions);
86 }
87
88 // Compute qList
89 qList_.resize(kSize_);
90 IntVec<D> G;
91 IntVec<D> Gmin;
92 UnitCell<D> const & unitCell = system().domain().unitCell();
93 MeshIterator<D> itr(kMeshDimensions_);
94 double Gsq;
95 for (itr.begin(); !itr.atEnd(); ++itr){
96 // Obtain square magnitude of reciprocal basis vector
97 G = itr.position();
98 Gmin = shiftToMinimum(G, dimensions, unitCell);
99 Gsq = unitCell.ksq(Gmin);
100 qList_[itr.rank()] = sqrt(Gsq);
101 }
102
103 }
104
105 nWave_ = kSize_;
106 structureFactors_.allocate(nWave_);
107 accumulators_.allocate(nWave_);
108 isInitialized_ = true;
109
110 // Clear accumulators
111 for (int i = 0; i < nWave_; ++i) {
112 structureFactors_[i] = 0.0;
113 accumulators_[i].setNSamplePerBlock(nSamplePerBlock_);
114 accumulators_[i].clear();
115 }
116
117 if (!isInitialized_) {
118 UTIL_THROW("Error: object is not initialized");
119 }
120 }
121
122 /*
123 * Increment structure factors for all wavevectors and modes.
124 */
125 template <int D>
127 {
128 UTIL_CHECK(system().w().hasData());
129
130 if (isAtInterval(iStep)) {
131
132 // Compute W-
133 for (int i = 0; i < wm_.capacity(); ++i) {
134 wm_[i] = (system().w().rgrid(0)[i] - system().w().rgrid(1)[i])/2;
135 }
136
137 // Convert real grid to KGrid format
138 system().domain().fft().forwardTransform(wm_, wk_);
139
140 // Pass square magnitudes of Fourier components to accumulators
141 for (int k=0; k< wk_.capacity(); k++) {
142 std::complex<double> wmKGrid(wk_[k][0], wk_[k][1]);
143 double squared_magnitude = std::norm(wmKGrid);
144 accumulators_[k].sample(squared_magnitude);
145 }
146
147 }
148 }
149
150 template <int D>
152 {
153 const double vSystem = system().domain().unitCell().volume();
154 const double vMonomer = system().mixture().vMonomer();
155 double n = vSystem / vMonomer;
156 double chi= system().interaction().chi(0,1);
157 MeshIterator<D> itr;
158 itr.setDimensions(wKGrid_[0].dftDimensions());
159 for (itr.begin(); !itr.atEnd(); ++itr) {
160 // Compute vS(q)
161 structureFactors_[itr.rank()] = n / (chi * chi) * accumulators_[itr.rank()].average() - 1.0/(2.0*chi);
162
163 // Compute S(q)
164 structureFactors_[itr.rank()] /= vMonomer;
165 }
166 }
167
168 // Average S(k) over k of equal magnitude
169 template <int D>
171 {
172 // Convert real grid to KGrid format
173 const int nMonomer = system().mixture().nMonomer();
174 for (int i = 0; i < nMonomer; ++i) {
175 system().domain().fft().forwardTransform(system().w().rgrid()[i],
176 wKGrid_[i]);
177 }
178
179 std::map<double, double> SMap;
180 {
181 int qListcapacity = (int)qList_.capacity();
182 double q, s;
183 UTIL_CHECK(qListcapacity == structureFactors_.capacity());
184 for (int i = 0; i < qListcapacity; ++i) {
185 q = qList_[i];
186 s = structureFactors_[i];
187 SMap[q] += s;
188 }
189 }
190
191 // Average structure factor with same magnitude value of q
192 for (auto& i : SMap) {
193 double q = i.first;
194 double sum = i.second;
195 int count = std::count(qList_.begin(), qList_.end(), q);
196 i.second = sum / count;
197 }
198
199 // Average structure factor for q in range of +-tolerance
200 double tolerance = 1e-5;
201 auto it = SMap.begin();
202 double currentq = it->first;
203 double sumS = it->second;
204 int count = 1;
205 for (++it; it != SMap.end(); ++it) {
206 double key = it->first;
207 double s = it->second;
208 if (std::abs(key - currentq) <= tolerance) {
209 sumS += s;
210 count++;
211 } else {
212 averageSMap_[currentq] = sumS / count;
213 currentq = key;
214 sumS = s;
215 count = 1;
216 }
217 }
218
219 // Add last batch of data (last number within tolerance)
220 averageSMap_[currentq] = sumS / count;
221 }
222
223 /*
224 * Output final results to output file.
225 */
226 template <int D>
228 {
231
232 // Output structure factors to one file
233 system().fileMaster().openOutputFile(outputFileName(), outputFile_);
234 outputFile_ << "\t" << "q";
235 outputFile_ << "\t" <<"\t" <<"S(q)";
236 outputFile_<< std::endl;
237 for (const auto& i : averageSMap_) {
238 double q = i.first;
239 double averageS = i.second;
240 outputFile_ << Dbl(q, 18, 8);
241 outputFile_ << Dbl(averageS, 18, 8);
242 outputFile_ << std::endl;
243 }
244 outputFile_.close();
245 }
246
247}
248}
249#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)?
void setDimensions(const IntVec< D > &dimensions)
Set the grid dimensions in all directions.
IntVec< D > position() const
Get current position in the grid, as integer vector.
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:262
virtual double ksq(IntVec< D > const &k) const
Compute square magnitude of reciprocal lattice vector.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
bool isAtInterval(long counter) const
Return true iff counter is a multiple of the interval.
void readInterval(std::istream &in)
Optionally read interval from file, with error checking.
const std::string & outputFileName() const
Return outputFileName string.
void readOutputFileName(std::istream &in)
Read outputFileName from file.
Analyzer()
Default constructor.
void setClassName(const char *className)
Set class name string.
System< D > & system()
Return reference to parent system.
void readParameters(std::istream &in)
Read parameters from file.
BinaryStructureFactorGrid(Simulator< D > &simulator, System< D > &system)
Constructor.
ScalarParam< Type > & readOptional(std::istream &in, const char *label, Type &value)
Add and read a new optional ScalarParam < Type > object.
Simulator< D > & simulator()
Return reference to parent Simulator.
System< D > * systemPtr_
Pointer to the parent system.
void sample(long iStep)
Add particles to BinaryStructureFactor accumulators.
void averageStructureFactor()
Compute average S(k) over k of equal magnitude.
Simulator< D > * simulatorPtr_
Pointer to parent Simulator.
void output()
Output results to predefined output file.
Field theoretic simulator (base class).
Main class, representing one complete system.
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
Periodic fields and crystallography.
Definition CField.cpp:11
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.
Definition param_pc.dox:1