ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/minimizers/Minimizer.cpp
Revision: 1422
Committed: Tue Mar 30 15:04:45 2010 UTC (15 years, 1 month ago) by gezelter
Original Path: trunk/src/minimizers/Minimizer.cpp
File size: 18443 byte(s)
Log Message:
Fixed a typo so that we use "Freq" instead of "Frq". 

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

Properties

Name Value
svn:executable *