PSCF v1.2
rpg/fts/analyzer/BinaryStructureFactorGrid.tpp
1#ifndef RPG_BINARY_STRUCTURE_FACTOR_GRID_TPP
2#define RPG_BINARY_STRUCTURE_FACTOR_GRID_TPP
3
4#include "BinaryStructureFactorGrid.h"
5
6#include <rpg/fts/simulator/Simulator.h>
7#include <rpg/System.h>
8#include <prdc/crystal/shiftToMinimum.h>
9#include <prdc/cuda/resources.h>
10#include <prdc/cuda/complex.h>
11#include <pscf/mesh/MeshIterator.h>
12#include <util/misc/FileMaster.h>
13#include <util/misc/ioUtil.h>
14#include <util/format/Dbl.h>
15#include <util/format/Int.h>
16
17#include <fftw3.h>
18
19#include <vector>
20#include <unordered_map>
21#include <algorithm>
22
23namespace Pscf {
24namespace Rpg {
25
26 using namespace Util;
27 using namespace Pscf::Prdc;
28 using namespace Pscf::Prdc::Cuda;
29
30 /*
31 * Constructor.
32 */
33 template <int D>
35 : Analyzer<D>(),
36 simulatorPtr_(&simulator),
37 systemPtr_(&(simulator.system())),
38 isInitialized_(false),
39 nSamplePerBlock_(1)
40 { setClassName("BinaryStructureFactorGrid"); }
41
42 /*
43 * Read parameters from file, and allocate memory.
44 */
45 template <int D>
47 {
48 // Precondition: Require that the system has two monomer types
49 UTIL_CHECK(system().mixture().nMonomer() == 2);
50
51 readInterval(in);
52 readOutputFileName(in);
53 readOptional(in,"nSamplePerBlock", nSamplePerBlock_);
54 }
55
56 /*
57 * BinaryStructureFactorGrid setup
58 */
59 template <int D>
61 {
62 //Allocate variables
63 const int nMonomer = system().mixture().nMonomer();
64 IntVec<D> const & dimensions = system().mesh().dimensions();
65 if (!isInitialized_){
66 wm_.allocate(dimensions);
67 wk_.allocate(dimensions);
68 }
69
70 // Compute Fourier space kMeshDimensions_
71 for (int i = 0; i < D; ++i) {
72 if (i < D - 1) {
73 kMeshDimensions_[i] = dimensions[i];
74 } else {
75 kMeshDimensions_[i] = dimensions[i]/2 + 1;
76 }
77 }
78 kSize_ = 1;
79 for(int i = 0; i < D; ++i) {
80 kSize_ *= kMeshDimensions_[i];
81 }
82
83 nWave_ = kSize_;
84 structureFactors_.allocate(nWave_);
85 accumulators_.allocate(nWave_);
86
87 // Convert real grid to KGrid format
88 qList_.resize(kSize_);
89 RField<D> const & kSq = system().domain().waveList().kSq();
90 HostDArray<cudaReal> kSqHost(kSize_);
91 kSqHost = kSq;
93 itr.setDimensions(kMeshDimensions_);
94 for (itr.begin(); !itr.atEnd(); ++itr){
95 qList_[itr.rank()] = sqrt(double(kSqHost[itr.rank()]));
96 }
97
98 isInitialized_ = true;
99
100 // Clear accumulators
101 for (int i = 0; i < nWave_; ++i) {
102 structureFactors_[i] = 0.0;
103 accumulators_[i].setNSamplePerBlock(nSamplePerBlock_);
104 accumulators_[i].clear();
105 }
106
107 if (!isInitialized_) {
108 UTIL_THROW("Error: object is not initialized");
109 }
110 }
111
112 /*
113 * Increment structure factors for all wavevectors and modes.
114 */
115 template <int D>
117 {
118 UTIL_CHECK(system().w().hasData());
119
120 if (isAtInterval(iStep)) {
121 IntVec<D> const & dimensions = system().mesh().dimensions();
122
123 // Compute W: (rgrid(0) - rgrid(1)) / 2
124 VecOp::addVcVc(wm_, system().w().rgrid(0), 0.5,
125 system().w().rgrid(1), -0.5);
126
127 // Convert real grid to KGrid format
128 system().fft().forwardTransform(wm_, wk_);
129
130 HostDArray<cudaComplex> wkCpu(kSize_);
131 wkCpu = wk_; // copy from device to host
132 for (int k = 0; k < wk_.capacity(); k++) {
133 accumulators_[k].sample(absSq<cudaComplex, cudaReal>(wkCpu[k]));
134 }
135 }
136
137 }
138
139 template <int D>
141 {
142 const double vSystem = system().domain().unitCell().volume();
143 const double vMonomer = system().mixture().vMonomer();
144 double n = vSystem / vMonomer;
145 double chi= system().interaction().chi(0,1);
146 MeshIterator<D> itr;
147 itr.setDimensions(kMeshDimensions_);
148 for (itr.begin(); !itr.atEnd(); ++itr) {
149 // Compute vS(q)
150 structureFactors_[itr.rank()] = n / (chi * chi) * accumulators_[itr.rank()].average() - 1.0/(2.0*chi);
151
152 // Compute S(q)
153 structureFactors_[itr.rank()] /= vMonomer;
154 }
155 }
156
157 // Average S(k) over k of equal magnitude
158 template <int D>
160 {
161 UTIL_CHECK(qList_.capacity() == structureFactors_.capacity());
162
163 std::map<double, double> SMap;
164 for (int i = 0; i < qList_.capacity(); ++i) {
165 double q = qList_[i];
166 double s = structureFactors_[i];
167 SMap[q] += s;
168 }
169
170 // Average structure factor with same magnitude value of q
171 for (auto& i : SMap) {
172 double q = i.first;
173 double sum = i.second;
174 int count = std::count(qList_.begin(), qList_.end(), q);
175 i.second = sum / count;
176 }
177
178 // Average structure factor for q in range of +-tolerance
179 double tolerance = 1e-5;
180 auto it = SMap.begin();
181 double currentq = it->first;
182 double sumS = it->second;
183 int count = 1;
184 for (++it; it != SMap.end(); ++it) {
185 double key = it->first;
186 double s = it->second;
187 if (std::abs(key - currentq) <= tolerance) {
188 sumS += s;
189 count++;
190 } else {
191 averageSMap_[currentq] = sumS / count;
192 currentq = key;
193 sumS = s;
194 count = 1;
195 }
196 }
197
198 // Add last batch of data (last number within tolerance)
199 averageSMap_[currentq] = sumS / count;
200 }
201
202
203
204
205 /*
206 * Output final results to output file.
207 */
208 template <int D>
210 {
211 computeStructureFactor();
212 averageStructureFactor();
213
214 // Output structure factors to one file
215 system().fileMaster().openOutputFile(outputFileName(), outputFile_);
216 outputFile_ << "\t" << "q";
217 outputFile_ << "\t" <<"\t" <<"S(q)/(\u03C1 N)";
218 outputFile_<< std::endl;
219 for (const auto& i : averageSMap_) {
220 double q = i.first;
221 double averageS = i.second;
222 outputFile_ << Dbl(q, 18, 8);
223 outputFile_ << Dbl(averageS, 18, 8);
224 outputFile_ << std::endl;
225 }
226 outputFile_.close();
227 }
228
229}
230}
231#endif
Template for dynamic array stored in host CPU memory.
Definition HostDArray.h:43
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.
Field of real double precision values on an FFT mesh.
Abstract base for periodic output and/or analysis actions.
void sample(long iStep)
Add particles to BinaryStructureFactor accumulators.
void setClassName(const char *className)
Set class name string.
void averageStructureFactor()
Compute average S(k) over k of equal magnitude.
void output()
Output results to predefined output file.
void readParameters(std::istream &in)
Read parameters from file.
BinaryStructureFactorGrid(Simulator< D > &simulator, System< D > &system)
Constructor.
Field theoretic simulator (base class).
Definition rpg/System.h:41
Main class for calculations that represent one system.
Definition rpg/System.h:107
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
#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:51
RT absSq(CT const &a)
Return square of absolute magnitude of a complex number.
void addVcVc(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, cudaReal const c, DeviceArray< cudaReal > const &d, cudaReal const e)
Vector addition w/ coefficient, a[i] = (b[i]*c) + (d[i]*e), kernel wrapper.
Definition VecOpMisc.cu:304
Fields, FFTs, and utilities for periodic boundary conditions (CUDA)
Definition CField.cu:12
Periodic fields and crystallography.
Definition CField.cpp:11
PSCF package top-level namespace.
Definition param_pc.dox:1
Utility classes for scientific computation.