# | Line 1 | Line 1 | |
---|---|---|
1 | + | /* |
2 | + | * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved. |
3 | + | * |
4 | + | * The University of Notre Dame grants you ("Licensee") a |
5 | + | * non-exclusive, royalty free, license to use, modify and |
6 | + | * redistribute this software in source and binary code form, provided |
7 | + | * that the following conditions are met: |
8 | + | * |
9 | + | * 1. Acknowledgement of the program authors must be made in any |
10 | + | * publication of scientific results based in part on use of the |
11 | + | * program. An acceptable form of acknowledgement is citation of |
12 | + | * the article in which the program was described (Matthew |
13 | + | * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher |
14 | + | * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented |
15 | + | * Parallel Simulation Engine for Molecular Dynamics," |
16 | + | * J. Comput. Chem. 26, pp. 252-271 (2005)) |
17 | + | * |
18 | + | * 2. Redistributions of source code must retain the above copyright |
19 | + | * notice, this list of conditions and the following disclaimer. |
20 | + | * |
21 | + | * 3. Redistributions in binary form must reproduce the above copyright |
22 | + | * notice, this list of conditions and the following disclaimer in the |
23 | + | * documentation and/or other materials provided with the |
24 | + | * distribution. |
25 | + | * |
26 | + | * This software is provided "AS IS," without a warranty of any |
27 | + | * kind. All express or implied conditions, representations and |
28 | + | * warranties, including any implied warranty of merchantability, |
29 | + | * fitness for a particular purpose or non-infringement, are hereby |
30 | + | * excluded. The University of Notre Dame and its licensors shall not |
31 | + | * be liable for any damages suffered by licensee as a result of |
32 | + | * using, modifying or distributing the software or its |
33 | + | * derivatives. In no event will the University of Notre Dame or its |
34 | + | * licensors be liable for any lost revenue, profit or data, or for |
35 | + | * direct, indirect, special, consequential, incidental or punitive |
36 | + | * damages, however caused and regardless of the theory of liability, |
37 | + | * arising out of the use of or inability to use software, even if the |
38 | + | * University of Notre Dame has been advised of the possibility of |
39 | + | * such damages. |
40 | + | */ |
41 | + | |
42 | #include <math.h> | |
43 | #include <iostream> | |
3 | – | using namespace std; |
44 | ||
45 | #ifdef IS_MPI | |
46 | #include <mpi.h> | |
47 | #endif //is_mpi | |
48 | ||
49 | < | #include "Thermo.hpp" |
50 | < | #include "SRI.hpp" |
51 | < | #include "Integrator.hpp" |
52 | < | #include "simError.h" |
13 | < | #include "MatVec3.h" |
49 | > | #include "brains/Thermo.hpp" |
50 | > | #include "primitives/Molecule.hpp" |
51 | > | #include "utils/simError.h" |
52 | > | #include "utils/OOPSEConstant.hpp" |
53 | ||
54 | < | #ifdef IS_MPI |
16 | < | #define __C |
17 | < | #include "mpiSimulation.hpp" |
18 | < | #endif // is_mpi |
54 | > | namespace oopse { |
55 | ||
56 | < | inline double roundMe( double x ){ |
57 | < | return ( x >= 0 ) ? floor( x + 0.5 ) : ceil( x - 0.5 ); |
58 | < | } |
56 | > | double Thermo::getKinetic() { |
57 | > | SimInfo::MoleculeIterator miter; |
58 | > | std::vector<StuntDouble*>::iterator iiter; |
59 | > | Molecule* mol; |
60 | > | StuntDouble* integrableObject; |
61 | > | Vector3d vel; |
62 | > | Vector3d angMom; |
63 | > | Mat3x3d I; |
64 | > | int i; |
65 | > | int j; |
66 | > | int k; |
67 | > | double kinetic = 0.0; |
68 | > | double kinetic_global = 0.0; |
69 | > | |
70 | > | for (mol = info_->beginMolecule(miter); mol != NULL; mol = info_->nextMolecule(miter)) { |
71 | > | for (integrableObject = mol->beginIntegrableObject(iiter); integrableObject != NULL; |
72 | > | integrableObject = mol->nextIntegrableObject(iiter)) { |
73 | ||
74 | < | Thermo::Thermo( SimInfo* the_info ) { |
75 | < | info = the_info; |
26 | < | int baseSeed = the_info->getSeed(); |
27 | < | |
28 | < | gaussStream = new gaussianSPRNG( baseSeed ); |
29 | < | } |
74 | > | double mass = integrableObject->getMass(); |
75 | > | Vector3d vel = integrableObject->getVel(); |
76 | ||
77 | < | Thermo::~Thermo(){ |
32 | < | delete gaussStream; |
33 | < | } |
77 | > | kinetic += mass * (vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]); |
78 | ||
79 | < | double Thermo::getKinetic(){ |
79 | > | if (integrableObject->isDirectional()) { |
80 | > | angMom = integrableObject->getJ(); |
81 | > | I = integrableObject->getI(); |
82 | ||
83 | < | const double e_convert = 4.184E-4; // convert kcal/mol -> (amu A^2)/fs^2 |
84 | < | double kinetic; |
85 | < | double amass; |
86 | < | double aVel[3], aJ[3], I[3][3]; |
87 | < | int i, j, k, kl; |
88 | < | |
89 | < | double kinetic_global; |
90 | < | vector<StuntDouble *> integrableObjects = info->integrableObjects; |
91 | < | |
92 | < | kinetic = 0.0; |
93 | < | kinetic_global = 0.0; |
48 | < | |
49 | < | for (kl=0; kl<integrableObjects.size(); kl++) { |
50 | < | integrableObjects[kl]->getVel(aVel); |
51 | < | amass = integrableObjects[kl]->getMass(); |
52 | < | |
53 | < | for(j=0; j<3; j++) |
54 | < | kinetic += amass*aVel[j]*aVel[j]; |
55 | < | |
56 | < | if (integrableObjects[kl]->isDirectional()){ |
57 | < | |
58 | < | integrableObjects[kl]->getJ( aJ ); |
59 | < | integrableObjects[kl]->getI( I ); |
60 | < | |
61 | < | if (integrableObjects[kl]->isLinear()) { |
62 | < | i = integrableObjects[kl]->linearAxis(); |
63 | < | j = (i+1)%3; |
64 | < | k = (i+2)%3; |
65 | < | kinetic += aJ[j]*aJ[j]/I[j][j] + aJ[k]*aJ[k]/I[k][k]; |
66 | < | } else { |
67 | < | for (j=0; j<3; j++) |
68 | < | kinetic += aJ[j]*aJ[j] / I[j][j]; |
83 | > | if (integrableObject->isLinear()) { |
84 | > | i = integrableObject->linearAxis(); |
85 | > | j = (i + 1) % 3; |
86 | > | k = (i + 2) % 3; |
87 | > | kinetic += angMom[j] * angMom[j] / I(j, j) + angMom[k] * angMom[k] / I(k, k); |
88 | > | } else { |
89 | > | kinetic += angMom[0]*angMom[0]/I(0, 0) + angMom[1]*angMom[1]/I(1, 1) |
90 | > | + angMom[2]*angMom[2]/I(2, 2); |
91 | > | } |
92 | > | } |
93 | > | |
94 | } | |
95 | < | } |
96 | < | } |
95 | > | } |
96 | > | |
97 | #ifdef IS_MPI | |
73 | – | MPI_Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE, |
74 | – | MPI_SUM, MPI_COMM_WORLD); |
75 | – | kinetic = kinetic_global; |
76 | – | #endif //is_mpi |
77 | – | |
78 | – | kinetic = kinetic * 0.5 / e_convert; |
98 | ||
99 | < | return kinetic; |
100 | < | } |
99 | > | MPI_Allreduce(&kinetic, &kinetic_global, 1, MPI_DOUBLE, MPI_SUM, |
100 | > | MPI_COMM_WORLD); |
101 | > | kinetic = kinetic_global; |
102 | ||
103 | < | double Thermo::getPotential(){ |
84 | < | |
85 | < | double potential_local; |
86 | < | double potential; |
87 | < | int el, nSRI; |
88 | < | Molecule* molecules; |
103 | > | #endif //is_mpi |
104 | ||
105 | < | molecules = info->molecules; |
91 | < | nSRI = info->n_SRI; |
105 | > | kinetic = kinetic * 0.5 / OOPSEConstant::energyConvert; |
106 | ||
107 | < | potential_local = 0.0; |
94 | < | potential = 0.0; |
95 | < | potential_local += info->lrPot; |
96 | < | |
97 | < | for( el=0; el<info->n_mol; el++ ){ |
98 | < | potential_local += molecules[el].getPotential(); |
107 | > | return kinetic; |
108 | } | |
109 | ||
110 | < | // Get total potential for entire system from MPI. |
111 | < | #ifdef IS_MPI |
112 | < | MPI_Allreduce(&potential_local,&potential,1,MPI_DOUBLE, |
113 | < | MPI_SUM, MPI_COMM_WORLD); |
114 | < | #else |
106 | < | potential = potential_local; |
107 | < | #endif // is_mpi |
110 | > | double Thermo::getPotential() { |
111 | > | double potential = 0.0; |
112 | > | Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot(); |
113 | > | double potential_local = curSnapshot->statData[Stats::LONG_RANGE_POTENTIAL] + |
114 | > | curSnapshot->statData[Stats::SHORT_RANGE_POTENTIAL] ; |
115 | ||
116 | < | return potential; |
110 | < | } |
116 | > | // Get total potential for entire system from MPI. |
117 | ||
118 | < | double Thermo::getTotalE(){ |
118 | > | #ifdef IS_MPI |
119 | ||
120 | < | double total; |
120 | > | MPI_Allreduce(&potential_local, &potential, 1, MPI_DOUBLE, MPI_SUM, |
121 | > | MPI_COMM_WORLD); |
122 | ||
123 | < | total = this->getKinetic() + this->getPotential(); |
117 | < | return total; |
118 | < | } |
123 | > | #else |
124 | ||
125 | < | double Thermo::getTemperature(){ |
125 | > | potential = potential_local; |
126 | ||
127 | < | const double kb = 1.9872156E-3; // boltzman's constant in kcal/(mol K) |
123 | < | double temperature; |
127 | > | #endif // is_mpi |
128 | ||
129 | < | temperature = ( 2.0 * this->getKinetic() ) / ((double)info->ndf * kb ); |
130 | < | return temperature; |
127 | < | } |
129 | > | return potential; |
130 | > | } |
131 | ||
132 | < | double Thermo::getVolume() { |
132 | > | double Thermo::getTotalE() { |
133 | > | double total; |
134 | ||
135 | < | return info->boxVol; |
136 | < | } |
135 | > | total = this->getKinetic() + this->getPotential(); |
136 | > | return total; |
137 | > | } |
138 | ||
139 | < | double Thermo::getPressure() { |
139 | > | double Thermo::getTemperature() { |
140 | > | |
141 | > | double temperature = ( 2.0 * this->getKinetic() ) / (info_->getNdf()* OOPSEConstant::kb ); |
142 | > | return temperature; |
143 | > | } |
144 | ||
145 | < | // Relies on the calculation of the full molecular pressure tensor |
146 | < | |
147 | < | const double p_convert = 1.63882576e8; |
148 | < | double press[3][3]; |
140 | < | double pressure; |
145 | > | double Thermo::getVolume() { |
146 | > | Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot(); |
147 | > | return curSnapshot->getVolume(); |
148 | > | } |
149 | ||
150 | < | this->getPressureTensor(press); |
150 | > | double Thermo::getPressure() { |
151 | ||
152 | < | pressure = p_convert * (press[0][0] + press[1][1] + press[2][2]) / 3.0; |
152 | > | // Relies on the calculation of the full molecular pressure tensor |
153 | ||
146 | – | return pressure; |
147 | – | } |
154 | ||
155 | < | double Thermo::getPressureX() { |
155 | > | Mat3x3d tensor; |
156 | > | double pressure; |
157 | ||
158 | < | // Relies on the calculation of the full molecular pressure tensor |
152 | < | |
153 | < | const double p_convert = 1.63882576e8; |
154 | < | double press[3][3]; |
155 | < | double pressureX; |
158 | > | tensor = getPressureTensor(); |
159 | ||
160 | < | this->getPressureTensor(press); |
160 | > | pressure = OOPSEConstant::pressureConvert * (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0; |
161 | ||
162 | < | pressureX = p_convert * press[0][0]; |
162 | > | return pressure; |
163 | > | } |
164 | ||
165 | < | return pressureX; |
162 | < | } |
165 | > | double Thermo::getPressure(int direction) { |
166 | ||
167 | < | double Thermo::getPressureY() { |
167 | > | // Relies on the calculation of the full molecular pressure tensor |
168 | ||
169 | < | // Relies on the calculation of the full molecular pressure tensor |
170 | < | |
171 | < | const double p_convert = 1.63882576e8; |
169 | < | double press[3][3]; |
170 | < | double pressureY; |
169 | > | |
170 | > | Mat3x3d tensor; |
171 | > | double pressure; |
172 | ||
173 | < | this->getPressureTensor(press); |
173 | > | tensor = getPressureTensor(); |
174 | ||
175 | < | pressureY = p_convert * press[1][1]; |
175 | > | pressure = OOPSEConstant::pressureConvert * tensor(direction, direction); |
176 | ||
177 | < | return pressureY; |
178 | < | } |
177 | > | return pressure; |
178 | > | } |
179 | ||
179 | – | double Thermo::getPressureZ() { |
180 | ||
181 | – | // Relies on the calculation of the full molecular pressure tensor |
182 | – | |
183 | – | const double p_convert = 1.63882576e8; |
184 | – | double press[3][3]; |
185 | – | double pressureZ; |
181 | ||
182 | < | this->getPressureTensor(press); |
182 | > | Mat3x3d Thermo::getPressureTensor() { |
183 | > | // returns pressure tensor in units amu*fs^-2*Ang^-1 |
184 | > | // routine derived via viral theorem description in: |
185 | > | // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322 |
186 | > | Mat3x3d pressureTensor; |
187 | > | Mat3x3d p_local(0.0); |
188 | > | Mat3x3d p_global(0.0); |
189 | ||
190 | < | pressureZ = p_convert * press[2][2]; |
190 | > | SimInfo::MoleculeIterator i; |
191 | > | std::vector<StuntDouble*>::iterator j; |
192 | > | Molecule* mol; |
193 | > | StuntDouble* integrableObject; |
194 | > | for (mol = info_->beginMolecule(i); mol != NULL; mol = info_->nextMolecule(i)) { |
195 | > | for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL; |
196 | > | integrableObject = mol->nextIntegrableObject(j)) { |
197 | ||
198 | < | return pressureZ; |
199 | < | } |
200 | < | |
201 | < | |
202 | < | void Thermo::getPressureTensor(double press[3][3]){ |
196 | < | // returns pressure tensor in units amu*fs^-2*Ang^-1 |
197 | < | // routine derived via viral theorem description in: |
198 | < | // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322 |
199 | < | |
200 | < | const double e_convert = 4.184e-4; |
201 | < | |
202 | < | double molmass, volume; |
203 | < | double vcom[3]; |
204 | < | double p_local[9], p_global[9]; |
205 | < | int i, j, k; |
206 | < | |
207 | < | for (i=0; i < 9; i++) { |
208 | < | p_local[i] = 0.0; |
209 | < | p_global[i] = 0.0; |
210 | < | } |
211 | < | |
212 | < | // use velocities of integrableObjects and their masses: |
213 | < | |
214 | < | for (i=0; i < info->integrableObjects.size(); i++) { |
215 | < | |
216 | < | molmass = info->integrableObjects[i]->getMass(); |
198 | > | double mass = integrableObject->getMass(); |
199 | > | Vector3d vcom = integrableObject->getVel(); |
200 | > | p_local += mass * outProduct(vcom, vcom); |
201 | > | } |
202 | > | } |
203 | ||
218 | – | info->integrableObjects[i]->getVel(vcom); |
219 | – | |
220 | – | p_local[0] += molmass * (vcom[0] * vcom[0]); |
221 | – | p_local[1] += molmass * (vcom[0] * vcom[1]); |
222 | – | p_local[2] += molmass * (vcom[0] * vcom[2]); |
223 | – | p_local[3] += molmass * (vcom[1] * vcom[0]); |
224 | – | p_local[4] += molmass * (vcom[1] * vcom[1]); |
225 | – | p_local[5] += molmass * (vcom[1] * vcom[2]); |
226 | – | p_local[6] += molmass * (vcom[2] * vcom[0]); |
227 | – | p_local[7] += molmass * (vcom[2] * vcom[1]); |
228 | – | p_local[8] += molmass * (vcom[2] * vcom[2]); |
229 | – | |
230 | – | } |
231 | – | |
232 | – | // Get total for entire system from MPI. |
233 | – | |
204 | #ifdef IS_MPI | |
205 | < | MPI_Allreduce(p_local,p_global,9,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); |
205 | > | MPI_Allreduce(p_local.getArrayPointer(), p_global.getArrayPointer(), 9, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); |
206 | #else | |
207 | < | for (i=0; i<9; i++) { |
238 | < | p_global[i] = p_local[i]; |
239 | < | } |
207 | > | p_global = p_local; |
208 | #endif // is_mpi | |
209 | ||
210 | < | volume = this->getVolume(); |
210 | > | double volume = this->getVolume(); |
211 | > | Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot(); |
212 | > | Mat3x3d tau = curSnapshot->statData.getTau(); |
213 | ||
214 | + | pressureTensor = (p_global + OOPSEConstant::energyConvert* tau)/volume; |
215 | ||
216 | < | |
246 | < | for(i = 0; i < 3; i++) { |
247 | < | for (j = 0; j < 3; j++) { |
248 | < | k = 3*i + j; |
249 | < | press[i][j] = (p_global[k] + info->tau[k]*e_convert) / volume; |
250 | < | } |
216 | > | return pressureTensor; |
217 | } | |
252 | – | } |
218 | ||
219 | < | void Thermo::velocitize() { |
220 | < | |
221 | < | double aVel[3], aJ[3], I[3][3]; |
257 | < | int i, j, l, m, n, vr, vd; // velocity randomizer loop counters |
258 | < | double vdrift[3]; |
259 | < | double vbar; |
260 | < | const double kb = 8.31451e-7; // kb in amu, angstroms, fs, etc. |
261 | < | double av2; |
262 | < | double kebar; |
263 | < | double temperature; |
264 | < | int nobj; |
265 | < | |
266 | < | if (!info->have_target_temp) { |
267 | < | sprintf( painCave.errMsg, |
268 | < | "You can't resample the velocities without a targetTemp!\n" |
269 | < | ); |
270 | < | painCave.isFatal = 1; |
271 | < | painCave.severity = OOPSE_ERROR; |
272 | < | simError(); |
273 | < | return; |
274 | < | } |
275 | < | |
276 | < | nobj = info->integrableObjects.size(); |
277 | < | |
278 | < | temperature = info->target_temp; |
279 | < | |
280 | < | kebar = kb * temperature * (double)info->ndfRaw / |
281 | < | ( 2.0 * (double)info->ndf ); |
282 | < | |
283 | < | for(vr = 0; vr < nobj; vr++){ |
219 | > | void Thermo::saveStat(){ |
220 | > | Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot(); |
221 | > | Stats& stat = currSnapshot->statData; |
222 | ||
223 | < | // uses equipartition theory to solve for vbar in angstrom/fs |
223 | > | stat[Stats::KINETIC_ENERGY] = getKinetic(); |
224 | > | stat[Stats::POTENTIAL_ENERGY] = getPotential(); |
225 | > | stat[Stats::TOTAL_ENERGY] = stat[Stats::KINETIC_ENERGY] + stat[Stats::POTENTIAL_ENERGY] ; |
226 | > | stat[Stats::TEMPERATURE] = getTemperature(); |
227 | > | stat[Stats::PRESSURE] = getPressure(); |
228 | > | stat[Stats::VOLUME] = getVolume(); |
229 | ||
230 | < | av2 = 2.0 * kebar / info->integrableObjects[vr]->getMass(); |
231 | < | vbar = sqrt( av2 ); |
230 | > | Mat3x3d tensor =getPressureTensor(); |
231 | > | stat[Stats::PRESSURE_TENSOR_X] = tensor(0, 0); |
232 | > | stat[Stats::PRESSURE_TENSOR_Y] = tensor(1, 1); |
233 | > | stat[Stats::PRESSURE_TENSOR_Z] = tensor(2, 2); |
234 | ||
290 | – | // picks random velocities from a gaussian distribution |
291 | – | // centered on vbar |
235 | ||
236 | < | for (j=0; j<3; j++) |
237 | < | aVel[j] = vbar * gaussStream->getGaussian(); |
236 | > | /**@todo need refactorying*/ |
237 | > | //Conserved Quantity is set by integrator and time is set by setTime |
238 | ||
296 | – | info->integrableObjects[vr]->setVel( aVel ); |
297 | – | |
298 | – | if(info->integrableObjects[vr]->isDirectional()){ |
299 | – | |
300 | – | info->integrableObjects[vr]->getI( I ); |
301 | – | |
302 | – | if (info->integrableObjects[vr]->isLinear()) { |
303 | – | |
304 | – | l= info->integrableObjects[vr]->linearAxis(); |
305 | – | m = (l+1)%3; |
306 | – | n = (l+2)%3; |
307 | – | |
308 | – | aJ[l] = 0.0; |
309 | – | vbar = sqrt( 2.0 * kebar * I[m][m] ); |
310 | – | aJ[m] = vbar * gaussStream->getGaussian(); |
311 | – | vbar = sqrt( 2.0 * kebar * I[n][n] ); |
312 | – | aJ[n] = vbar * gaussStream->getGaussian(); |
313 | – | |
314 | – | } else { |
315 | – | for (j = 0 ; j < 3; j++) { |
316 | – | vbar = sqrt( 2.0 * kebar * I[j][j] ); |
317 | – | aJ[j] = vbar * gaussStream->getGaussian(); |
318 | – | } |
319 | – | } // else isLinear |
320 | – | |
321 | – | info->integrableObjects[vr]->setJ( aJ ); |
322 | – | |
323 | – | }//isDirectional |
324 | – | |
239 | } | |
240 | ||
241 | < | // Get the Center of Mass drift velocity. |
328 | < | |
329 | < | getCOMVel(vdrift); |
330 | < | |
331 | < | // Corrects for the center of mass drift. |
332 | < | // sums all the momentum and divides by total mass. |
333 | < | |
334 | < | for(vd = 0; vd < nobj; vd++){ |
335 | < | |
336 | < | info->integrableObjects[vd]->getVel(aVel); |
337 | < | |
338 | < | for (j=0; j < 3; j++) |
339 | < | aVel[j] -= vdrift[j]; |
340 | < | |
341 | < | info->integrableObjects[vd]->setVel( aVel ); |
342 | < | } |
343 | < | |
344 | < | } |
345 | < | |
346 | < | void Thermo::getCOMVel(double vdrift[3]){ |
347 | < | |
348 | < | double mtot, mtot_local; |
349 | < | double aVel[3], amass; |
350 | < | double vdrift_local[3]; |
351 | < | int vd, j; |
352 | < | int nobj; |
353 | < | |
354 | < | nobj = info->integrableObjects.size(); |
355 | < | |
356 | < | mtot_local = 0.0; |
357 | < | vdrift_local[0] = 0.0; |
358 | < | vdrift_local[1] = 0.0; |
359 | < | vdrift_local[2] = 0.0; |
360 | < | |
361 | < | for(vd = 0; vd < nobj; vd++){ |
362 | < | |
363 | < | amass = info->integrableObjects[vd]->getMass(); |
364 | < | info->integrableObjects[vd]->getVel( aVel ); |
365 | < | |
366 | < | for(j = 0; j < 3; j++) |
367 | < | vdrift_local[j] += aVel[j] * amass; |
368 | < | |
369 | < | mtot_local += amass; |
370 | < | } |
371 | < | |
372 | < | #ifdef IS_MPI |
373 | < | MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
374 | < | MPI_Allreduce(vdrift_local,vdrift,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
375 | < | #else |
376 | < | mtot = mtot_local; |
377 | < | for(vd = 0; vd < 3; vd++) { |
378 | < | vdrift[vd] = vdrift_local[vd]; |
379 | < | } |
380 | < | #endif |
381 | < | |
382 | < | for (vd = 0; vd < 3; vd++) { |
383 | < | vdrift[vd] = vdrift[vd] / mtot; |
384 | < | } |
385 | < | |
386 | < | } |
387 | < | |
388 | < | void Thermo::getCOM(double COM[3]){ |
389 | < | |
390 | < | double mtot, mtot_local; |
391 | < | double aPos[3], amass; |
392 | < | double COM_local[3]; |
393 | < | int i, j; |
394 | < | int nobj; |
395 | < | |
396 | < | mtot_local = 0.0; |
397 | < | COM_local[0] = 0.0; |
398 | < | COM_local[1] = 0.0; |
399 | < | COM_local[2] = 0.0; |
400 | < | |
401 | < | nobj = info->integrableObjects.size(); |
402 | < | for(i = 0; i < nobj; i++){ |
403 | < | |
404 | < | amass = info->integrableObjects[i]->getMass(); |
405 | < | info->integrableObjects[i]->getPos( aPos ); |
406 | < | |
407 | < | for(j = 0; j < 3; j++) |
408 | < | COM_local[j] += aPos[j] * amass; |
409 | < | |
410 | < | mtot_local += amass; |
411 | < | } |
412 | < | |
413 | < | #ifdef IS_MPI |
414 | < | MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
415 | < | MPI_Allreduce(COM_local,COM,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
416 | < | #else |
417 | < | mtot = mtot_local; |
418 | < | for(i = 0; i < 3; i++) { |
419 | < | COM[i] = COM_local[i]; |
420 | < | } |
421 | < | #endif |
422 | < | |
423 | < | for (i = 0; i < 3; i++) { |
424 | < | COM[i] = COM[i] / mtot; |
425 | < | } |
426 | < | } |
427 | < | |
428 | < | void Thermo::removeCOMdrift() { |
429 | < | double vdrift[3], aVel[3]; |
430 | < | int vd, j, nobj; |
431 | < | |
432 | < | nobj = info->integrableObjects.size(); |
433 | < | |
434 | < | // Get the Center of Mass drift velocity. |
435 | < | |
436 | < | getCOMVel(vdrift); |
437 | < | |
438 | < | // Corrects for the center of mass drift. |
439 | < | // sums all the momentum and divides by total mass. |
440 | < | |
441 | < | for(vd = 0; vd < nobj; vd++){ |
442 | < | |
443 | < | info->integrableObjects[vd]->getVel(aVel); |
444 | < | |
445 | < | for (j=0; j < 3; j++) |
446 | < | aVel[j] -= vdrift[j]; |
447 | < | |
448 | < | info->integrableObjects[vd]->setVel( aVel ); |
449 | < | } |
450 | < | } |
241 | > | } //end namespace oopse |
– | Removed lines |
+ | Added lines |
< | Changed lines |
> | Changed lines |