ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/ZConstraint.cpp
Revision: 693
Committed: Wed Aug 13 19:21:53 2003 UTC (20 years, 10 months ago) by tim
File size: 23205 byte(s)
Log Message:
harmonic potential & z-contraint method

File Contents

# Content
1 #include "Integrator.hpp"
2 #include "simError.h"
3 #include <cmath>
4 template<typename T> ZConstraint<T>::ZConstraint(SimInfo* theInfo, ForceFields* the_ff)
5 : T(theInfo, the_ff), fz(NULL),
6 indexOfZConsMols(NULL)
7 {
8
9 //get properties from SimInfo
10 GenericData* data;
11 ZConsParaData* zConsParaData;
12 DoubleData* sampleTime;
13 DoubleData* tolerance;
14 StringData* filename;
15 double COM[3];
16
17 //by default, the direction of constraint is z
18 // 0 --> x
19 // 1 --> y
20 // 2 --> z
21 whichDirection = 2;
22
23 //estimate the force constant of harmonical potential
24 double Kb = 1.986E-3 ; //in kcal/K
25
26 double halfOfLargestBox = max(info->boxL[0], max(info->boxL[1], info->boxL[2])) /2;
27 zForceConst = Kb * info->target_temp /(halfOfLargestBox * halfOfLargestBox);
28
29 //retrieve sample time of z-contraint
30 data = info->getProperty(ZCONSTIME_ID);
31
32 if(!data) {
33
34 sprintf( painCave.errMsg,
35 "ZConstraint error: If you use an ZConstraint\n"
36 " , you must set sample time.\n");
37 painCave.isFatal = 1;
38 simError();
39 }
40 else{
41
42 sampleTime = dynamic_cast<DoubleData*>(data);
43
44 if(!sampleTime){
45
46 sprintf( painCave.errMsg,
47 "ZConstraint error: Can not get property from SimInfo\n");
48 painCave.isFatal = 1;
49 simError();
50
51 }
52 else{
53 this->zconsTime = sampleTime->getData();
54 }
55
56 }
57
58 //retrieve output filename of z force
59 data = info->getProperty(ZCONSFILENAME_ID);
60 if(!data) {
61
62
63 sprintf( painCave.errMsg,
64 "ZConstraint error: If you use an ZConstraint\n"
65 " , you must set output filename of z-force.\n");
66 painCave.isFatal = 1;
67 simError();
68
69 }
70 else{
71
72 filename = dynamic_cast<StringData*>(data);
73
74 if(!filename){
75
76 sprintf( painCave.errMsg,
77 "ZConstraint error: Can not get property from SimInfo\n");
78 painCave.isFatal = 1;
79 simError();
80
81 }
82 else{
83 this->zconsOutput = filename->getData();
84 }
85
86
87 }
88
89 //retrieve tolerance for z-constraint molecuels
90 data = info->getProperty(ZCONSTOL_ID);
91
92 if(!data) {
93
94 sprintf( painCave.errMsg,
95 "ZConstraint error: can not get tolerance \n");
96 painCave.isFatal = 1;
97 simError();
98 }
99 else{
100
101 tolerance = dynamic_cast<DoubleData*>(data);
102
103 if(!tolerance){
104
105 sprintf( painCave.errMsg,
106 "ZConstraint error: Can not get property from SimInfo\n");
107 painCave.isFatal = 1;
108 simError();
109
110 }
111 else{
112 this->zconsTol = tolerance->getData();
113 }
114
115 }
116
117 //retrieve index of z-constraint molecules
118 data = info->getProperty(ZCONSPARADATA_ID);
119 if(!data) {
120
121 sprintf( painCave.errMsg,
122 "ZConstraint error: If you use an ZConstraint\n"
123 " , you must set index of z-constraint molecules.\n");
124 painCave.isFatal = 1;
125 simError();
126 }
127 else{
128
129 zConsParaData = dynamic_cast<ZConsParaData*>(data);
130
131 if(!zConsParaData){
132
133 sprintf( painCave.errMsg,
134 "ZConstraint error: Can not get parameters of zconstraint method from SimInfo\n");
135 painCave.isFatal = 1;
136 simError();
137
138 }
139 else{
140
141 parameters = zConsParaData->getData();
142
143 //check the range of zconsIndex
144 //and the minimum value of index is the first one (we already sorted the data)
145 //the maximum value of index is the last one
146
147 int maxIndex;
148 int minIndex;
149 int totalNumMol;
150
151 minIndex = (*parameters)[0].zconsIndex;
152 if(minIndex < 0){
153 sprintf( painCave.errMsg,
154 "ZConstraint error: index is out of range\n");
155 painCave.isFatal = 1;
156 simError();
157 }
158
159 maxIndex = (*parameters)[parameters->size() - 1].zconsIndex;
160
161 #ifndef IS_MPI
162 totalNumMol = nMols;
163 #else
164 totalNumMol = mpiSim->getTotNmol();
165 #endif
166
167 if(maxIndex > totalNumMol - 1){
168 sprintf( painCave.errMsg,
169 "ZConstraint error: index is out of range\n");
170 painCave.isFatal = 1;
171 simError();
172 }
173
174 //if user does not specify the zpos for the zconstraint molecule
175 //its initial z coordinate will be used as default
176 for(int i = 0; i < parameters->size(); i++){
177
178 if(!(*parameters)[i].havingZPos){
179
180 #ifndef IS_MPI
181 for(int j = 0; j < nMols; j++){
182 if (molecules[j].getGlobalIndex() == (*parameters)[i].zconsIndex){
183 molecules[j].getCOM(COM);
184 break;
185 }
186 }
187 #else
188 //query which processor current zconstraint molecule belongs to
189 int *MolToProcMap;
190 int whichNode;
191 double initZPos;
192 MolToProcMap = mpiSim->getMolToProcMap();
193 whichNode = MolToProcMap[(*parameters)[i].zconsIndex];
194
195 //broadcast the zpos of current z-contraint molecule
196 //the node which contain this
197
198 if (worldRank == whichNode ){
199
200 for(int j = 0; j < nMols; j++)
201 if (molecules[j].getGlobalIndex() == (*parameters)[i].zconsIndex){
202 molecules[j].getCOM(COM);
203 break;
204 }
205
206 }
207
208 MPI_Bcast(&COM[whichDirection], 1, MPI_DOUBLE_PRECISION, whichNode, MPI_COMM_WORLD);
209 #endif
210
211 (*parameters)[i].zPos = COM[whichDirection];
212
213 sprintf( painCave.errMsg,
214 "ZConstraint warningr: Does not specify zpos for z-constraint molecule "
215 "initial z coornidate will be used \n");
216 painCave.isFatal = 0;
217 simError();
218
219 }
220 }
221
222 }//end if (!zConsParaData)
223 }//end if (!data)
224
225 //
226 #ifdef IS_MPI
227 update();
228 #else
229 int searchResult;
230
231 for(int i = 0; i < nMols; i++){
232
233 searchResult = isZConstraintMol(&molecules[i]);
234
235 if(searchResult > -1){
236
237 zconsMols.push_back(&molecules[i]);
238 massOfZConsMols.push_back(molecules[i].getTotalMass());
239
240 zPos.push_back((*parameters)[searchResult].zPos);
241 kz.push_back((*parameters)[searchResult]. kRatio * zForceConst);
242
243 molecules[i].getCOM(COM);
244 }
245 else
246 {
247
248 unconsMols.push_back(&molecules[i]);
249 massOfUnconsMols.push_back(molecules[i].getTotalMass());
250
251 }
252 }
253
254 fz = new double[zconsMols.size()];
255 indexOfZConsMols = new int [zconsMols.size()];
256
257 if(!fz || !indexOfZConsMols){
258 sprintf( painCave.errMsg,
259 "Memory allocation failure in class Zconstraint\n");
260 painCave.isFatal = 1;
261 simError();
262 }
263
264 //determine the states of z-constraint molecules
265 for(int i = 0; i < zconsMols.size(); i++){
266 indexOfZConsMols[i] = zconsMols[i]->getGlobalIndex();
267
268 zconsMols[i]->getCOM(COM);
269 if (fabs(zPos[i] - COM[whichDirection]) < zconsTol)
270 states.push_back(zcsFixed);
271 else
272 states.push_back(zcsMoving);
273 }
274
275 #endif
276
277 //get total masss of unconstraint molecules
278 double totalMassOfUncons_local;
279 totalMassOfUncons_local = 0;
280
281 for(int i = 0; i < unconsMols.size(); i++)
282 totalMassOfUncons_local += unconsMols[i]->getTotalMass();
283
284 #ifndef IS_MPI
285 totalMassOfUncons = totalMassOfUncons_local;
286 #else
287 MPI_Allreduce(&totalMassOfUncons_local, &totalMassOfUncons, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
288 #endif
289
290
291 //get total number of unconstrained atoms
292 int nUnconsAtoms_local;
293 nUnconsAtoms_local = 0;
294 for(int i = 0; i < unconsMols.size(); i++)
295 nUnconsAtoms_local += unconsMols[i]->getNAtoms();
296
297 #ifndef IS_MPI
298 totNumOfUnconsAtoms = nUnconsAtoms_local;
299 #else
300 MPI_Allreduce(&nUnconsAtoms_local, &totNumOfUnconsAtoms, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
301 #endif
302
303 // creat zconsWriter
304 fzOut = new ZConsWriter(zconsOutput.c_str());
305
306 if(!fzOut){
307 sprintf( painCave.errMsg,
308 "Memory allocation failure in class Zconstraint\n");
309 painCave.isFatal = 1;
310 simError();
311 }
312
313 }
314
315 template<typename T> ZConstraint<T>::~ZConstraint()
316 {
317 if(fz)
318 delete[] fz;
319
320 if(indexOfZConsMols)
321 delete[] indexOfZConsMols;
322
323 if(fzOut)
324 delete fzOut;
325 }
326
327 #ifdef IS_MPI
328 template<typename T> void ZConstraint<T>::update()
329 {
330 double COM[3];
331 int index;
332
333 zconsMols.clear();
334 massOfZConsMols.clear();
335 zPos.clear();
336 kz.clear();
337
338 unconsMols.clear();
339 massOfUnconsMols.clear();
340
341
342 //creat zconsMol and unconsMol lists
343 for(int i = 0; i < nMols; i++){
344
345 index = isZConstraintMol(&molecules[i]);
346
347 if(index > -1){
348
349 zconsMols.push_back(&molecules[i]);
350 zPos.push_back((*parameters)[index].zPos);
351 kz.push_back((*parameters)[index].kRatio * zForceConst);
352
353 massOfZConsMols.push_back(molecules[i].getTotalMass());
354
355 molecules[i].getCOM(COM);
356 }
357 else
358 {
359
360 unconsMols.push_back(&molecules[i]);
361 massOfUnconsMols.push_back(molecules[i].getTotalMass());
362
363 }
364 }
365
366 //determine the states of z-constraint molecules
367 for(int i = 0; i < zconsMols.size(); i++){
368 zconsMols[i]->getCOM(COM);
369 if (fabs(zPos[i] - COM[whichDirection]) < zconsTol)
370 states.push_back(zcsFixed);
371 else
372 states.push_back(zcsMoving);
373 }
374
375
376 //The reason to declare fz and indexOfZconsMols as pointer to array is
377 // that we want to make the MPI communication simple
378 if(fz)
379 delete[] fz;
380
381 if(indexOfZConsMols)
382 delete[] indexOfZConsMols;
383
384 if (zconsMols.size() > 0){
385 fz = new double[zconsMols.size()];
386 indexOfZConsMols = new int[zconsMols.size()];
387
388 if(!fz || !indexOfZConsMols){
389 sprintf( painCave.errMsg,
390 "Memory allocation failure in class Zconstraint\n");
391 painCave.isFatal = 1;
392 simError();
393 }
394
395 for(int i = 0; i < zconsMols.size(); i++){
396 indexOfZConsMols[i] = zconsMols[i]->getGlobalIndex();
397 }
398
399 }
400 else{
401 fz = NULL;
402 indexOfZConsMols = NULL;
403 }
404
405 }
406
407 #endif
408
409 /** Function Name: isZConstraintMol
410 ** Parameter
411 ** Molecule* mol
412 ** Return value:
413 ** -1, if the molecule is not z-constraint molecule,
414 ** other non-negative values, its index in indexOfAllZConsMols vector
415 */
416
417 template<typename T> int ZConstraint<T>::isZConstraintMol(Molecule* mol)
418 {
419 int index;
420 int low;
421 int high;
422 int mid;
423
424 index = mol->getGlobalIndex();
425
426 low = 0;
427 high = parameters->size() - 1;
428
429 //Binary Search (we have sorted the array)
430 while(low <= high){
431 mid = (low + high) /2;
432 if ((*parameters)[mid].zconsIndex == index)
433 return mid;
434 else if ((*parameters)[mid].zconsIndex > index )
435 high = mid -1;
436 else
437 low = mid + 1;
438 }
439
440 return -1;
441 }
442
443 template<typename T> void ZConstraint<T>::integrate(){
444
445 //zero out the velocities of center of mass of unconstrained molecules
446 //and the velocities of center of mass of every single z-constrained molecueles
447 zeroOutVel();
448
449 T::integrate();
450
451 }
452
453
454 /**
455 *
456 *
457 *
458 *
459 */
460
461
462 template<typename T> void ZConstraint<T>::calcForce(int calcPot, int calcStress){
463 double zsys;
464
465 T::calcForce(calcPot, calcStress);
466
467 if (checkZConsState())
468 zeroOutVel();
469
470 zsys = calcZSys();
471 cout << "---------------------------------------------------------------------" <<endl;
472 cout << "current time: " << info->getTime() <<"\tcenter of mass at z: " << zsys << endl;
473 cout << "before calcForce, the COMVel of unconstraint molecules is " << calcCOMVel() <<endl;
474
475
476 //do zconstraint force;
477 if (haveFixedZMols())
478 this->doZconstraintForce();
479
480
481
482 //use harmonical poteintial to move the molecules to the specified positions
483 if (haveMovingZMols())
484 this->doHarmonic();
485
486 fzOut->writeFZ(info->getTime(), zconsMols.size(),indexOfZConsMols, fz);
487 cout << "after calcForce, the COMVel of unconstraint molecules is " << calcCOMVel() <<endl;
488 }
489
490 template<typename T> double ZConstraint<T>::calcZSys()
491 {
492 //calculate reference z coordinate for z-constraint molecules
493 double totalMass_local;
494 double totalMass;
495 double totalMZ_local;
496 double totalMZ;
497 double massOfUncons_local;
498 double massOfCurMol;
499 double COM[3];
500
501 totalMass_local = 0;
502 totalMass = 0;
503 totalMZ_local = 0;
504 totalMZ = 0;
505 massOfUncons_local = 0;
506
507
508 for(int i = 0; i < nMols; i++){
509 massOfCurMol = molecules[i].getTotalMass();
510 molecules[i].getCOM(COM);
511
512 totalMass_local += massOfCurMol;
513 totalMZ_local += massOfCurMol * COM[whichDirection];
514
515 if(isZConstraintMol(&molecules[i]) == -1){
516
517 massOfUncons_local += massOfCurMol;
518 }
519
520 }
521
522
523 #ifdef IS_MPI
524 MPI_Allreduce(&totalMass_local, &totalMass, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
525 MPI_Allreduce(&totalMZ_local, &totalMZ, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
526 MPI_Allreduce(&massOfUncons_local, &totalMassOfUncons, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
527 #else
528 totalMass = totalMass_local;
529 totalMZ = totalMZ_local;
530 totalMassOfUncons = massOfUncons_local;
531 #endif
532
533 double zsys;
534 zsys = totalMZ / totalMass;
535
536 return zsys;
537 }
538
539 /**
540 *
541 */
542 template<typename T> void ZConstraint<T>::thermalize( void ){
543
544 T::thermalize();
545 zeroOutVel();
546 }
547
548 /**
549 *
550 *
551 *
552 */
553
554 template<typename T> void ZConstraint<T>::zeroOutVel(){
555
556 Atom** fixedZAtoms;
557 double COMvel[3];
558 double vel[3];
559
560 double tempMass = 0;
561 double tempMVz =0;
562 double tempVz = 0;
563 for(int i = 0; i < nMols; i++){
564 molecules[i].getCOMvel(COMvel);
565 tempMass +=molecules[i].getTotalMass();
566 tempMVz += molecules[i].getTotalMass() * COMvel[whichDirection];
567 tempVz += COMvel[whichDirection];
568 }
569 cout << "initial velocity of center of mass is " << tempMVz / tempMass << endl;
570
571 //zero out the velocities of center of mass of fixed z-constrained molecules
572
573 for(int i = 0; i < zconsMols.size(); i++){
574
575 if (states[i] == zcsFixed){
576
577 zconsMols[i]->getCOMvel(COMvel);
578 cout << "before resetting " << indexOfZConsMols[i] <<"'s vz is " << COMvel[whichDirection] << endl;
579
580 fixedZAtoms = zconsMols[i]->getMyAtoms();
581
582 for(int j =0; j < zconsMols[i]->getNAtoms(); j++){
583 fixedZAtoms[j]->getVel(vel);
584 vel[whichDirection] -= COMvel[whichDirection];
585 fixedZAtoms[j]->setVel(vel);
586 }
587
588 zconsMols[i]->getCOMvel(COMvel);
589 cout << "after resetting " << indexOfZConsMols[i] <<"'s vz is " << COMvel[whichDirection] << endl;
590 }
591
592 }
593
594 cout << "before resetting the COMVel of unconstraint molecules is " << calcCOMVel() <<endl;
595
596 // calculate the vz of center of mass of unconstrained molecules and moving z-constrained molecules
597 double MVzOfMovingMols_local;
598 double MVzOfMovingMols;
599 double totalMassOfMovingZMols_local;
600 double totalMassOfMovingZMols;
601
602 MVzOfMovingMols_local = 0;
603 totalMassOfMovingZMols_local = 0;
604
605 for(int i =0; i < unconsMols.size(); i++){
606 unconsMols[i]->getCOMvel(COMvel);
607 MVzOfMovingMols_local += massOfUnconsMols[i] * COMvel[whichDirection];
608 }
609
610 for(int i = 0; i < zconsMols.size(); i++){
611 if (states[i] == zcsMoving){
612 zconsMols[i]->getCOMvel(COMvel);
613 MVzOfMovingMols_local += massOfZConsMols[i] * COMvel[whichDirection];
614 totalMassOfMovingZMols_local += massOfZConsMols[i];
615 }
616
617 }
618
619 #ifndef IS_MPI
620 MVzOfMovingMols = MVzOfMovingMols_local;
621 totalMassOfMovingZMols = totalMassOfMovingZMols_local;
622 #else
623 MPI_Allreduce(&MVzOfMovingMols_local, &MVzOfMovingMols, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
624 MPI_Allreduce(&totalMassOfMovingZMols_local, &totalMassOfMovingZMols, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
625 #endif
626
627 double vzOfMovingMols;
628 vzOfMovingMols = MVzOfMovingMols / (totalMassOfUncons + totalMassOfMovingZMols);
629
630 //modify the velocites of unconstrained molecules
631 Atom** unconsAtoms;
632 for(int i = 0; i < unconsMols.size(); i++){
633
634 unconsAtoms = unconsMols[i]->getMyAtoms();
635 for(int j = 0; j < unconsMols[i]->getNAtoms();j++){
636 unconsAtoms[j]->getVel(vel);
637 vel[whichDirection] -= vzOfMovingMols;
638 unconsAtoms[j]->setVel(vel);
639 }
640
641 }
642
643 //modify the velocities of moving z-constrained molecuels
644 Atom** movingZAtoms;
645 for(int i = 0; i < zconsMols.size(); i++){
646
647 if (states[i] ==zcsMoving){
648
649 movingZAtoms = zconsMols[i]->getMyAtoms();
650 for(int j = 0; j < zconsMols[i]->getNAtoms(); j++){
651 movingZAtoms[j]->getVel(vel);
652 vel[whichDirection] -= vzOfMovingMols;
653 movingZAtoms[j]->setVel(vel);
654 }
655
656 }
657
658 }
659
660 cout << "after resetting the COMVel of unconstraint molecules is " << calcCOMVel() <<endl;
661
662 }
663
664 template<typename T> void ZConstraint<T>::doZconstraintForce(){
665
666 Atom** zconsAtoms;
667 double totalFZ;
668 double totalFZ_local;
669 double COMvel[3];
670 double COM[3];
671 double force[3];
672
673 int nMovingZMols_local;
674 int nMovingZMols;
675
676 //constrain the molecules which do not reach the specified positions
677
678 //Zero Out the force of z-contrained molecules
679 totalFZ_local = 0;
680
681 //calculate the total z-contrained force of fixed z-contrained molecules
682 cout << "Fixed Molecules" << endl;
683 for(int i = 0; i < zconsMols.size(); i++){
684
685 if (states[i] == zcsFixed){
686
687 zconsMols[i]->getCOM(COM);
688 zconsAtoms = zconsMols[i]->getMyAtoms();
689
690 fz[i] = 0;
691 for(int j =0; j < zconsMols[i]->getNAtoms(); j++) {
692 zconsAtoms[j]->getFrc(force);
693 fz[i] += force[whichDirection];
694 }
695 totalFZ_local += fz[i];
696
697 cout << "index: " << indexOfZConsMols[i] <<"\tcurrent zpos: " << COM[whichDirection] << endl;
698
699 }
700
701 }
702
703 //calculate the number of atoms of moving z-constrained molecules
704 nMovingZMols_local = 0;
705 for(int i = 0; i < zconsMols.size(); i++)
706 if(states[i] == zcsMoving)
707 nMovingZMols_local += massOfZConsMols[i];
708
709 #ifdef IS_MPI
710 MPI_Allreduce(&totalFZ_local, &totalFZ, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
711 MPI_Allreduce(&nMovingZMols_local, &nMovingZMols, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
712 #else
713 totalFZ = totalFZ_local;
714 nMovingZMols = nMovingZMols_local;
715 #endif
716
717 force[0]= 0;
718 force[1]= 0;
719 force[2]= 0;
720 force[whichDirection] = totalFZ / (totNumOfUnconsAtoms + nMovingZMols);
721
722 //modify the forces of unconstrained molecules
723 for(int i = 0; i < unconsMols.size(); i++){
724
725 Atom** unconsAtoms = unconsMols[i]->getMyAtoms();
726
727 for(int j = 0; j < unconsMols[i]->getNAtoms(); j++)
728 unconsAtoms[j]->addFrc(force);
729
730 }
731
732 //modify the forces of moving z-constrained molecules
733 for(int i = 0; i < zconsMols.size(); i++) {
734 if (states[i] == zcsMoving){
735
736 Atom** movingZAtoms = zconsMols[i]->getMyAtoms();
737
738 for(int j = 0; j < zconsMols[i]->getNAtoms(); j++)
739 movingZAtoms[j]->addFrc(force);
740 }
741 }
742
743 // apply negative to fixed z-constrained molecues;
744 force[0]= 0;
745 force[1]= 0;
746 force[2]= 0;
747
748 for(int i = 0; i < zconsMols.size(); i++){
749
750 if (states[i] == zcsFixed){
751
752 int nAtomOfCurZConsMol = zconsMols[i]->getNAtoms();
753 zconsAtoms = zconsMols[i]->getMyAtoms();
754
755 for(int j =0; j < nAtomOfCurZConsMol; j++) {
756 force[whichDirection] = -fz[i]/ nAtomOfCurZConsMol;
757 zconsAtoms[j]->addFrc(force);
758 }
759
760 }
761
762 }
763
764 }
765
766 template<typename T> bool ZConstraint<T>::checkZConsState(){
767 double COM[3];
768 double diff;
769
770 bool changed;
771
772 changed = false;
773
774 for(int i =0; i < zconsMols.size(); i++){
775
776 zconsMols[i]->getCOM(COM);
777 diff = fabs(COM[whichDirection] - zPos[i]);
778 if ( diff <= zconsTol && states[i] == zcsMoving){
779 states[i] = zcsFixed;
780 changed = true;
781 }
782 else if ( diff > zconsTol && states[i] == zcsFixed){
783 states[i] = zcsMoving;
784 changed = true;
785 }
786
787 }
788
789 return changed;
790 }
791
792 template<typename T> bool ZConstraint<T>::haveFixedZMols(){
793 for(int i = 0; i < zconsMols.size(); i++)
794 if (states[i] == zcsFixed)
795 return true;
796
797 return false;
798 }
799
800
801 /**
802 *
803 */
804 template<typename T> bool ZConstraint<T>::haveMovingZMols(){
805 for(int i = 0; i < zconsMols.size(); i++)
806 if (states[i] == zcsMoving)
807 return true;
808
809 return false;
810
811 }
812
813 /**
814 *
815 *
816 */
817
818 template<typename T> void ZConstraint<T>::doHarmonic(){
819 double force[3];
820 double harmonicU;
821 double harmonicF;
822 double COM[3];
823 double diff;
824 double totalFZ;
825
826 force[0] = 0;
827 force[1] = 0;
828 force[2] = 0;
829
830 totalFZ = 0;
831
832 cout << "Moving Molecules" << endl;
833 for(int i = 0; i < zconsMols.size(); i++) {
834
835 if (states[i] == zcsMoving){
836 zconsMols[i]->getCOM(COM);
837 cout << "index: " << indexOfZConsMols[i] <<"\tcurrent zpos: " << COM[whichDirection] << endl;
838
839 diff = COM[whichDirection] -zPos[i];
840
841 harmonicU = 0.5 * kz[i] * diff * diff;
842 info->lrPot += harmonicU;
843
844 harmonicF = - kz[i] * diff / zconsMols[i]->getNAtoms();
845 force[whichDirection] = harmonicF;
846 totalFZ += harmonicF;
847
848 Atom** movingZAtoms = zconsMols[i]->getMyAtoms();
849
850 for(int j = 0; j < zconsMols[i]->getNAtoms(); j++)
851 movingZAtoms[j]->addFrc(force);
852 }
853
854 }
855
856 force[0]= 0;
857 force[1]= 0;
858 force[2]= 0;
859 force[whichDirection] = -totalFZ /totNumOfUnconsAtoms;
860
861 //modify the forces of unconstrained molecules
862 for(int i = 0; i < unconsMols.size(); i++){
863
864 Atom** unconsAtoms = unconsMols[i]->getMyAtoms();
865
866 for(int j = 0; j < unconsMols[i]->getNAtoms(); j++)
867 unconsAtoms[j]->addFrc(force);
868 }
869
870 }
871
872 template<typename T> double ZConstraint<T>::calcCOMVel()
873 {
874 double MVzOfMovingMols_local;
875 double MVzOfMovingMols;
876 double totalMassOfMovingZMols_local;
877 double totalMassOfMovingZMols;
878 double COMvel[3];
879
880 MVzOfMovingMols_local = 0;
881 totalMassOfMovingZMols_local = 0;
882
883 for(int i =0; i < unconsMols.size(); i++){
884 unconsMols[i]->getCOMvel(COMvel);
885 MVzOfMovingMols_local += massOfUnconsMols[i] * COMvel[whichDirection];
886 }
887
888 for(int i = 0; i < zconsMols.size(); i++){
889
890 if (states[i] == zcsMoving){
891 zconsMols[i]->getCOMvel(COMvel);
892 MVzOfMovingMols_local += massOfZConsMols[i] * COMvel[whichDirection];
893 totalMassOfMovingZMols_local += massOfZConsMols[i];
894 }
895
896 }
897
898 #ifndef IS_MPI
899 MVzOfMovingMols = MVzOfMovingMols_local;
900 totalMassOfMovingZMols = totalMassOfMovingZMols_local;
901 #else
902 MPI_Allreduce(&MVzOfMovingMols_local, &MVzOfMovingMols, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
903 MPI_Allreduce(&totalMassOfMovingZMols_local, &totalMassOfMovingZMols, 1, MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
904 #endif
905
906 double vzOfMovingMols;
907 vzOfMovingMols = MVzOfMovingMols / (totalMassOfUncons + totalMassOfMovingZMols);
908
909 return vzOfMovingMols;
910 }
911
912
913 template<typename T> double ZConstraint<T>::calcCOMVel2()
914 {
915 double COMvel[3];
916 double tempMVz = 0;
917 int index;
918
919 for(int i =0 ; i < nMols; i++){
920 index = isZConstraintMol(&molecules[i]);
921 if( index == -1){
922 molecules[i].getCOMvel(COMvel);
923 tempMVz += molecules[i].getTotalMass()*COMvel[whichDirection];
924 }
925 else if(states[i] == zcsMoving){
926 zconsMols[index]->getCOMvel(COMvel);
927 tempMVz += massOfZConsMols[index]*COMvel[whichDirection];
928 }
929 }
930
931 return tempMVz /totalMassOfUncons;
932 }