source: src/atom.cpp@ 4a7776a

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 4a7776a was 4a7776a, checked in by Frederik Heber <heber@…>, 16 years ago

Complete refactoring of molecule_dynamics.cpp

  • Property mode set to 100644
File size: 17.9 KB
Line 
1/** \file atom.cpp
2 *
3 * Function implementations for the class atom.
4 *
5 */
6
7#include "atom.hpp"
8#include "bond.hpp"
9#include "config.hpp"
10#include "element.hpp"
11#include "memoryallocator.hpp"
12#include "parser.hpp"
13#include "vector.hpp"
14
15/************************************* Functions for class atom *************************************/
16
17/** Constructor of class atom.
18 */
19atom::atom()
20{
21 father = this; // generally, father is itself
22 previous = NULL;
23 next = NULL;
24 Ancestor = NULL;
25 type = NULL;
26 sort = NULL;
27 FixedIon = 0;
28 GraphNr = -1;
29 ComponentNr = NULL;
30 IsCyclic = false;
31 SeparationVertex = false;
32 LowpointNr = -1;
33 AdaptiveOrder = 0;
34 MaxOrder = false;
35 // set LCNode::Vector to our Vector
36 node = &x;
37};
38
39/** Constructor of class atom.
40 */
41atom::atom(atom *pointer)
42{
43 Name = NULL;
44 previous = NULL;
45 next = NULL;
46 father = pointer; // generally, father is itself
47 Ancestor = NULL;
48 GraphNr = -1;
49 ComponentNr = NULL;
50 IsCyclic = false;
51 SeparationVertex = false;
52 LowpointNr = -1;
53 AdaptiveOrder = 0;
54 MaxOrder = false;
55 type = pointer->type; // copy element of atom
56 x.CopyVector(&pointer->x); // copy coordination
57 v.CopyVector(&pointer->v); // copy velocity
58 FixedIon = pointer->FixedIon;
59 nr = -1;
60 sort = &nr;
61 node = &x;
62}
63
64
65/** Destructor of class atom.
66 */
67atom::~atom()
68{
69 Free<int>(&ComponentNr, "atom::~atom: *ComponentNr");
70 Free<char>(&Name, "atom::~atom: *Name");
71 Trajectory.R.clear();
72 Trajectory.U.clear();
73 Trajectory.F.clear();
74};
75
76
77/** Climbs up the father list until NULL, last is returned.
78 * \return true father, i.e. whose father points to itself, NULL if it could not be found or has none (added hydrogen)
79 */
80atom *atom::GetTrueFather()
81{
82 atom *walker = this;
83 do {
84 if (walker == walker->father) // top most father is the one that points on itself
85 break;
86 walker = walker->father;
87 } while (walker != NULL);
88 return walker;
89};
90
91/** Sets father to itself or its father in case of copying a molecule.
92 */
93void atom::CorrectFather()
94{
95 if (father->father == father) // same atom in copy's father points to itself
96 father = this; // set father to itself (copy of a whole molecule)
97 else
98 father = father->father; // set father to original's father
99
100};
101
102/** Check whether father is equal to given atom.
103 * \param *ptr atom to compare father to
104 * \param **res return value (only set if atom::father is equal to \a *ptr)
105 */
106void atom::EqualsFather ( atom *ptr, atom **res )
107{
108 if ( ptr == father )
109 *res = this;
110};
111
112/** Checks whether atom is within the given box.
113 * \param offset offset to box origin
114 * \param *parallelepiped box matrix
115 * \return true - is inside, false - is not
116 */
117bool atom::IsInParallelepiped(Vector offset, double *parallelepiped)
118{
119 return (node->IsInParallelepiped(offset, parallelepiped));
120};
121
122/** Output of a single atom.
123 * \param ElementNo cardinal number of the element
124 * \param AtomNo cardinal number among these atoms of the same element
125 * \param *out stream to output to
126 * \param *comment commentary after '#' sign
127 * \return true - \a *out present, false - \a *out is NULL
128 */
129bool atom::Output(ofstream *out, int ElementNo, int AtomNo, const char *comment) const
130{
131 if (out != NULL) {
132 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint;
133 *out << x.x[0] << "\t" << x.x[1] << "\t" << x.x[2];
134 *out << "\t" << FixedIon;
135 if (v.Norm() > MYEPSILON)
136 *out << "\t" << scientific << setprecision(6) << v.x[0] << "\t" << v.x[1] << "\t" << v.x[2] << "\t";
137 if (comment != NULL)
138 *out << " # " << comment << endl;
139 else
140 *out << " # molecule nr " << nr << endl;
141 return true;
142 } else
143 return false;
144};
145bool atom::Output(ofstream *out, int *ElementNo, int *AtomNo, const char *comment)
146{
147 AtomNo[type->Z]++; // increment number
148 if (out != NULL) {
149 *out << "Ion_Type" << ElementNo[type->Z] << "_" << AtomNo[type->Z] << "\t" << fixed << setprecision(9) << showpoint;
150 *out << x.x[0] << "\t" << x.x[1] << "\t" << x.x[2];
151 *out << "\t" << FixedIon;
152 if (v.Norm() > MYEPSILON)
153 *out << "\t" << scientific << setprecision(6) << v.x[0] << "\t" << v.x[1] << "\t" << v.x[2] << "\t";
154 if (comment != NULL)
155 *out << " # " << comment << endl;
156 else
157 *out << " # molecule nr " << nr << endl;
158 return true;
159 } else
160 return false;
161};
162
163/** Output of a single atom as one lin in xyz file.
164 * \param *out stream to output to
165 * \return true - \a *out present, false - \a *out is NULL
166 */
167bool atom::OutputXYZLine(ofstream *out) const
168{
169 if (out != NULL) {
170 *out << type->symbol << "\t" << x.x[0] << "\t" << x.x[1] << "\t" << x.x[2] << "\t" << endl;
171 return true;
172 } else
173 return false;
174};
175
176/** Output of a single atom as one lin in xyz file.
177 * \param *out stream to output to
178 * \param *ElementNo array with ion type number in the config file this atom's element shall have
179 * \param *AtomNo array with atom number in the config file this atom shall have, is increase by one automatically
180 * \param step Trajectory time step to output
181 * \return true - \a *out present, false - \a *out is NULL
182 */
183bool atom::OutputTrajectory(ofstream *out, int *ElementNo, int *AtomNo, int step) const
184{
185 AtomNo[type->Z]++;
186 if (out != NULL) {
187 *out << "Ion_Type" << ElementNo[type->Z] << "_" << AtomNo[type->Z] << "\t" << fixed << setprecision(9) << showpoint;
188 *out << Trajectory.R.at(step).x[0] << "\t" << Trajectory.R.at(step).x[1] << "\t" << Trajectory.R.at(step).x[2];
189 *out << "\t" << FixedIon;
190 if (Trajectory.U.at(step).Norm() > MYEPSILON)
191 *out << "\t" << scientific << setprecision(6) << Trajectory.U.at(step).x[0] << "\t" << Trajectory.U.at(step).x[1] << "\t" << Trajectory.U.at(step).x[2] << "\t";
192 if (Trajectory.F.at(step).Norm() > MYEPSILON)
193 *out << "\t" << scientific << setprecision(6) << Trajectory.F.at(step).x[0] << "\t" << Trajectory.F.at(step).x[1] << "\t" << Trajectory.F.at(step).x[2] << "\t";
194 *out << "\t# Number in molecule " << nr << endl;
195 return true;
196 } else
197 return false;
198};
199
200/** Output of a single atom as one lin in xyz file.
201 * \param *out stream to output to
202 * \param step Trajectory time step to output
203 * \return true - \a *out present, false - \a *out is NULL
204 */
205bool atom::OutputTrajectoryXYZ(ofstream *out, int step) const
206{
207 if (out != NULL) {
208 *out << type->symbol << "\t";
209 *out << Trajectory.R.at(step).x[0] << "\t";
210 *out << Trajectory.R.at(step).x[1] << "\t";
211 *out << Trajectory.R.at(step).x[2] << endl;
212 return true;
213 } else
214 return false;
215};
216
217/** Prints all bonds of this atom from given global lists.
218 * \param *out stream to output to
219 * \param *NumberOfBondsPerAtom array with number of bonds per atomic index
220 * \param ***ListOfBondsPerAtom array per atomic index of array with pointer to bond
221 * \return true - \a *out present, false - \a *out is NULL
222 */
223bool atom::OutputBondOfAtom(ofstream *out, int *NumberOfBondsPerAtom, bond ***ListOfBondsPerAtom) const
224{
225 if (out != NULL) {
226#ifdef ADDHYDROGEN
227 if (type->Z != 1) { // regard only non-hydrogen
228#endif
229 *out << Verbose(4) << "Atom " << Name << "/" << nr << " with " << NumberOfBondsPerAtom[nr] << " bonds: ";
230 int TotalDegree = 0;
231 for (int j=0;j<NumberOfBondsPerAtom[nr];j++) {
232 *out << *ListOfBondsPerAtom[nr][j] << "\t";
233 TotalDegree += ListOfBondsPerAtom[nr][j]->BondDegree;
234 }
235 *out << " -- TotalDegree: " << TotalDegree << endl;
236#ifdef ADDHYDROGEN
237 }
238#endif
239 return true;
240 } else
241 return false;
242};
243
244ostream & operator << (ostream &ost, const atom &a)
245{
246 ost << "[" << a.Name << "|" << &a << "]";
247 return ost;
248};
249
250ostream & atom::operator << (ostream &ost)
251{
252 ost << "[" << Name << "|" << this << "]";
253 return ost;
254};
255
256/** Compares the indices of \a this atom with a given \a ptr.
257 * \param ptr atom to compare index against
258 * \return true - this one's is smaller, false - not
259 */
260bool atom::Compare(const atom &ptr)
261{
262 if (nr < ptr.nr)
263 return true;
264 else
265 return false;
266};
267
268/** Extends the trajectory STL vector to the new size.
269 * Does nothing if \a MaxSteps is smaller than current size.
270 * \param MaxSteps
271 */
272void atom::ResizeTrajectory(int MaxSteps)
273{
274 if (Trajectory.R.size() <= (unsigned int)(MaxSteps)) {
275 //cout << "Increasing size for trajectory array of " << keyword << " to " << (MaxSteps+1) << "." << endl;
276 Trajectory.R.resize(MaxSteps+1);
277 Trajectory.U.resize(MaxSteps+1);
278 Trajectory.F.resize(MaxSteps+1);
279 }
280};
281
282/** Copies a given trajectory step \a src onto another \a dest
283 * \param dest index of destination step
284 * \param src index of source step
285 */
286void atom::CopyStepOnStep(int dest, int src)
287{
288 if (dest == src) // self assignment check
289 return;
290
291 for (int n=NDIM;n--;) {
292 Trajectory.R.at(dest).x[n] = Trajectory.R.at(src).x[n];
293 Trajectory.U.at(dest).x[n] = Trajectory.U.at(src).x[n];
294 Trajectory.F.at(dest).x[n] = Trajectory.F.at(src).x[n];
295 }
296};
297
298/** Performs a velocity verlet update of the trajectory.
299 * Parameters are according to those in configuration class.
300 * \param NextStep index of sequential step to set
301 * \param *configuration pointer to configuration with parameters
302 * \param *Force matrix with forces
303 */
304void atom::VelocityVerletUpdate(int NextStep, config *configuration, ForceMatrix *Force)
305{
306 //a = configuration.Deltat*0.5/walker->type->mass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a
307 for (int d=0; d<NDIM; d++) {
308 Trajectory.F.at(NextStep).x[d] = -Force->Matrix[0][nr][d+5]*(configuration->GetIsAngstroem() ? AtomicLengthToAngstroem : 1.);
309 Trajectory.R.at(NextStep).x[d] = Trajectory.R.at(NextStep-1).x[d];
310 Trajectory.R.at(NextStep).x[d] += configuration->Deltat*(Trajectory.U.at(NextStep-1).x[d]); // s(t) = s(0) + v * deltat + 1/2 a * deltat^2
311 Trajectory.R.at(NextStep).x[d] += 0.5*configuration->Deltat*configuration->Deltat*(Trajectory.F.at(NextStep).x[d]/type->mass); // F = m * a and s = 0.5 * F/m * t^2 = F * a * t
312 }
313 // Update U
314 for (int d=0; d<NDIM; d++) {
315 Trajectory.U.at(NextStep).x[d] = Trajectory.U.at(NextStep-1).x[d];
316 Trajectory.U.at(NextStep).x[d] += configuration->Deltat * (Trajectory.F.at(NextStep).x[d]+Trajectory.F.at(NextStep-1).x[d]/type->mass); // v = F/m * t
317 }
318 // Update R (and F)
319// out << "Integrated position&velocity of step " << (NextStep) << ": (";
320// for (int d=0;d<NDIM;d++)
321// out << Trajectory.R.at(NextStep).x[d] << " "; // next step
322// out << ")\t(";
323// for (int d=0;d<NDIM;d++)
324// cout << Trajectory.U.at(NextStep).x[d] << " "; // next step
325// out << ")" << endl;
326};
327
328/** Sums up mass and kinetics.
329 * \param Step step to sum for
330 * \param *TotalMass pointer to total mass sum
331 * \param *TotalVelocity pointer to tota velocity sum
332 */
333void atom::SumUpKineticEnergy( int Step, double *TotalMass, Vector *TotalVelocity )
334{
335 *TotalMass += type->mass; // sum up total mass
336 for(int d=0;d<NDIM;d++) {
337 TotalVelocity->x[d] += Trajectory.U.at(Step).x[d]*type->mass;
338 }
339};
340
341/** Returns squared distance to a given vector.
342 * \param origin vector to calculate distance to
343 * \return distance squared
344 */
345double atom::DistanceSquaredToVector(Vector &origin)
346{
347 return origin.DistanceSquared(&x);
348};
349
350/** Adds kinetic energy of this atom to given temperature value.
351 * \param *temperature add on this value
352 * \param step given step of trajectory to add
353 */
354void atom::AddKineticToTemperature(double *temperature, int step) const
355{
356 for (int i=NDIM;i--;)
357 *temperature += type->mass * Trajectory.U.at(step).x[i]* Trajectory.U.at(step).x[i];
358};
359
360/** Returns distance to a given vector.
361 * \param origin vector to calculate distance to
362 * \return distance
363 */
364double atom::DistanceToVector(Vector &origin)
365{
366 return origin.Distance(&x);
367};
368
369bool operator < (atom &a, atom &b)
370{
371 return a.Compare(b);
372};
373
374/** Evaluates some constraint potential if atom moves from \a startstep at once to \endstep in trajectory.
375 * \param startstep trajectory begins at
376 * \param endstep trajectory ends at
377 * \param **PermutationMap if atom switches places with some other atom, there is no translation but a permutaton noted here (not in the trajectories of each).
378 * \param *Force Force matrix to store result in
379 */
380void atom::EvaluateConstrainedForce(int startstep, int endstep, atom **PermutationMap, ForceMatrix *Force)
381{
382 double constant = 10.;
383 atom *Sprinter = PermutationMap[nr];
384 // set forces
385 for (int i=NDIM;i++;)
386 Force->Matrix[0][nr][5+i] += 2.*constant*sqrt(Trajectory.R.at(startstep).Distance(&Sprinter->Trajectory.R.at(endstep)));
387};
388
389/** Correct velocity against the summed \a CoGVelocity for \a step.
390 * \param *ActualTemp sum up actual temperature meanwhile
391 * \param Step MD step in atom::Tracjetory
392 * \param *CoGVelocity remnant velocity (i.e. vector sum of all atom velocities)
393 */
394void atom::CorrectVelocity(double *ActualTemp, int Step, Vector *CoGVelocity)
395{
396 for(int d=0;d<NDIM;d++) {
397 Trajectory.U.at(Step).x[d] -= CoGVelocity->x[d];
398 *ActualTemp += 0.5 * type->mass * Trajectory.U.at(Step).x[d] * Trajectory.U.at(Step).x[d];
399 }
400};
401
402/** Scales velocity of atom according to Woodcock thermostat.
403 * \param ScaleTempFactor factor to scale the velocities with (i.e. sqrt of energy scale factor)
404 * \param Step MD step to scale
405 * \param *ekin sum of kinetic energy
406 */
407void atom::Thermostat_Woodcock(double ScaleTempFactor, int Step, double *ekin)
408{
409 double *U = Trajectory.U.at(Step).x;
410 if (FixedIon == 0) // even FixedIon moves, only not by other's forces
411 for (int d=0; d<NDIM; d++) {
412 U[d] *= ScaleTempFactor;
413 *ekin += 0.5*type->mass * U[d]*U[d];
414 }
415};
416
417/** Scales velocity of atom according to Gaussian thermostat.
418 * \param Step MD step to scale
419 * \param *G
420 * \param *E
421 */
422void atom::Thermostat_Gaussian_init(int Step, double *G, double *E)
423{
424 double *U = Trajectory.U.at(Step).x;
425 double *F = Trajectory.F.at(Step).x;
426 if (FixedIon == 0) // even FixedIon moves, only not by other's forces
427 for (int d=0; d<NDIM; d++) {
428 *G += U[d] * F[d];
429 *E += U[d]*U[d]*type->mass;
430 }
431};
432
433/** Determines scale factors according to Gaussian thermostat.
434 * \param Step MD step to scale
435 * \param GE G over E ratio
436 * \param *ekin sum of kinetic energy
437 * \param *configuration configuration class with TempFrequency and TargetTemp
438 */
439void atom::Thermostat_Gaussian_least_constraint(int Step, double G_over_E, double *ekin, config *configuration)
440{
441 double *U = Trajectory.U.at(Step).x;
442 if (FixedIon == 0) // even FixedIon moves, only not by other's forces
443 for (int d=0; d<NDIM; d++) {
444 U[d] += configuration->Deltat/type->mass * ( (G_over_E) * (U[d]*type->mass) );
445 *ekin += type->mass * U[d]*U[d];
446 }
447};
448
449/** Scales velocity of atom according to Langevin thermostat.
450 * \param Step MD step to scale
451 * \param *r random number generator
452 * \param *ekin sum of kinetic energy
453 * \param *configuration configuration class with TempFrequency and TargetTemp
454 */
455void atom::Thermostat_Langevin(int Step, gsl_rng * r, double *ekin, config *configuration)
456{
457 double sigma = sqrt(configuration->TargetTemp/type->mass); // sigma = (k_b T)/m (Hartree/atomicmass = atomiclength/atomictime)
458 double *U = Trajectory.U.at(Step).x;
459 if (FixedIon == 0) { // even FixedIon moves, only not by other's forces
460 // throw a dice to determine whether it gets hit by a heat bath particle
461 if (((((rand()/(double)RAND_MAX))*configuration->TempFrequency) < 1.)) {
462 cout << Verbose(3) << "Particle " << *this << " was hit (sigma " << sigma << "): " << sqrt(U[0]*U[0]+U[1]*U[1]+U[2]*U[2]) << " -> ";
463 // pick three random numbers from a Boltzmann distribution around the desired temperature T for each momenta axis
464 for (int d=0; d<NDIM; d++) {
465 U[d] = gsl_ran_gaussian (r, sigma);
466 }
467 cout << sqrt(U[0]*U[0]+U[1]*U[1]+U[2]*U[2]) << endl;
468 }
469 for (int d=0; d<NDIM; d++)
470 *ekin += 0.5*type->mass * U[d]*U[d];
471 }
472};
473
474/** Scales velocity of atom according to Berendsen thermostat.
475 * \param Step MD step to scale
476 * \param ScaleTempFactor factor to scale energy (not velocity!) with
477 * \param *ekin sum of kinetic energy
478 * \param *configuration configuration class with TempFrequency and Deltat
479 */
480void atom::Thermostat_Berendsen(int Step, double ScaleTempFactor, double *ekin, config *configuration)
481{
482 double *U = Trajectory.U.at(Step).x;
483 if (FixedIon == 0) { // even FixedIon moves, only not by other's forces
484 for (int d=0; d<NDIM; d++) {
485 U[d] *= sqrt(1+(configuration->Deltat/configuration->TempFrequency)*(ScaleTempFactor-1));
486 *ekin += 0.5*type->mass * U[d]*U[d];
487 }
488 }
489};
490
491/** Initializes current run of NoseHoover thermostat.
492 * \param Step MD step to scale
493 * \param *delta_alpha additional sum of kinetic energy on return
494 */
495void atom::Thermostat_NoseHoover_init(int Step, double *delta_alpha)
496{
497 double *U = Trajectory.U.at(Step).x;
498 if (FixedIon == 0) { // even FixedIon moves, only not by other's forces
499 for (int d=0; d<NDIM; d++) {
500 *delta_alpha += U[d]*U[d]*type->mass;
501 }
502 }
503};
504
505/** Initializes current run of NoseHoover thermostat.
506 * \param Step MD step to scale
507 * \param *ekin sum of kinetic energy
508 * \param *configuration configuration class with TempFrequency and Deltat
509 */
510void atom::Thermostat_NoseHoover_scale(int Step, double *ekin, config *configuration)
511{
512 double *U = Trajectory.U.at(Step).x;
513 if (FixedIon == 0) { // even FixedIon moves, only not by other's forces
514 for (int d=0; d<NDIM; d++) {
515 U[d] += configuration->Deltat/type->mass * (configuration->alpha * (U[d] * type->mass));
516 *ekin += (0.5*type->mass) * U[d]*U[d];
517 }
518 }
519};
Note: See TracBrowser for help on using the repository browser.