Simpatico  v1.10
ddMd/analyzers/scattering/StructureFactor.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "StructureFactor.h"
9 #include <ddMd/simulation/Simulation.h>
10 #include <ddMd/simulation/SimulationAccess.h>
11 #include <ddMd/storage/AtomStorage.h>
12 #include <ddMd/storage/AtomIterator.h>
13 #include <ddMd/communicate/Exchanger.h>
14 #include <simp/boundary/Boundary.h>
15 #include <util/math/Constants.h>
16 #include <util/space/Dimension.h>
17 #include <util/space/IntVector.h>
18 #include <util/misc/ioUtil.h>
19 #include <util/mpi/MpiLoader.h>
20 #include <util/format/Int.h>
21 #include <util/format/Dbl.h>
22 
23 namespace DdMd
24 {
25 
26  using namespace Util;
27  using namespace Simp;
28 
31  : Analyzer(simulation),
32  isInitialized_(false),
33  isFirstStep_(true)
34  { setClassName("StructureFactor"); }
35 
37  {}
38 
40  void StructureFactor::readParameters(std::istream& in)
41  {
43 
44  readInterval(in);
46  read<int>(in, "nMode", nMode_);
48  readDMatrix<double>(in, "modes", modes_, nMode_, nAtomType_);
49  read<int>(in, "nWave", nWave_);
50  waveIntVectors_.allocate(nWave_);
51  readDArray<IntVector>(in, "waveIntVectors", waveIntVectors_, nWave_);
52 
53  waveVectors_.allocate(nWave_);
54  fourierModes_.allocate(nWave_, nMode_);
56 
57  if (simulation().domain().isMaster()) {
59  int i, j;
60  for (i = 0; i < nWave_; ++i) {
61  for (j = 0; j < nMode_; ++j) {
62  structureFactors_(i, j) = 0.0;
63  }
64  }
65  }
66 
67  isInitialized_ = true;
68  }
69 
70  /*
71  * Load internal state from an archive.
72  */
74  {
76 
77  // Load and broadcast parameter file parameters
78  loadInterval(ar);
80  loadParameter<int>(ar, "nMode", nMode_);
82  loadDMatrix<double>(ar, "modes", modes_, nMode_, nAtomType_);
83  loadParameter<int>(ar, "nWave", nWave_);
84  waveIntVectors_.allocate(nWave_);
85  loadDArray<IntVector>(ar, "waveIntVectors", waveIntVectors_, nWave_);
86 
87  // Load and broadcast nSample_
88  MpiLoader<Serializable::IArchive> loader(*this, ar);
89  loader.load(nSample_);
90 
91  // Allocate and load accumulators that exist only on master.
92  if (simulation().domain().isMaster()) {
94  ar >> structureFactors_;
95  }
96 
97  // Allocate work space (all processors).
98  waveVectors_.allocate(nWave_);
99  fourierModes_.allocate(nWave_, nMode_);
101 
102  isInitialized_ = true;
103  }
104 
105  /*
106  * Save internal state to an archive.
107  */
109  {
110  saveInterval(ar);
111  saveOutputFileName(ar);
112  ar << nMode_;
113  ar << modes_;
114  ar << nWave_;
115  ar << waveIntVectors_;
116  ar << nSample_;
117  ar << structureFactors_;
118  }
119 
120  /*
121  * Clear accumulators.
122  */
124  {
125  if (!isInitialized_) {
126  UTIL_THROW("Error: object is not initialized");
127  }
128  assert (nWave_ > 0);
129  assert (nMode_ > 0);
130 
131  nSample_ = 0;
132  if (simulation().domain().isMaster()) {
133 
134  int i, j;
135  for (i = 0; i < nWave_; ++i) {
136  for (j = 0; j < nMode_; ++j) {
137  structureFactors_(i, j) = 0.0;
138  }
139  }
140  }
141  }
142 
143  /*
144  * Increment structure factor.
145  */
146  void StructureFactor::sample(long iStep)
147  {
148  if (!isAtInterval(iStep)) {
149  UTIL_THROW("Time step index not a multiple of interval");
150  }
151  if (simulation().domain().isMaster()) {
152  std::ios_base::openmode mode = std::ios_base::out;
153  if (!isFirstStep_) {
154  mode = std::ios_base::out | std::ios_base::app;
155  }
156  std::string name = outputFileName("_max.dat");
158  }
159 
160  isFirstStep_ = false;
161  Vector position;
162  std::complex<double> expFactor;
163  double product;
164  AtomIterator atomIter;
165  int i, j, typeId;
166 
167  makeWaveVectors();
168 
169  // Set all Fourier modes to zero
170  for (i = 0; i < nWave_; ++i) {
171  for (j = 0; j < nMode_; ++j) {
172  fourierModes_(i, j) = std::complex<double>(0.0, 0.0);
173  }
174  }
175 
176  simulation().atomStorage().begin(atomIter);
177  for ( ; atomIter.notEnd(); ++atomIter) {
178  position = atomIter->position();
179  typeId = atomIter->typeId();
180 
181  // Loop over wavevectors
182  for (i = 0; i < nWave_; ++i) {
183 
184  product = position.dot(waveVectors_[i]);
185  expFactor = exp( product*Constants::Im );
186  for (j = 0; j < nMode_; ++j) {
187  fourierModes_(i, j) += modes_(j, typeId)*expFactor;
188  }
189  }
190  }
191 
192  for (i = 0; i < nWave_; ++i) {
193  for (j = 0; j < nMode_; ++j) {
194  totalFourierModes_(i, j) = std::complex<double>(0.0, 0.0);
195  }
196  }
197 
198  #ifdef UTIL_MPI
199  // Loop over wavevectors
200  for (int i = 0; i < nWave_; ++i) {
201  for (int j = 0; j < nMode_; ++j) {
202  //Sum values from all processors.
204  Reduce(&fourierModes_(i, j), &totalFourierModes_(i, j),
205  1, MPI::DOUBLE_COMPLEX, MPI::SUM, 0);
206  }
207  }
208  #else
209  for (int i = 0; i < nWave_; ++i) {
210  for (int j = 0; j < nMode_; ++j) {
211  totalFourierModes_(i, j) = fourierModes_(i, j);
212  }
213  }
214  #endif
215 
216  if (simulation().domain().isMaster()) {
217  // Increment structure factors
218  double volume = simulation().boundary().volume();
219  double norm, maxValue, maxQ;
220  IntVector maxIntVector;
221  for (j = 0; j < nMode_; ++j) {
222  maxValue = 0.0;
223  maxQ = 0.0;
224  for (i = 1; i < nWave_; ++i) {
225  norm = std::norm(totalFourierModes_(i, j));
226  norm = norm/volume;
227  if ( norm >= maxValue ) {
228  maxValue = norm;
229  maxIntVector = waveIntVectors_[i];
230  maxQ = waveVectors_[i].abs();
231  }
232  structureFactors_(i, j) += norm;
233  }
234  outputFile_ << maxIntVector;
235  outputFile_ << Dbl(maxQ,20,8);
236  outputFile_ << Dbl(maxValue,20,8);
237  outputFile_ << std::endl;
238  }
239  outputFile_ << std::endl;
240  outputFile_.close();
241  }
242 
243  ++nSample_;
244 
245  }
246 
247  /*
248  * Calculate floating point wavevectors.
249  */
251  {
252  Vector dWave;
253  Boundary* boundaryPtr = &simulation().boundary();
254  int i, j;
255 
256  // Calculate wavevectors
257  for (i = 0; i < nWave_; ++i) {
259  for (j = 0; j < Dimension; ++j) {
260  dWave = boundaryPtr->reciprocalBasisVector(j);
261  dWave *= waveIntVectors_[i][j];
262  waveVectors_[i] += dWave;
263  }
264  }
265  }
266 
267  /*
268  * Write data to three output files.
269  */
271  {
272  if (simulation().domain().isMaster()) {
273 
274  // Write parameters to a *.prm file
276  outputFile_);
278  outputFile_.close();
279 
280  // Output structure factors to one *.dat file
282  outputFile_);
283  double value;
284  int i, j, k;
285  for (i = 0; i < nWave_; ++i) {
286  for (k = 0; k < Dimension; ++k) {
287  outputFile_ << Int(waveIntVectors_[i][k], 5);
288  }
289  outputFile_ << Dbl(waveVectors_[i].abs(), 20, 8);
290  for (j = 0; j < nMode_; ++j) {
291  value = structureFactors_(i, j)/double(nSample_);
292  outputFile_ << Dbl(value, 18, 8);
293  }
294  outputFile_ << std::endl;
295  }
296  outputFile_.close();
297  }
298 
299  }
300 
301 }
const int Dimension
Dimensionality of space.
Definition: Dimension.h:19
Abstract base for periodic output and/or analysis actions.
Simulation & simulation()
Get the parent Simulation by reference.
A Vector is a Cartesian vector.
Definition: Vector.h:75
DArray< IntVector > waveIntVectors_
Array of Miller index IntVectors for wavevectors.
float product(float a, float b)
Product for float Data.
Definition: product.h:22
void readOutputFileName(std::istream &in)
Read outputFileName from file.
void saveInterval(Serializable::OArchive &ar)
Save interval parameter to an archive.
void allocate(int capacity1, int capacity2)
Allocate memory for a matrix.
Definition: DMatrix.h:170
AtomStorage & atomStorage()
Get the AtomStorage by reference.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
double volume() const
Return unit cell volume.
double dot(const Vector &v) const
Return dot product of this vector and vector v.
Definition: Vector.h:632
An orthorhombic periodic unit cell.
void openOutputFile(const std::string &filename, std::ofstream &out, std::ios_base::openmode mode=std::ios_base::out) const
Open an output file.
Definition: FileMaster.cpp:290
static const Vector Zero
Zero Vector = {0.0, 0.0, 0.0}.
Definition: Vector.h:369
DMatrix< double > structureFactors_
Structure factor accumulators.
int nAtomType_
Number of atom types, copied from Simulation::nAtomType().
void readInterval(std::istream &in)
Read parameter interval from file.
Wrapper for a double precision number, for formatted ostream output.
Definition: Dbl.h:39
DArray< Vector > waveVectors_
Array of floating point wave vectors.
virtual void readParameters(std::istream &in)
Read parameters from file.
Parallel domain decomposition (DD) MD simulation.
Classes used by all simpatico molecular simulations.
Main object for a domain-decomposition MD simulation.
MPI::Intracomm & communicator() const
Return Cartesian communicator by reference.
Definition: Domain.h:257
Saving / output archive for binary ostream.
void loadOutputFileName(Serializable::IArchive &ar)
Load output file name to an archive.
FileMaster & fileMaster()
Get the associated FileMaster by reference.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
virtual void writeParam(std::ostream &out)
Write all parameters to an output stream.
const Vector & reciprocalBasisVector(int i) const
Return reciprocal lattice basis vector i.
bool isAtInterval(long counter) const
Return true iff counter is a multiple of the interval.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Definition: accumulators.mod:1
virtual void clear()
Clear accumulators.
std::ofstream outputFile_
Output file stream.
Wrapper for an int, for formatted ostream output.
Definition: Int.h:36
DMatrix< std::complex< double > > totalFourierModes_
Total fourier modes of concentration.
const std::string & outputFileName() const
Return outputFileName string.
StructureFactor(Simulation &simulation)
Constructor.
Saving archive for binary istream.
DMatrix< std::complex< double > > fourierModes_
Fourier modes of concentration.
Provides methods for MPI-aware loading of data from input archive.
Definition: MpiLoader.h:43
void setClassName(const char *className)
Set class name string.
void loadInterval(Serializable::IArchive &ar)
Load parameter interval from input archive.
An IntVector is an integer Cartesian vector.
Definition: IntVector.h:73
int nAtomType()
Get maximum number of atom types.
Boundary & boundary()
Get the Boundary by reference.
void saveOutputFileName(Serializable::OArchive &ar)
Save output file name to an archive.
Domain & domain()
Get the Domain by reference.
Iterator for all atoms owned by an AtomStorage.
Definition: AtomIterator.h:24
static const std::complex< double > Im
Square root of -1.
Definition: Constants.h:40
int nSample_
Number of samples thus far.
void sample(long iStep)
Add particles to StructureFactor accumulators.
DMatrix< double > modes_
Array of mode vectors.
void begin(AtomIterator &iterator)
Set iterator to beginning of the set of atoms.
bool isInitialized_
Has readParam been called?
virtual void output()
Output results to predefined output file.