-
Notifications
You must be signed in to change notification settings - Fork 1
/
analysis.h
401 lines (311 loc) · 12.3 KB
/
analysis.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#ifndef ANALYSIS_H_
#define ANALYSIS_H_
#include "watersystem.h"
#include "utility.h"
#include "patterns.h"
#include "dataoutput.h"
// An analysis that will be performed on a system by an analyzer
template <typename T>
class AnalysisSet {
public:
typedef T system_t;
virtual ~AnalysisSet () { }
AnalysisSet (std::string desc, std::string fn) : description (desc), filename(fn) { }
// default setup
virtual void Setup (system_t& t) {
rewind(t.Output());
t.LoadAll();
return;
}
// each analyzer has to have an analysis function to do some number crunching
virtual void Analysis (system_t&) = 0;
// normally this can be done in the analysis section, but just for style we can have something different defined here
virtual void DataOutput (system_t&) { }
virtual void PostAnalysis (system_t&) { }
std::string& Description () { return description; }
std::string& Filename () { return filename; }
protected:
std::string description; // describes the analysis that is performed
std::string filename; // filename to use for data output
}; // class AnalysisSet
template <class T>
class Analyzer : public WaterSystem<T>, public patterns::observer::observable {
protected:
std::string output_filename;
FILE * output;
int output_freq;
void _OutputHeader () const;
void _OutputStatus ();
md_analysis::StarStatusBarUpdater status_updater;
public:
Analyzer (const std::string = std::string("system.cfg"));
virtual ~Analyzer ();
typedef AnalysisSet<Analyzer<T> > analysis_t;
void SystemAnalysis (analysis_t&);
// position boundaries and bin widths for gathering histogram data
static double posres;
static int posbins;
static double angmin, angmax, angres;
static int angbins;
int timestep;
int Timestep () const { return timestep; }
static int timesteps;
static unsigned int restart;
static double Position (const AtomPtr);
static double Position (const VecR&);
static double Position (const double);
void LoadNext ();
FILE * Output () { return output; }
void OpenDataOutputFile (analysis_t&);
Atom_ptr_vec& Atoms () { return WaterSystem<T>::int_atoms; }
Mol_ptr_vec& Molecules () { return WaterSystem<T>::int_mols; }
Water_ptr_vec& Waters () { return WaterSystem<T>::int_wats; }
// calculate the system's center of mass
template <typename Iter> static VecR CenterOfMass (Iter first, Iter last);
//! Predicate for sorting a container of molecules based on position along the main axis of the system, and using a specific element type to determine molecular position. i.e. sort a container of waters based on the O position, or sort a container of NO3s based on the N position, etc.
class molecule_position_pred;
class molecule_reference_distance_pred;
class atomic_reference_distance_pred;
class MoleculeAbovePosition;
class MoleculeBelowPosition;
}; // Analyzer
template <class T> double Analyzer<T>::posres;
template <class T> int Analyzer<T>::posbins;
template <class T> double Analyzer<T>::angmin;
template <class T> double Analyzer<T>::angmax;
template <class T> double Analyzer<T>::angres;
template <class T> int Analyzer<T>::angbins;
template <class T> int Analyzer<T>::timesteps;
template <class T> unsigned int Analyzer<T>::restart;
template <class T>
Analyzer<T>::Analyzer (const std::string ConfigurationFilename) :
WaterSystem<T>(ConfigurationFilename),
output_filename(""), output((FILE *)NULL),
output_freq(WaterSystem<T>::SystemParameterLookup("analysis.output-frequency")),
timestep (0)
{
Analyzer<T>::posres = WaterSystem<T>::SystemParameterLookup("analysis.resolution.position");
Analyzer<T>::posbins = int((WaterSystem<T>::posmax - WaterSystem<T>::posmin)/posres);
Analyzer<T>::angmin = WaterSystem<T>::SystemParameterLookup("analysis.angle-range")[0];
Analyzer<T>::angmax = WaterSystem<T>::SystemParameterLookup("analysis.angle-range")[1];
Analyzer<T>::angres = WaterSystem<T>::SystemParameterLookup("analysis.resolution.angle");
Analyzer<T>::angbins = int((angmax - angmin)/angres);
Analyzer<T>::timesteps = WaterSystem<T>::SystemParameterLookup("system.timesteps");
Analyzer<T>::restart = WaterSystem<T>::SystemParameterLookup("analysis.restart-time");
status_updater.Set (output_freq, timesteps, 0);
this->registerObserver(&status_updater);
this->_OutputHeader();
} // Analyzer ctor
template <class T>
void Analyzer<T>::_OutputHeader () const {
printf ("Analysis Parameters:\n\tScreen output frequency = 1/%d\n\n\tPosition extents for analysis:\n\t\tMin = % 8.3f\n\t\tMax = % 8.3f\n\t\tPosition Resolution = % 8.3f\n\n\tPrimary Axis = %d\nNumber of timesteps to be analyzed = %d\n",
output_freq, Analyzer<T>::posmin, Analyzer<T>::posmax, Analyzer<T>::posres, int(Analyzer<T>::axis), Analyzer<T>::timesteps);
#ifdef AVG
printf ("\n\nThe analysis is averaging about the two interfaces located as:\n\tLow = % 8.3f\n\tHigh = % 8.3f\n\n", int_low, int_high);
#endif
return;
}
template <class T>
Analyzer<T>::~Analyzer () {
delete this->sys;
if (output != (FILE *)NULL)
fclose(output);
return;
}
template <class T>
void Analyzer<T>::OpenDataOutputFile (analysis_t& an) {
output = (FILE *)NULL;
output = fopen(an.Filename().c_str(), "w");
if (output == (FILE *)NULL) {
printf ("Analyzer<T>::_CheckOutputFile() - couldn't open the data output file, \"%s\", given in the analysis set!\n", an.Filename().c_str());
exit(1);
}
printf ("\nOutputting data to \"%s\"\n", an.Filename().c_str());
return;
}
template <class T>
void Analyzer<T>::_OutputStatus ()
{
this->notifyObservers ();
/*
if (!(timestep % (this->output_freq * 10)))
std::cout << std::endl << timestep << "/" << this->timesteps << " ) ";
if (!(timestep % this->output_freq)) {
std::cout << "*";
}
fflush (stdout);
*/
return;
}
template <>
extern void Analyzer<XYZSystem>::LoadNext () {
this->sys->LoadNext();
this->LoadAll();
return;
}
template <>
extern void Analyzer<AmberSystem>::LoadNext () {
this->sys->LoadNext();
return;
}
template <>
extern void Analyzer<gromacs::GMXSystem<gromacs::TRRFile> >::LoadNext () {
this->sys->LoadNext();
return;
}
template <>
extern void Analyzer<gromacs::GMXSystem<gromacs::XTCFile> >::LoadNext () {
this->sys->LoadNext();
return;
}
template <class T>
void Analyzer<T>::SystemAnalysis (analysis_t& an) {
// Open a file for data output
this->OpenDataOutputFile (an);
// do some initial setup
an.Setup(*this);
// start the analysis - run through each timestep
for (timestep = 0; timestep < timesteps; timestep++) {
try {
// Perform the main loop analysis that works on every timestep of the simulation
an.Analysis (*this);
} catch (std::exception& ex) {
std::cout << "Caught an exception during the system analysis at timestep " << timestep << "." << std::endl;
throw;
}
// output the status of the analysis (to the screen or somewhere useful)
this->_OutputStatus ();
// Output the actual data being collected to a file or something for processing later
if (!(timestep % (output_freq * 10)) && timestep)
an.DataOutput(*this);
try {
// load the next timestep
this->LoadNext();
} catch (std::exception& ex) {
throw;
}
}
// do one final data output to push out the finalized data set
an.DataOutput(*this);
// do a little work after the main analysis loop (normalization of a histogram? etc.)
an.PostAnalysis (*this);
return;
} // System Analysis w/ analysis set
/* Find the periodic-boundary-satistfying location of an atom, vector, or raw coordinate along the reference axis */
template <class T>
double Analyzer<T>::Position (const AtomPtr patom) {
//return Analyzer<T>::Position(patom->Position());
return WaterSystem<T>::AxisPosition(patom);
}
template <class T>
double Analyzer<T>::Position (const VecR& v) {
double position = v[WaterSystem<T>::axis];
return Analyzer<T>::Position(position);
}
template <class T>
double Analyzer<T>::Position (const double d) {
double pos = d;
if (pos < WaterSystem<T>::pbcflip) pos += MDSystem::Dimensions()[WaterSystem<T>::axis];
return pos;
}
template <class T>
template <class Iter> // Has to be iterators to a container of molecules
VecR Analyzer<T>::CenterOfMass (Iter first, Iter last)
{
double mass = 0.0;
VecR com;
com.setZero();
typedef typename std::iterator_traits<Iter>::value_type val_t;
for (Iter it = first; it != last; it++) {
for (Atom_it jt = (*it)->begin(); jt != (*it)->end(); jt++) {
mass += (*jt)->Mass();
com += (*jt)->Position() * (*jt)->Mass();
}
}
com /= mass;
return com;
}
//! Predicate for sorting molecules based on their positions along the system reference axis. The position of the element supplied (elmt) is used. e.g. if elmt = Atom::O, then the first oxygen of the molecule will be used
template<class T>
class Analyzer<T>::molecule_position_pred : public std::binary_function <Molecule*,Molecule*,bool> {
private:
Atom::Element_t _elmt; // determines the element in a molecule to use for position comparison
public:
//! upon instantiation, the element to be used for specifying molecular position is provided
molecule_position_pred (const Atom::Element_t elmt) : _elmt(elmt) { }
bool operator()(const Molecule* left, const Molecule* right) const {
AtomPtr left_o = left->GetAtom(_elmt);
AtomPtr right_o = right->GetAtom(_elmt);
double left_pos = Analyzer<T>::Position(left_o);
double right_pos = Analyzer<T>::Position(right_o);
return left_pos < right_pos;
}
};
//! Calculates the distance between two molecules using their given reference points (as defined in the Molecule::ReferencePoint
template<class T>
class Analyzer<T>::molecule_reference_distance_pred : public std::binary_function <MolPtr,MolPtr,bool> {
private:
MolPtr _reference_mol; // the molecule that will act as the reference point for the comparison
public:
molecule_reference_distance_pred (const MolPtr refmol) : _reference_mol(refmol) { }
// return the distance between the two molecules and the reference mol
bool operator()(const MolPtr left, const MolPtr right) const {
double left_dist = (left->ReferencePoint() - _reference_mol->ReferencePoint()).norm();
double right_dist = (right->ReferencePoint() - _reference_mol->ReferencePoint()).norm();
return left_dist < right_dist;
}
};
// this predicate is used for distance calculations/sorting between atoms given a reference atom
template<class T>
class Analyzer<T>::atomic_reference_distance_pred : public std::binary_function <AtomPtr,AtomPtr,bool> {
private:
AtomPtr _refatom; // the molecule that will act as the reference point for the comparison
public:
atomic_reference_distance_pred (const AtomPtr refatom) : _refatom (refatom) { }
// return the distance between the two molecules and the reference mol
bool operator()(const AtomPtr left, const AtomPtr right) const {
double left_dist = (left->Position() - _refatom->Position()).norm();
double right_dist = (right->Position() - _refatom->Position()).norm();
return left_dist < right_dist;
}
};
// predicate tells if a molecule's reference point along a given axis is above a given value
template <typename T>
class Analyzer<T>::MoleculeAbovePosition : public std::unary_function <MolPtr,bool> {
private:
double position;
coord axis;
public:
MoleculeAbovePosition (const double pos, const coord ax) : position(pos), axis(ax) { }
bool operator() (const MolPtr mol) {
return Analyzer<T>::Position(mol->ReferencePoint()) > position;
}
};
// predicate tells if a molecule's reference point along a given axis is above a given value
template <typename T>
class Analyzer<T>::MoleculeBelowPosition : public std::unary_function <MolPtr,bool> {
private:
double position;
coord axis;
public:
MoleculeBelowPosition (const double pos, const coord ax) : position(pos), axis(ax) { }
bool operator() (const MolPtr mol) {
return Analyzer<T>::Position(mol->ReferencePoint()) < position;
}
};
/***************** Analysis Sets specific to given MD systems ***************/
class XYZAnalysisSet : public AnalysisSet< Analyzer<XYZSystem> > {
public:
typedef Analyzer<XYZSystem> system_t;
XYZAnalysisSet (std::string desc, std::string fn) :
AnalysisSet<system_t> (desc, fn) { }
virtual ~XYZAnalysisSet () { }
};
class AmberAnalysisSet : public AnalysisSet< Analyzer<AmberSystem> > {
public:
typedef Analyzer<AmberSystem> system_t;
AmberAnalysisSet (std::string desc, std::string fn) :
AnalysisSet< system_t > (desc, fn) { }
virtual ~AmberAnalysisSet () { }
};
#endif