ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/Integrator.cpp
Revision: 567
Committed: Wed Jun 25 21:12:14 2003 UTC (21 years ago) by mmeineke
File size: 15366 byte(s)
Log Message:
Changed over the bonds to Harmonic bonds in the DUFF frc file

fixed constraints.

File Contents

# User Rev Content
1 mmeineke 558 #include <iostream>
2     #include <cstdlib>
3 mmeineke 561 #include <cmath>
4 mmeineke 558
5     #ifdef IS_MPI
6     #include "mpiSimulation.hpp"
7     #include <unistd.h>
8     #endif //is_mpi
9    
10     #include "Integrator.hpp"
11     #include "simError.h"
12    
13    
14 mmeineke 561 Integrator::Integrator( SimInfo *theInfo, ForceFields* the_ff ){
15 mmeineke 558
16     info = theInfo;
17     myFF = the_ff;
18     isFirst = 1;
19    
20     molecules = info->molecules;
21     nMols = info->n_mol;
22    
23     // give a little love back to the SimInfo object
24    
25     if( info->the_integrator != NULL ) delete info->the_integrator;
26     info->the_integrator = this;
27    
28     nAtoms = info->n_atoms;
29    
30     // check for constraints
31    
32     constrainedA = NULL;
33     constrainedB = NULL;
34     constrainedDsqr = NULL;
35     moving = NULL;
36     moved = NULL;
37 mmeineke 561 oldPos = NULL;
38 mmeineke 558
39     nConstrained = 0;
40    
41     checkConstraints();
42     }
43    
44     Integrator::~Integrator() {
45    
46     if( nConstrained ){
47     delete[] constrainedA;
48     delete[] constrainedB;
49     delete[] constrainedDsqr;
50     delete[] moving;
51     delete[] moved;
52 mmeineke 561 delete[] oldPos;
53 mmeineke 558 }
54    
55     }
56    
57     void Integrator::checkConstraints( void ){
58    
59    
60     isConstrained = 0;
61    
62     Constraint *temp_con;
63     Constraint *dummy_plug;
64     temp_con = new Constraint[info->n_SRI];
65     nConstrained = 0;
66     int constrained = 0;
67    
68     SRI** theArray;
69     for(int i = 0; i < nMols; i++){
70    
71     theArray = (SRI**) molecules[i].getMyBonds();
72     for(int j=0; j<molecules[i].getNBonds(); j++){
73    
74     constrained = theArray[j]->is_constrained();
75    
76     if(constrained){
77    
78     dummy_plug = theArray[j]->get_constraint();
79     temp_con[nConstrained].set_a( dummy_plug->get_a() );
80     temp_con[nConstrained].set_b( dummy_plug->get_b() );
81     temp_con[nConstrained].set_dsqr( dummy_plug->get_dsqr() );
82    
83     nConstrained++;
84     constrained = 0;
85     }
86     }
87    
88     theArray = (SRI**) molecules[i].getMyBends();
89     for(int j=0; j<molecules[i].getNBends(); j++){
90    
91     constrained = theArray[j]->is_constrained();
92    
93     if(constrained){
94    
95     dummy_plug = theArray[j]->get_constraint();
96     temp_con[nConstrained].set_a( dummy_plug->get_a() );
97     temp_con[nConstrained].set_b( dummy_plug->get_b() );
98     temp_con[nConstrained].set_dsqr( dummy_plug->get_dsqr() );
99    
100     nConstrained++;
101     constrained = 0;
102     }
103     }
104    
105     theArray = (SRI**) molecules[i].getMyTorsions();
106     for(int j=0; j<molecules[i].getNTorsions(); j++){
107    
108     constrained = theArray[j]->is_constrained();
109    
110     if(constrained){
111    
112     dummy_plug = theArray[j]->get_constraint();
113     temp_con[nConstrained].set_a( dummy_plug->get_a() );
114     temp_con[nConstrained].set_b( dummy_plug->get_b() );
115     temp_con[nConstrained].set_dsqr( dummy_plug->get_dsqr() );
116    
117     nConstrained++;
118     constrained = 0;
119     }
120     }
121     }
122    
123     if(nConstrained > 0){
124    
125     isConstrained = 1;
126    
127     if(constrainedA != NULL ) delete[] constrainedA;
128     if(constrainedB != NULL ) delete[] constrainedB;
129     if(constrainedDsqr != NULL ) delete[] constrainedDsqr;
130    
131     constrainedA = new int[nConstrained];
132     constrainedB = new int[nConstrained];
133     constrainedDsqr = new double[nConstrained];
134    
135     for( int i = 0; i < nConstrained; i++){
136    
137     constrainedA[i] = temp_con[i].get_a();
138     constrainedB[i] = temp_con[i].get_b();
139     constrainedDsqr[i] = temp_con[i].get_dsqr();
140 mmeineke 563
141 mmeineke 558 }
142    
143    
144     // save oldAtoms to check for lode balanceing later on.
145    
146     oldAtoms = nAtoms;
147    
148     moving = new int[nAtoms];
149     moved = new int[nAtoms];
150    
151 mmeineke 561 oldPos = new double[nAtoms*3];
152 mmeineke 558 }
153    
154     delete[] temp_con;
155     }
156    
157    
158     void Integrator::integrate( void ){
159    
160     int i, j; // loop counters
161    
162     double runTime = info->run_time;
163     double sampleTime = info->sampleTime;
164     double statusTime = info->statusTime;
165     double thermalTime = info->thermalTime;
166    
167     double currSample;
168     double currThermal;
169     double currStatus;
170     double currTime;
171    
172     int calcPot, calcStress;
173     int isError;
174    
175 mmeineke 561
176    
177 mmeineke 558 tStats = new Thermo( info );
178 mmeineke 561 statOut = new StatWriter( info );
179     dumpOut = new DumpWriter( info );
180 mmeineke 558
181 mmeineke 561 atoms = info->atoms;
182 mmeineke 558 DirectionalAtom* dAtom;
183 mmeineke 561
184     dt = info->dt;
185 mmeineke 558 dt2 = 0.5 * dt;
186    
187     // initialize the forces before the first step
188    
189     myFF->doForces(1,1);
190    
191     if( info->setTemp ){
192    
193     tStats->velocitize();
194     }
195    
196 mmeineke 561 dumpOut->writeDump( 0.0 );
197     statOut->writeStat( 0.0 );
198 mmeineke 558
199     calcPot = 0;
200     calcStress = 0;
201     currSample = sampleTime;
202     currThermal = thermalTime;
203     currStatus = statusTime;
204     currTime = 0.0;;
205    
206 mmeineke 559
207     readyCheck();
208    
209     #ifdef IS_MPI
210     strcpy( checkPointMsg,
211     "The integrator is ready to go." );
212     MPIcheckPoint();
213     #endif // is_mpi
214    
215 mmeineke 561
216     pos = Atom::getPosArray();
217     vel = Atom::getVelArray();
218     frc = Atom::getFrcArray();
219     trq = Atom::getTrqArray();
220     Amat = Atom::getAmatArray();
221    
222 mmeineke 558 while( currTime < runTime ){
223    
224     if( (currTime+dt) >= currStatus ){
225     calcPot = 1;
226     calcStress = 1;
227     }
228 mmeineke 561
229 mmeineke 558 integrateStep( calcPot, calcStress );
230    
231     currTime += dt;
232    
233     if( info->setTemp ){
234     if( currTime >= currThermal ){
235     tStats->velocitize();
236     currThermal += thermalTime;
237     }
238     }
239    
240     if( currTime >= currSample ){
241 mmeineke 561 dumpOut->writeDump( currTime );
242 mmeineke 558 currSample += sampleTime;
243     }
244    
245     if( currTime >= currStatus ){
246 mmeineke 561 statOut->writeStat( currTime );
247 mmeineke 558 calcPot = 0;
248     calcStress = 0;
249     currStatus += statusTime;
250     }
251 mmeineke 559
252     #ifdef IS_MPI
253     strcpy( checkPointMsg,
254     "successfully took a time step." );
255     MPIcheckPoint();
256     #endif // is_mpi
257    
258 mmeineke 558 }
259    
260 mmeineke 561 dumpOut->writeFinal();
261 mmeineke 558
262 mmeineke 561 delete dumpOut;
263     delete statOut;
264 mmeineke 558 }
265    
266     void Integrator::integrateStep( int calcPot, int calcStress ){
267    
268 mmeineke 561
269    
270 mmeineke 558 // Position full step, and velocity half step
271    
272 mmeineke 561 preMove();
273 mmeineke 558 moveA();
274     if( nConstrained ) constrainA();
275    
276     // calc forces
277    
278     myFF->doForces(calcPot,calcStress);
279    
280     // finish the velocity half step
281    
282     moveB();
283     if( nConstrained ) constrainB();
284    
285     }
286    
287    
288     void Integrator::moveA( void ){
289    
290     int i,j,k;
291     int atomIndex, aMatIndex;
292     DirectionalAtom* dAtom;
293     double Tb[3];
294     double ji[3];
295 mmeineke 561 double angle;
296 mmeineke 558
297 mmeineke 567
298    
299 mmeineke 558 for( i=0; i<nAtoms; i++ ){
300     atomIndex = i * 3;
301     aMatIndex = i * 9;
302 mmeineke 567
303 mmeineke 558 // velocity half step
304     for( j=atomIndex; j<(atomIndex+3); j++ )
305     vel[j] += ( dt2 * frc[j] / atoms[i]->getMass() ) * eConvert;
306    
307     // position whole step
308 mmeineke 567 for( j=atomIndex; j<(atomIndex+3); j++ ) pos[j] += dt * vel[j];
309    
310 mmeineke 558 if( atoms[i]->isDirectional() ){
311    
312     dAtom = (DirectionalAtom *)atoms[i];
313    
314     // get and convert the torque to body frame
315    
316     Tb[0] = dAtom->getTx();
317     Tb[1] = dAtom->getTy();
318     Tb[2] = dAtom->getTz();
319    
320     dAtom->lab2Body( Tb );
321    
322     // get the angular momentum, and propagate a half step
323    
324     ji[0] = dAtom->getJx() + ( dt2 * Tb[0] ) * eConvert;
325     ji[1] = dAtom->getJy() + ( dt2 * Tb[1] ) * eConvert;
326     ji[2] = dAtom->getJz() + ( dt2 * Tb[2] ) * eConvert;
327    
328     // use the angular velocities to propagate the rotation matrix a
329     // full time step
330    
331     // rotate about the x-axis
332     angle = dt2 * ji[0] / dAtom->getIxx();
333 mmeineke 561 this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
334 mmeineke 558
335     // rotate about the y-axis
336     angle = dt2 * ji[1] / dAtom->getIyy();
337 mmeineke 561 this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
338 mmeineke 558
339     // rotate about the z-axis
340     angle = dt * ji[2] / dAtom->getIzz();
341 mmeineke 561 this->rotate( 0, 1, angle, ji, &Amat[aMatIndex] );
342 mmeineke 558
343     // rotate about the y-axis
344     angle = dt2 * ji[1] / dAtom->getIyy();
345 mmeineke 561 this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
346 mmeineke 558
347     // rotate about the x-axis
348     angle = dt2 * ji[0] / dAtom->getIxx();
349 mmeineke 561 this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
350 mmeineke 558
351     dAtom->setJx( ji[0] );
352     dAtom->setJy( ji[1] );
353     dAtom->setJz( ji[2] );
354     }
355    
356     }
357     }
358    
359    
360     void Integrator::moveB( void ){
361     int i,j,k;
362     int atomIndex;
363     DirectionalAtom* dAtom;
364     double Tb[3];
365     double ji[3];
366    
367     for( i=0; i<nAtoms; i++ ){
368     atomIndex = i * 3;
369    
370     // velocity half step
371     for( j=atomIndex; j<(atomIndex+3); j++ )
372     vel[j] += ( dt2 * frc[j] / atoms[i]->getMass() ) * eConvert;
373    
374     if( atoms[i]->isDirectional() ){
375    
376     dAtom = (DirectionalAtom *)atoms[i];
377    
378     // get and convert the torque to body frame
379    
380     Tb[0] = dAtom->getTx();
381     Tb[1] = dAtom->getTy();
382     Tb[2] = dAtom->getTz();
383    
384     dAtom->lab2Body( Tb );
385    
386     // get the angular momentum, and complete the angular momentum
387     // half step
388    
389     ji[0] = dAtom->getJx() + ( dt2 * Tb[0] ) * eConvert;
390     ji[1] = dAtom->getJy() + ( dt2 * Tb[1] ) * eConvert;
391     ji[2] = dAtom->getJz() + ( dt2 * Tb[2] ) * eConvert;
392    
393     dAtom->setJx( ji[0] );
394     dAtom->setJy( ji[1] );
395     dAtom->setJz( ji[2] );
396     }
397     }
398    
399     }
400    
401     void Integrator::preMove( void ){
402     int i;
403    
404     if( nConstrained ){
405 mmeineke 561
406 mmeineke 558 for(i=0; i<(nAtoms*3); i++) oldPos[i] = pos[i];
407     }
408     }
409    
410     void Integrator::constrainA(){
411    
412     int i,j,k;
413     int done;
414     double pxab, pyab, pzab;
415     double rxab, ryab, rzab;
416 mmeineke 563 int a, b, ax, ay, az, bx, by, bz;
417 mmeineke 558 double rma, rmb;
418     double dx, dy, dz;
419 mmeineke 561 double rpab;
420 mmeineke 558 double rabsq, pabsq, rpabsq;
421     double diffsq;
422     double gab;
423     int iteration;
424    
425    
426    
427     for( i=0; i<nAtoms; i++){
428    
429     moving[i] = 0;
430     moved[i] = 1;
431     }
432 mmeineke 567
433 mmeineke 558 iteration = 0;
434     done = 0;
435     while( !done && (iteration < maxIteration )){
436    
437     done = 1;
438     for(i=0; i<nConstrained; i++){
439    
440     a = constrainedA[i];
441     b = constrainedB[i];
442 mmeineke 563
443     ax = (a*3) + 0;
444     ay = (a*3) + 1;
445     az = (a*3) + 2;
446    
447     bx = (b*3) + 0;
448     by = (b*3) + 1;
449     bz = (b*3) + 2;
450    
451 mmeineke 558 if( moved[a] || moved[b] ){
452    
453 mmeineke 563 pxab = pos[ax] - pos[bx];
454     pyab = pos[ay] - pos[by];
455     pzab = pos[az] - pos[bz];
456 mmeineke 558
457 mmeineke 567 //periodic boundary condition
458 mmeineke 558 pxab = pxab - info->box_x * copysign(1, pxab)
459 mmeineke 563 * (int)( fabs(pxab / info->box_x) + 0.5);
460 mmeineke 558 pyab = pyab - info->box_y * copysign(1, pyab)
461 mmeineke 563 * (int)( fabs(pyab / info->box_y) + 0.5);
462 mmeineke 558 pzab = pzab - info->box_z * copysign(1, pzab)
463 mmeineke 563 * (int)( fabs(pzab / info->box_z) + 0.5);
464 mmeineke 567
465     pabsq = pxab * pxab + pyab * pyab + pzab * pzab;
466    
467 mmeineke 561 rabsq = constrainedDsqr[i];
468 mmeineke 567 diffsq = rabsq - pabsq;
469 mmeineke 558
470     // the original rattle code from alan tidesley
471 mmeineke 563 if (fabs(diffsq) > (tol*rabsq*2)) {
472     rxab = oldPos[ax] - oldPos[bx];
473     ryab = oldPos[ay] - oldPos[by];
474     rzab = oldPos[az] - oldPos[bz];
475 mmeineke 567
476 mmeineke 558 rxab = rxab - info->box_x * copysign(1, rxab)
477 mmeineke 563 * (int)( fabs(rxab / info->box_x) + 0.5);
478 mmeineke 558 ryab = ryab - info->box_y * copysign(1, ryab)
479 mmeineke 563 * (int)( fabs(ryab / info->box_y) + 0.5);
480 mmeineke 558 rzab = rzab - info->box_z * copysign(1, rzab)
481 mmeineke 563 * (int)( fabs(rzab / info->box_z) + 0.5);
482 mmeineke 558
483     rpab = rxab * pxab + ryab * pyab + rzab * pzab;
484 mmeineke 567
485 mmeineke 558 rpabsq = rpab * rpab;
486    
487    
488     if (rpabsq < (rabsq * -diffsq)){
489 mmeineke 563
490 mmeineke 558 #ifdef IS_MPI
491     a = atoms[a]->getGlobalIndex();
492     b = atoms[b]->getGlobalIndex();
493     #endif //is_mpi
494     sprintf( painCave.errMsg,
495 mmeineke 563 "Constraint failure in constrainA at atom %d and %d.\n",
496 mmeineke 558 a, b );
497     painCave.isFatal = 1;
498     simError();
499     }
500    
501     rma = 1.0 / atoms[a]->getMass();
502     rmb = 1.0 / atoms[b]->getMass();
503 mmeineke 567
504 mmeineke 558 gab = diffsq / ( 2.0 * ( rma + rmb ) * rpab );
505 mmeineke 567
506 mmeineke 558 dx = rxab * gab;
507     dy = ryab * gab;
508     dz = rzab * gab;
509    
510 mmeineke 563 pos[ax] += rma * dx;
511     pos[ay] += rma * dy;
512     pos[az] += rma * dz;
513 mmeineke 558
514 mmeineke 563 pos[bx] -= rmb * dx;
515     pos[by] -= rmb * dy;
516     pos[bz] -= rmb * dz;
517 mmeineke 558
518     dx = dx / dt;
519     dy = dy / dt;
520     dz = dz / dt;
521    
522 mmeineke 563 vel[ax] += rma * dx;
523     vel[ay] += rma * dy;
524     vel[az] += rma * dz;
525 mmeineke 558
526 mmeineke 563 vel[bx] -= rmb * dx;
527     vel[by] -= rmb * dy;
528     vel[bz] -= rmb * dz;
529 mmeineke 558
530     moving[a] = 1;
531     moving[b] = 1;
532     done = 0;
533     }
534     }
535     }
536    
537     for(i=0; i<nAtoms; i++){
538    
539     moved[i] = moving[i];
540     moving[i] = 0;
541     }
542    
543     iteration++;
544     }
545    
546     if( !done ){
547    
548 mmeineke 561 sprintf( painCave.errMsg,
549 mmeineke 558 "Constraint failure in constrainA, too many iterations: %d\n",
550 mmeineke 561 iteration );
551 mmeineke 558 painCave.isFatal = 1;
552     simError();
553     }
554    
555     }
556    
557     void Integrator::constrainB( void ){
558    
559     int i,j,k;
560     int done;
561     double vxab, vyab, vzab;
562     double rxab, ryab, rzab;
563 mmeineke 563 int a, b, ax, ay, az, bx, by, bz;
564 mmeineke 558 double rma, rmb;
565     double dx, dy, dz;
566     double rabsq, pabsq, rvab;
567     double diffsq;
568     double gab;
569     int iteration;
570    
571 mmeineke 561 for(i=0; i<nAtoms; i++){
572 mmeineke 558 moving[i] = 0;
573     moved[i] = 1;
574     }
575    
576     done = 0;
577 mmeineke 561 iteration = 0;
578 mmeineke 558 while( !done && (iteration < maxIteration ) ){
579    
580 mmeineke 567 done = 1;
581    
582 mmeineke 558 for(i=0; i<nConstrained; i++){
583    
584     a = constrainedA[i];
585     b = constrainedB[i];
586    
587 mmeineke 567 ax = (a*3) + 0;
588     ay = (a*3) + 1;
589     az = (a*3) + 2;
590 mmeineke 563
591 mmeineke 567 bx = (b*3) + 0;
592     by = (b*3) + 1;
593     bz = (b*3) + 2;
594 mmeineke 563
595 mmeineke 558 if( moved[a] || moved[b] ){
596    
597 mmeineke 563 vxab = vel[ax] - vel[bx];
598     vyab = vel[ay] - vel[by];
599     vzab = vel[az] - vel[bz];
600 mmeineke 558
601 mmeineke 563 rxab = pos[ax] - pos[bx];
602     ryab = pos[ay] - pos[by];
603     rzab = pos[az] - pos[bz];
604 mmeineke 558
605 mmeineke 567
606 mmeineke 558 rxab = rxab - info->box_x * copysign(1, rxab)
607 mmeineke 563 * (int)( fabs(rxab / info->box_x) + 0.5);
608 mmeineke 558 ryab = ryab - info->box_y * copysign(1, ryab)
609 mmeineke 563 * (int)( fabs(ryab / info->box_y) + 0.5);
610 mmeineke 558 rzab = rzab - info->box_z * copysign(1, rzab)
611 mmeineke 563 * (int)( fabs(rzab / info->box_z) + 0.5);
612 mmeineke 567
613 mmeineke 558 rma = 1.0 / atoms[a]->getMass();
614     rmb = 1.0 / atoms[b]->getMass();
615    
616     rvab = rxab * vxab + ryab * vyab + rzab * vzab;
617    
618 mmeineke 561 gab = -rvab / ( ( rma + rmb ) * constrainedDsqr[i] );
619 mmeineke 558
620     if (fabs(gab) > tol) {
621    
622     dx = rxab * gab;
623     dy = ryab * gab;
624     dz = rzab * gab;
625    
626 mmeineke 563 vel[ax] += rma * dx;
627     vel[ay] += rma * dy;
628     vel[az] += rma * dz;
629 mmeineke 558
630 mmeineke 563 vel[bx] -= rmb * dx;
631     vel[by] -= rmb * dy;
632     vel[bz] -= rmb * dz;
633 mmeineke 558
634     moving[a] = 1;
635     moving[b] = 1;
636     done = 0;
637     }
638     }
639     }
640    
641     for(i=0; i<nAtoms; i++){
642     moved[i] = moving[i];
643     moving[i] = 0;
644     }
645    
646     iteration++;
647     }
648    
649     if( !done ){
650    
651    
652 mmeineke 561 sprintf( painCave.errMsg,
653 mmeineke 558 "Constraint failure in constrainB, too many iterations: %d\n",
654 mmeineke 561 iteration );
655 mmeineke 558 painCave.isFatal = 1;
656     simError();
657     }
658    
659     }
660    
661    
662    
663    
664    
665    
666    
667     void Integrator::rotate( int axes1, int axes2, double angle, double ji[3],
668 mmeineke 561 double A[9] ){
669 mmeineke 558
670     int i,j,k;
671     double sinAngle;
672     double cosAngle;
673     double angleSqr;
674     double angleSqrOver4;
675     double top, bottom;
676     double rot[3][3];
677     double tempA[3][3];
678     double tempJ[3];
679    
680     // initialize the tempA
681    
682     for(i=0; i<3; i++){
683     for(j=0; j<3; j++){
684 mmeineke 561 tempA[j][i] = A[3*i + j];
685 mmeineke 558 }
686     }
687    
688     // initialize the tempJ
689    
690     for( i=0; i<3; i++) tempJ[i] = ji[i];
691    
692     // initalize rot as a unit matrix
693    
694     rot[0][0] = 1.0;
695     rot[0][1] = 0.0;
696     rot[0][2] = 0.0;
697    
698     rot[1][0] = 0.0;
699     rot[1][1] = 1.0;
700     rot[1][2] = 0.0;
701    
702     rot[2][0] = 0.0;
703     rot[2][1] = 0.0;
704     rot[2][2] = 1.0;
705    
706     // use a small angle aproximation for sin and cosine
707    
708     angleSqr = angle * angle;
709     angleSqrOver4 = angleSqr / 4.0;
710     top = 1.0 - angleSqrOver4;
711     bottom = 1.0 + angleSqrOver4;
712    
713     cosAngle = top / bottom;
714     sinAngle = angle / bottom;
715    
716     rot[axes1][axes1] = cosAngle;
717     rot[axes2][axes2] = cosAngle;
718    
719     rot[axes1][axes2] = sinAngle;
720     rot[axes2][axes1] = -sinAngle;
721    
722     // rotate the momentum acoording to: ji[] = rot[][] * ji[]
723    
724     for(i=0; i<3; i++){
725     ji[i] = 0.0;
726     for(k=0; k<3; k++){
727     ji[i] += rot[i][k] * tempJ[k];
728     }
729     }
730    
731     // rotate the Rotation matrix acording to:
732     // A[][] = A[][] * transpose(rot[][])
733    
734    
735 mmeineke 561 // NOte for as yet unknown reason, we are performing the
736 mmeineke 558 // calculation as:
737     // transpose(A[][]) = transpose(A[][]) * transpose(rot[][])
738    
739     for(i=0; i<3; i++){
740     for(j=0; j<3; j++){
741 mmeineke 561 A[3*j + i] = 0.0;
742 mmeineke 558 for(k=0; k<3; k++){
743 mmeineke 561 A[3*j + i] += tempA[i][k] * rot[j][k];
744 mmeineke 558 }
745     }
746     }
747     }