ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/minimizers/Minimizer.cpp
Revision: 1665
Committed: Tue Nov 22 20:38:56 2011 UTC (13 years, 5 months ago) by gezelter
File size: 18536 byte(s)
Log Message:
updated copyright notices

File Contents

# Content
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. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * This software is provided "AS IS," without a warranty of any
18 * kind. All express or implied conditions, representations and
19 * warranties, including any implied warranty of merchantability,
20 * fitness for a particular purpose or non-infringement, are hereby
21 * excluded. The University of Notre Dame and its licensors shall not
22 * be liable for any damages suffered by licensee as a result of
23 * using, modifying or distributing the software or its
24 * derivatives. In no event will the University of Notre Dame or its
25 * licensors be liable for any lost revenue, profit or data, or for
26 * direct, indirect, special, consequential, incidental or punitive
27 * damages, however caused and regardless of the theory of liability,
28 * arising out of the use of or inability to use software, even if the
29 * University of Notre Dame has been advised of the possibility of
30 * such damages.
31 *
32 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 * research, please cite the appropriate papers when you publish your
34 * work. Good starting points are:
35 *
36 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 */
42
43 #include <cmath>
44
45
46 #include "io/StatWriter.hpp"
47 #include "minimizers/Minimizer.hpp"
48 #include "primitives/Molecule.hpp"
49 #ifdef IS_MPI
50 #include <mpi.h>
51 #endif
52 namespace OpenMD {
53 RealType dotProduct(const std::vector<RealType>& v1, const std::vector<RealType>& v2) {
54 if (v1.size() != v2.size()) {
55
56 }
57
58
59 RealType result = 0.0;
60 for (unsigned int i = 0; i < v1.size(); ++i) {
61 result += v1[i] * v2[i];
62 }
63
64 return result;
65 }
66
67 Minimizer::Minimizer(SimInfo* rhs) :
68 info(rhs), usingShake(false) {
69
70 forceMan = new ForceManager(info);
71 paramSet= new MinimizerParameterSet(info), calcDim();
72 curX = getCoor();
73 curG.resize(ndim);
74
75 }
76
77 Minimizer::~Minimizer() {
78 delete forceMan;
79 delete paramSet;
80 }
81
82 void Minimizer::calcEnergyGradient(std::vector<RealType> &x,
83 std::vector<RealType> &grad, RealType&energy, int&status) {
84
85 SimInfo::MoleculeIterator i;
86 Molecule::IntegrableObjectIterator j;
87 Molecule* mol;
88 StuntDouble* integrableObject;
89 std::vector<RealType> myGrad;
90 int shakeStatus;
91
92 status = 1;
93
94 setCoor(x);
95
96 if (usingShake) {
97 shakeStatus = shakeR();
98 }
99
100 energy = calcPotential();
101
102 if (usingShake) {
103 shakeStatus = shakeF();
104 }
105
106 x = getCoor();
107
108 int index = 0;
109
110 for (mol = info->beginMolecule(i); mol != NULL; mol = info->nextMolecule(i)) {
111 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
112 integrableObject = mol->nextIntegrableObject(j)) {
113
114 myGrad = integrableObject->getGrad();
115 for (unsigned int k = 0; k < myGrad.size(); ++k) {
116
117 grad[index++] = myGrad[k];
118 }
119 }
120 }
121
122 }
123
124 void Minimizer::setCoor(std::vector<RealType> &x) {
125 Vector3d position;
126 Vector3d eulerAngle;
127 SimInfo::MoleculeIterator i;
128 Molecule::IntegrableObjectIterator j;
129 Molecule* mol;
130 StuntDouble* integrableObject;
131 int index = 0;
132
133 for (mol = info->beginMolecule(i); mol != NULL; mol = info->nextMolecule(i)) {
134 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
135 integrableObject = mol->nextIntegrableObject(j)) {
136
137 position[0] = x[index++];
138 position[1] = x[index++];
139 position[2] = x[index++];
140
141 integrableObject->setPos(position);
142
143 if (integrableObject->isDirectional()) {
144 eulerAngle[0] = x[index++];
145 eulerAngle[1] = x[index++];
146 eulerAngle[2] = x[index++];
147
148 integrableObject->setEuler(eulerAngle);
149 }
150 }
151 }
152
153 }
154
155 std::vector<RealType> Minimizer::getCoor() {
156 Vector3d position;
157 Vector3d eulerAngle;
158 SimInfo::MoleculeIterator i;
159 Molecule::IntegrableObjectIterator j;
160 Molecule* mol;
161 StuntDouble* integrableObject;
162 int index = 0;
163 std::vector<RealType> x(getDim());
164
165 for (mol = info->beginMolecule(i); mol != NULL; mol = info->nextMolecule(i)) {
166 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
167 integrableObject = mol->nextIntegrableObject(j)) {
168
169 position = integrableObject->getPos();
170 x[index++] = position[0];
171 x[index++] = position[1];
172 x[index++] = position[2];
173
174 if (integrableObject->isDirectional()) {
175 eulerAngle = integrableObject->getEuler();
176 x[index++] = eulerAngle[0];
177 x[index++] = eulerAngle[1];
178 x[index++] = eulerAngle[2];
179 }
180 }
181 }
182 return x;
183 }
184
185
186 /*
187 int Minimizer::shakeR() {
188 int i, j;
189
190 int done;
191
192 RealType posA[3], posB[3];
193
194 RealType velA[3], velB[3];
195
196 RealType pab[3];
197
198 RealType rab[3];
199
200 int a, b,
201 ax, ay,
202 az, bx,
203 by, bz;
204
205 RealType rma, rmb;
206
207 RealType dx, dy,
208 dz;
209
210 RealType rpab;
211
212 RealType rabsq, pabsq,
213 rpabsq;
214
215 RealType diffsq;
216
217 RealType gab;
218
219 int iteration;
220
221 for(i = 0; i < nAtoms; i++) {
222 moving[i] = 0;
223
224 moved[i] = 1;
225 }
226
227 iteration = 0;
228
229 done = 0;
230
231 while (!done && (iteration < maxIteration)) {
232 done = 1;
233
234 for(i = 0; i < nConstrained; i++) {
235 a = constrainedA[i];
236
237 b = constrainedB[i];
238
239 ax = (a * 3) + 0;
240
241 ay = (a * 3) + 1;
242
243 az = (a * 3) + 2;
244
245 bx = (b * 3) + 0;
246
247 by = (b * 3) + 1;
248
249 bz = (b * 3) + 2;
250
251 if (moved[a] || moved[b]) {
252 posA = atoms[a]->getPos();
253
254 posB = atoms[b]->getPos();
255
256 for(j = 0; j < 3; j++)
257 pab[j] = posA[j] - posB[j];
258
259 //periodic boundary condition
260
261 info->wrapVector(pab);
262
263 pabsq = pab[0] * pab[0] + pab[1] * pab[1] + pab[2] * pab[2];
264
265 rabsq = constrainedDsqr[i];
266
267 diffsq = rabsq - pabsq;
268
269 // the original rattle code from alan tidesley
270
271 if (fabs(diffsq) > (tol * rabsq * 2)) {
272 rab[0] = oldPos[ax] - oldPos[bx];
273
274 rab[1] = oldPos[ay] - oldPos[by];
275
276 rab[2] = oldPos[az] - oldPos[bz];
277
278 info->wrapVector(rab);
279
280 rpab = rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
281
282 rpabsq = rpab * rpab;
283
284 if (rpabsq < (rabsq * -diffsq)) {
285
286 #ifdef IS_MPI
287
288 a = atoms[a]->getGlobalIndex();
289
290 b = atoms[b]->getGlobalIndex();
291
292 #endif //is_mpi
293
294 //std::cerr << "Waring: constraint failure" << std::endl;
295
296 gab = sqrt(rabsq / pabsq);
297
298 rab[0] = (posA[0] - posB[0])
299 * gab;
300
301 rab[1] = (posA[1] - posB[1])
302 * gab;
303
304 rab[2] = (posA[2] - posB[2])
305 * gab;
306
307 info->wrapVector(rab);
308
309 rpab =
310 rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
311 }
312
313 //rma = 1.0 / atoms[a]->getMass();
314
315 //rmb = 1.0 / atoms[b]->getMass();
316
317 rma = 1.0;
318
319 rmb = 1.0;
320
321 gab = diffsq / (2.0 * (rma + rmb) * rpab);
322
323 dx = rab[0]*
324 gab;
325
326 dy = rab[1]*
327 gab;
328
329 dz = rab[2]*
330 gab;
331
332 posA[0] += rma *dx;
333
334 posA[1] += rma *dy;
335
336 posA[2] += rma *dz;
337
338 atoms[a]->setPos(posA);
339
340 posB[0] -= rmb *dx;
341
342 posB[1] -= rmb *dy;
343
344 posB[2] -= rmb *dz;
345
346 atoms[b]->setPos(posB);
347
348 moving[a] = 1;
349
350 moving[b] = 1;
351
352 done = 0;
353 }
354 }
355 }
356
357 for(i = 0; i < nAtoms; i++) {
358 moved[i] = moving[i];
359
360 moving[i] = 0;
361 }
362
363 iteration++;
364 }
365
366 if (!done) {
367 std::cerr << "Waring: can not constraint within maxIteration"
368 << std::endl;
369
370 return -1;
371 } else
372 return 1;
373 }
374
375 //remove constraint force along the bond direction
376
377
378 int Minimizer::shakeF() {
379 int i, j;
380
381 int done;
382
383 RealType posA[3], posB[3];
384
385 RealType frcA[3], frcB[3];
386
387 RealType rab[3], fpab[3];
388
389 int a, b,
390 ax, ay,
391 az, bx,
392 by, bz;
393
394 RealType rma, rmb;
395
396 RealType rvab;
397
398 RealType gab;
399
400 RealType rabsq;
401
402 RealType rfab;
403
404 int iteration;
405
406 for(i = 0; i < nAtoms; i++) {
407 moving[i] = 0;
408
409 moved[i] = 1;
410 }
411
412 done = 0;
413
414 iteration = 0;
415
416 while (!done && (iteration < maxIteration)) {
417 done = 1;
418
419 for(i = 0; i < nConstrained; i++) {
420 a = constrainedA[i];
421
422 b = constrainedB[i];
423
424 ax = (a * 3) + 0;
425
426 ay = (a * 3) + 1;
427
428 az = (a * 3) + 2;
429
430 bx = (b * 3) + 0;
431
432 by = (b * 3) + 1;
433
434 bz = (b * 3) + 2;
435
436 if (moved[a] || moved[b]) {
437 posA = atoms[a]->getPos();
438
439 posB = atoms[b]->getPos();
440
441 for(j = 0; j < 3; j++)
442 rab[j] = posA[j] - posB[j];
443
444 info->wrapVector(rab);
445
446 atoms[a]->getFrc(frcA);
447
448 atoms[b]->getFrc(frcB);
449
450 //rma = 1.0 / atoms[a]->getMass();
451
452 //rmb = 1.0 / atoms[b]->getMass();
453
454 rma = 1.0;
455
456 rmb = 1.0;
457
458 fpab[0] = frcA[0] * rma - frcB[0] * rmb;
459
460 fpab[1] = frcA[1] * rma - frcB[1] * rmb;
461
462 fpab[2] = frcA[2] * rma - frcB[2] * rmb;
463
464 gab = fpab[0] * fpab[0] + fpab[1] * fpab[1] + fpab[2] * fpab[2];
465
466 if (gab < 1.0)
467 gab = 1.0;
468
469 rabsq = rab[0] * rab[0] + rab[1] * rab[1] + rab[2] * rab[2];
470
471 rfab = rab[0] * fpab[0] + rab[1] * fpab[1] + rab[2] * fpab[2];
472
473 if (fabs(rfab) > sqrt(rabsq*gab) * 0.00001) {
474 gab = -rfab / (rabsq * (rma + rmb));
475
476 frcA[0] = rab[0]*
477 gab;
478
479 frcA[1] = rab[1]*
480 gab;
481
482 frcA[2] = rab[2]*
483 gab;
484
485 atoms[a]->addFrc(frcA);
486
487 frcB[0] = -rab[0]*gab;
488
489 frcB[1] = -rab[1]*gab;
490
491 frcB[2] = -rab[2]*gab;
492
493 atoms[b]->addFrc(frcB);
494
495 moving[a] = 1;
496
497 moving[b] = 1;
498
499 done = 0;
500 }
501 }
502 }
503
504 for(i = 0; i < nAtoms; i++) {
505 moved[i] = moving[i];
506
507 moving[i] = 0;
508 }
509
510 iteration++;
511 }
512
513 if (!done) {
514 std::cerr << "Waring: can not constraint within maxIteration"
515 << std::endl;
516
517 return -1;
518 } else
519 return 1;
520 }
521
522 */
523
524 //calculate the value of object function
525
526 void Minimizer::calcF() {
527 calcEnergyGradient(curX, curG, curF, egEvalStatus);
528 }
529
530 void Minimizer::calcF(std::vector < RealType > &x, RealType&f, int&status) {
531 std::vector < RealType > tempG;
532
533 tempG.resize(x.size());
534
535 calcEnergyGradient(x, tempG, f, status);
536 }
537
538 //calculate the gradient
539
540 void Minimizer::calcG() {
541 calcEnergyGradient(curX, curG, curF, egEvalStatus);
542 }
543
544 void Minimizer::calcG(std::vector<RealType>& x, std::vector<RealType>& g, RealType&f, int&status) {
545 calcEnergyGradient(x, g, f, status);
546 }
547
548 void Minimizer::calcDim() {
549
550 SimInfo::MoleculeIterator i;
551 Molecule::IntegrableObjectIterator j;
552 Molecule* mol;
553 StuntDouble* integrableObject;
554 ndim = 0;
555
556 for (mol = info->beginMolecule(i); mol != NULL; mol = info->nextMolecule(i)) {
557 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
558 integrableObject = mol->nextIntegrableObject(j)) {
559
560 ndim += 3;
561
562 if (integrableObject->isDirectional()) {
563 ndim += 3;
564 }
565 }
566
567 }
568 }
569
570 void Minimizer::setX(std::vector < RealType > &x) {
571 if (x.size() != ndim) {
572 sprintf(painCave.errMsg, "Minimizer Error: dimesion of x and curX does not match\n");
573 painCave.isFatal = 1;
574 simError();
575 }
576
577 curX = x;
578 }
579
580 void Minimizer::setG(std::vector < RealType > &g) {
581 if (g.size() != ndim) {
582 sprintf(painCave.errMsg, "Minimizer Error: dimesion of g and curG does not match\n");
583 painCave.isFatal = 1;
584 simError();
585 }
586
587 curG = g;
588 }
589
590
591 /**
592
593 * In thoery, we need to find the minimum along the search direction
594 * However, function evaluation is too expensive.
595 * At the very begining of the problem, we check the search direction and make sure
596 * it is a descent direction
597 * we will compare the energy of two end points,
598 * if the right end point has lower energy, we just take it
599 * @todo optimize this line search algorithm
600 */
601
602 int Minimizer::doLineSearch(std::vector<RealType> &direction,
603 RealType stepSize) {
604
605 std::vector<RealType> xa;
606 std::vector<RealType> xb;
607 std::vector<RealType> xc;
608 std::vector<RealType> ga;
609 std::vector<RealType> gb;
610 std::vector<RealType> gc;
611 RealType fa;
612 RealType fb;
613 RealType fc;
614 RealType a;
615 RealType b;
616 RealType c;
617 int status;
618 RealType initSlope;
619 RealType slopeA;
620 RealType slopeB;
621 RealType slopeC;
622 bool foundLower;
623 int iter;
624 int maxLSIter;
625 RealType mu;
626 RealType eta;
627 RealType ftol;
628 RealType lsTol;
629
630 xa.resize(ndim);
631 xb.resize(ndim);
632 xc.resize(ndim);
633 ga.resize(ndim);
634 gb.resize(ndim);
635 gc.resize(ndim);
636
637 a = 0.0;
638
639 fa = curF;
640
641 xa = curX;
642
643 ga = curG;
644
645 c = a + stepSize;
646
647 ftol = paramSet->getFTol();
648
649 lsTol = paramSet->getLineSearchTol();
650
651 //calculate the derivative at a = 0
652
653 slopeA = 0;
654
655 for(size_t i = 0; i < ndim; i++) {
656 slopeA += curG[i] * direction[i];
657 }
658
659 initSlope = slopeA;
660
661 // if going uphill, use negative gradient as searching direction
662
663 if (slopeA > 0) {
664
665 for(size_t i = 0; i < ndim; i++) {
666 direction[i] = -curG[i];
667 }
668
669 for(size_t i = 0; i < ndim; i++) {
670 slopeA += curG[i] * direction[i];
671 }
672
673 initSlope = slopeA;
674 }
675
676 // Take a trial step
677
678 for(size_t i = 0; i < ndim; i++) {
679 xc[i] = curX[i] + direction[i]* c;
680 }
681
682 calcG(xc, gc, fc, status);
683
684 if (status < 0) {
685 if (bVerbose)
686 std::cerr << "Function Evaluation Error" << std::endl;
687 }
688
689 //calculate the derivative at c
690
691 slopeC = 0;
692
693 for(size_t i = 0; i < ndim; i++) {
694 slopeC += gc[i] * direction[i];
695 }
696 // found a lower point
697
698 if (fc < fa) {
699 curX = xc;
700
701 curG = gc;
702
703 curF = fc;
704
705 return LS_SUCCEED;
706 } else {
707 if (slopeC > 0)
708 stepSize *= 0.618034;
709 }
710
711 maxLSIter = paramSet->getLineSearchMaxIteration();
712
713 iter = 0;
714
715 do {
716
717 // Select a new trial point.
718
719 // If the derivatives at points a & c have different sign we use cubic interpolate
720
721 //if (slopeC > 0){
722
723 eta = 3 * (fa - fc) / (c - a) + slopeA + slopeC;
724
725 mu = sqrt(eta * eta - slopeA * slopeC);
726
727 b = a + (c - a)
728 * (1 - (slopeC + mu - eta) / (slopeC - slopeA + 2 * mu));
729
730 if (b < lsTol) {
731 break;
732 }
733
734 //}
735
736 // Take a trial step to this new point - new coords in xb
737
738 for(size_t i = 0; i < ndim; i++) {
739 xb[i] = curX[i] + direction[i]* b;
740 }
741
742 //function evaluation
743
744 calcG(xb, gb, fb, status);
745
746 if (status < 0) {
747 if (bVerbose)
748 std::cerr << "Function Evaluation Error" << std::endl;
749 }
750
751 //calculate the derivative at c
752
753 slopeB = 0;
754
755 for(size_t i = 0; i < ndim; i++) {
756 slopeB += gb[i] * direction[i];
757 }
758
759 //Amijo Rule to stop the line search
760
761 if (fb <= curF + initSlope * ftol * b) {
762 curF = fb;
763
764 curX = xb;
765
766 curG = gb;
767
768 return LS_SUCCEED;
769 }
770
771 if (slopeB < 0 && fb < fa) {
772
773 //replace a by b
774
775 fa = fb;
776
777 a = b;
778
779 slopeA = slopeB;
780
781 // swap coord a/b
782
783 std::swap(xa, xb);
784
785 std::swap(ga, gb);
786 } else {
787
788 //replace c by b
789
790 fc = fb;
791
792 c = b;
793
794 slopeC = slopeB;
795
796 // swap coord b/c
797
798 std::swap(gb, gc);
799
800 std::swap(xb, xc);
801 }
802
803 iter++;
804 } while ((fb > fa || fb > fc) && (iter < maxLSIter));
805
806 if (fb < curF || iter >= maxLSIter) {
807
808 //could not find a lower value, we might just go uphill.
809
810 return LS_ERROR;
811 }
812
813 //select the end point
814
815 if (fa <= fc) {
816 curX = xa;
817
818 curG = ga;
819
820 curF = fa;
821 } else {
822 curX = xc;
823
824 curG = gc;
825
826 curF = fc;
827 }
828
829 return LS_SUCCEED;
830 }
831
832 void Minimizer::minimize() {
833 int convgStatus;
834 int stepStatus;
835 int maxIter;
836 int writeFreq;
837 int nextWriteIter;
838 Snapshot* curSnapshot =info->getSnapshotManager()->getCurrentSnapshot();
839 DumpWriter dumpWriter(info);
840 StatsBitSet mask;
841 mask.set(Stats::TIME);
842 mask.set(Stats::POTENTIAL_ENERGY);
843 StatWriter statWriter(info->getStatFileName(), mask);
844
845 init();
846
847 writeFreq = paramSet->getWriteFreq();
848
849 nextWriteIter = writeFreq;
850
851 maxIter = paramSet->getMaxIteration();
852
853 for(curIter = 1; curIter <= maxIter; curIter++) {
854 stepStatus = step();
855
856 //if (usingShake)
857 // preMove();
858
859 if (stepStatus < 0) {
860 saveResult();
861
862 minStatus = MIN_LSERROR;
863
864 std::cerr
865 << "Minimizer Error: line search error, please try a small stepsize"
866 << std::endl;
867
868 return;
869 }
870
871 //save snapshot
872 info->getSnapshotManager()->advance();
873 //increase time
874 curSnapshot->increaseTime(1);
875
876 if (curIter == nextWriteIter) {
877 nextWriteIter += writeFreq;
878 calcF();
879 dumpWriter.writeDumpAndEor();
880 statWriter.writeStat(curSnapshot->statData);
881 }
882
883 convgStatus = checkConvg();
884
885 if (convgStatus > 0) {
886 saveResult();
887
888 minStatus = MIN_CONVERGE;
889
890 return;
891 }
892
893 prepareStep();
894 }
895
896 if (bVerbose) {
897 std::cout << "Minimizer Warning: " << minimizerName
898 << " algorithm did not converge within " << maxIter << " iteration"
899 << std::endl;
900 }
901
902 minStatus = MIN_MAXITER;
903
904 saveResult();
905 }
906
907
908 RealType Minimizer::calcPotential() {
909 forceMan->calcForces();
910
911 Snapshot* curSnapshot = info->getSnapshotManager()->getCurrentSnapshot();
912 RealType potential_local = curSnapshot->statData[Stats::LONG_RANGE_POTENTIAL] +
913 curSnapshot->statData[Stats::SHORT_RANGE_POTENTIAL] ;
914 RealType potential;
915
916 #ifdef IS_MPI
917 MPI_Allreduce(&potential_local, &potential, 1, MPI_REALTYPE, MPI_SUM,
918 MPI_COMM_WORLD);
919 #else
920 potential = potential_local;
921 #endif
922
923 //save total potential
924 curSnapshot->statData[Stats::POTENTIAL_ENERGY] = potential;
925 return potential;
926 }
927
928 }

Properties

Name Value
svn:executable *
svn:keywords Author Id Revision Date