ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/minimizers/Minimizer.cpp
Revision: 1627
Committed: Tue Sep 13 22:05:04 2011 UTC (13 years, 7 months ago) by gezelter
File size: 18470 byte(s)
Log Message:
Splitting out ifstrstream into a header and an implementation.  This
means that much of the code that depends on it can be compiled only
once and the parallel I/O is concentrated into a few files.  To do
this, a number of files that relied on basic_ifstrstream to load the
mpi header had to be modified to manage their own headers.


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

Properties

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