@@ -87,6 +87,9 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
87
87
88
88
// Get energy cutoff
89
89
double cut = actionArgs.getKeyDouble (" cut" , 12.0 );
90
+ if (purewater_) {
91
+ if (pairList_.InitPairList ( cut, 0.1 , debug_ )) return Action::ERR;
92
+ }
90
93
cut2_ = cut * cut;
91
94
doublecut_ = 2 * cut;
92
95
onecut2_ = 1 / cut2_;
@@ -96,6 +99,7 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
96
99
DataSet* ds = init.DSL ().AddSet (DataSet::DOUBLE, MetaData (ds_name));
97
100
if (ds == 0 ) return Action::ERR;
98
101
if (datafile != 0 ) datafile->AddDataSet ( ds );
102
+ ds->ModifyDim (Dimension::X).SetLabel (" Index" );
99
103
myDSL_.push_back ( ds );
100
104
DG_BULK_ = 0.0 ;
101
105
DH_BULK_ = 0.0 ;
@@ -205,6 +209,7 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
205
209
mprintf (" \t Calculating bulk value for pure solvent\n " );
206
210
if (datafile != 0 )
207
211
mprintf (" \t Printing solvent energies to %s\n " , datafile->DataFilename ().full ());
212
+ mprintf (" \t Data set '%s' index is water # * frame.\n " , myDSL_[0 ]->legend ());
208
213
mprintf (" \t Using a %.2f Angstrom non-bonded cutoff with shifted EEL.\n " ,
209
214
sqrt (cut2_));
210
215
if (reorder_)
@@ -261,19 +266,31 @@ Action::RetType Action_Spam::Setup(ActionSetup& setup) {
261
266
mprinterr (" Error: SPAM: The box appears to be too small for your cutoff!\n " );
262
267
return Action::ERR;
263
268
}
269
+ // Set up imaging info for this parm
270
+ image_.SetupImaging ( setup.CoordInfo ().TrajBox ().Type () );
271
+ // SANITY CHECK - imaging should always be active.
272
+ if (!image_.ImagingEnabled ()) {
273
+ mprinterr (" Interal Error: Imaging info not properly set up for Action_Spam\n " );
274
+ return Action::ERR;
275
+ }
264
276
// Set up the solvent_residues_ vector
265
- int resnum = 0 ;
277
+ mask_.ResetMask ();
278
+ int idx = 0 ;
279
+ watidx_.resize ( setup.Top ().Natom (), -1 );
266
280
for (Topology::res_iterator res = setup.Top ().ResStart ();
267
281
res != setup.Top ().ResEnd (); res++)
268
282
{
269
283
if (res->Name ().Truncated () == solvname_) {
270
284
solvent_residues_.push_back (*res);
271
285
// Tabulate COM
272
286
double mass = 0.0 ;
273
- for (int i = res->FirstAtom (); i < res->LastAtom (); i++)
287
+ for (int i = res->FirstAtom (); i < res->LastAtom (); i++) {
288
+ mask_.AddAtom ( i );
289
+ watidx_[i] = idx; // TODO currently purewater only - skip if not purewater?
274
290
mass += setup.Top ()[i].Mass ();
291
+ }
292
+ idx++;
275
293
}
276
- resnum++;
277
294
}
278
295
if (solvent_residues_.empty ()) {
279
296
mprinterr (" Error: No solvent residues found with name '%s'\n " , solvname_.c_str ());
@@ -285,6 +302,11 @@ Action::RetType Action_Spam::Setup(ActionSetup& setup) {
285
302
mprintf (" \t Found %zu solvent residues [%s]\n " , solvent_residues_.size (),
286
303
solvname_.c_str ());
287
304
305
+ // Set up pair list
306
+ if (purewater_) {
307
+ if (pairList_.SetupPairList ( currentBox )) return Action::ERR;
308
+ }
309
+
288
310
// Set up the charge array and check that we have enough info
289
311
if (SetupParms (setup.Top ())) return Action::ERR;
290
312
@@ -311,45 +333,9 @@ int Action_Spam::SetupParms(Topology const& ParmIn) {
311
333
return 0 ;
312
334
}
313
335
314
- // Action_Spam::Calculate_Energy()
315
- double Action_Spam::Calculate_Energy (Frame const & frameIn, Residue const & res) {
316
- // The first atom of the solvent residue we want the energy from
317
- double result = 0 ;
318
-
319
- // Now loop through all atoms in the residue and loop through the pairlist to
320
- // get the energies
321
- for (int i = res.FirstAtom (); i < res.LastAtom (); i++) {
322
- Vec3 atm1 = Vec3 (frameIn.XYZ (i));
323
- for (int j = 0 ; j < CurrentParm_->Natom (); j++) {
324
- if (j >= res.FirstAtom () && j < res.LastAtom ()) continue ;
325
- Vec3 atm2 = Vec3 (frameIn.XYZ (j));
326
- double dist2;
327
- // Get imaged distance
328
- switch ( image_.ImageType () ) {
329
- case NONORTHO : dist2 = DIST2_ImageNonOrtho (atm1, atm2, ucell_, recip_); break ;
330
- case ORTHO : dist2 = DIST2_ImageOrtho (atm1, atm2, frameIn.BoxCrd ()); break ;
331
- default : dist2 = DIST2_NoImage (atm1, atm2); break ;
332
- }
333
- if (dist2 < cut2_) {
334
- double qiqj = atom_charge_[i] * atom_charge_[j];
335
- NonbondType const & LJ = CurrentParm_->GetLJparam (i, j);
336
- double r2 = 1 / dist2;
337
- double r6 = r2 * r2 * r2;
338
- // Shifted electrostatics: qiqj/r * (1-r/rcut)^2 + VDW
339
- double shift = (1 - dist2 * onecut2_);
340
- result += qiqj / sqrt (dist2) * shift * shift + LJ.A () * r6 * r6 - LJ.B () * r6;
341
- }
342
- }
343
- }
344
- return result;
345
- }
346
-
347
336
// Action_Spam::DoAction()
348
337
Action::RetType Action_Spam::DoAction (int frameNum, ActionFrame& frm) {
349
338
Nframes_++;
350
- // Calculate unit cell and fractional matrices for non-orthorhombic system
351
- if ( image_.ImageType () == NONORTHO )
352
- frm.Frm ().BoxCrd ().ToRecip (ucell_, recip_);
353
339
// Check that our box is still big enough...
354
340
overflow_ = overflow_ || frm.Frm ().BoxCrd ().BoxX () < doublecut_ ||
355
341
frm.Frm ().BoxCrd ().BoxY () < doublecut_ ||
@@ -360,33 +346,105 @@ Action::RetType Action_Spam::DoAction(int frameNum, ActionFrame& frm) {
360
346
return DoSPAM (frameNum, frm.ModifyFrm ());
361
347
}
362
348
349
+ /* * \return Energy between atoms i and j with given distance squared.
350
+ * \param i Absolute atom index for atom i.
351
+ * \param j Absolute atom index for atom j.
352
+ * \param dist2 Distance squared between atoms i and j.
353
+ */
354
+ double Action_Spam::Ecalc (int i, int j, double dist2) const {
355
+ double qiqj = atom_charge_[i] * atom_charge_[j];
356
+ NonbondType const & LJ = CurrentParm_->GetLJparam (i, j);
357
+ double r2 = 1 / dist2;
358
+ double r6 = r2 * r2 * r2;
359
+ // Shifted electrostatics: qiqj/r * (1-r/rcut)^2 + VDW
360
+ double shift = (1 - dist2 * onecut2_);
361
+ double eval = (qiqj / sqrt (dist2) * shift * shift + LJ.A () * r6 * r6 - LJ.B () * r6);
362
+ // if (i < j) {
363
+ // if (i > 2 && i < 6)
364
+ // mprintf("DEBUG: %6i %6i %8.3f %8.3f\n", i, j, sqrt(dist2), eval);
365
+ // } else {
366
+ // if (j > 2 && j < 6)
367
+ // mprintf("DEBUG: %6i %6i %8.3f %8.3f\n", j, i, sqrt(dist2), eval);
368
+ // }
369
+ return eval;
370
+ }
371
+
363
372
// Action_Spam::DoPureWater
364
- /* * Carries out SPAM analysis for pure water to parametrize bulk */
365
- /* This is relatively simple... We have to loop through every water molecule
366
- * for every frame, calculate the energy of that solvent molecule, and add
367
- * that to our one data set. Therefore we will have NFRAMES * NWATER data
368
- * points
369
- */
373
+ /* * Carries out SPAM analysis for pure water to parametrize bulk.
374
+ * This is relatively simple. For each frame, calculate the interaction
375
+ * energy for every water to every other water in the system. Therefore
376
+ * we will have NFRAMES * NWATER data points total.
377
+ */
370
378
Action::RetType Action_Spam::DoPureWater (int frameNum, Frame const & frameIn)
371
379
{
372
380
t_action_.Start ();
373
- int wat = 0 ;
374
- int maxwat = (int )solvent_residues_.size ();
381
+ frameIn.BoxCrd ().ToRecip (ucell_, recip_);
382
+ pairList_.CreatePairList (frameIn, ucell_, recip_, mask_);
383
+ int wat = 0 , wat1 = 0 ;
375
384
int basenum = frameNum * solvent_residues_.size ();
376
385
DataSet_double& evals = static_cast <DataSet_double&>( *myDSL_[0 ] );
377
386
// Make room for each solvent residue energy this frame.
378
387
evals.Resize ( evals.Size () + solvent_residues_.size () );
379
388
t_energy_.Start ();
380
- # ifdef _OPENMP
381
- # pragma omp parallel private(wat )
389
+ // Loop over all grid cells
390
+ for ( int cidx = 0 ; cidx < pairList_. NGridMax (); cidx++ )
382
391
{
383
- # pragma omp for
384
- # endif
385
- for (wat = 0 ; wat < maxwat; wat++)
386
- evals[basenum + wat] = Calculate_Energy (frameIn, solvent_residues_[wat]);
387
- # ifdef _OPENMP
388
- }
389
- # endif
392
+ PairList::CellType const & thisCell = pairList_.Cell ( cidx );
393
+ if (thisCell.NatomsInGrid () > 0 )
394
+ {
395
+ // cellList contains this cell index and all neighbors.
396
+ PairList::Iarray const & cellList = thisCell.CellList ();
397
+ // transList contains index to translation for the neighbor.
398
+ PairList::Iarray const & transList = thisCell.TransList ();
399
+ // Loop over all atoms of thisCell.
400
+ for (PairList::CellType::const_iterator it0 = thisCell.begin ();
401
+ it0 != thisCell.end (); ++it0)
402
+ {
403
+ wat = watidx_[it0->Idx ()];
404
+ int atomi = mask_[it0->Idx ()];
405
+ Vec3 const & xyz0 = it0->ImageCoords ();
406
+ // Calc interaction of atom to all other atoms in thisCell.
407
+ for (PairList::CellType::const_iterator it1 = it0 + 1 ;
408
+ it1 != thisCell.end (); ++it1)
409
+ {
410
+ wat1 = watidx_[it1->Idx ()];
411
+ if ( wat != wat1 ) {
412
+ Vec3 const & xyz1 = it1->ImageCoords ();
413
+ Vec3 dxyz = xyz1 - xyz0;
414
+ double D2 = dxyz.Magnitude2 ();
415
+ if (D2 < cut2_) {
416
+ double eval = Ecalc (atomi, mask_[it1->Idx ()], D2);
417
+ evals[basenum + wat] += eval;
418
+ evals[basenum + wat1] += eval;
419
+ }
420
+ }
421
+ } // END loop over all other atoms in thisCell
422
+ // Loop over all neighbor cells
423
+ for (unsigned int nidx = 1 ; nidx != cellList.size (); nidx++)
424
+ {
425
+ PairList::CellType const & nbrCell = pairList_.Cell ( cellList[nidx] );
426
+ // Translate vector for neighbor cell
427
+ Vec3 const & tVec = pairList_.TransVec ( transList[nidx] );
428
+ // Loop over every atom in nbrCell
429
+ for (PairList::CellType::const_iterator it1 = nbrCell.begin ();
430
+ it1 != nbrCell.end (); ++it1)
431
+ {
432
+ wat1 = watidx_[it1->Idx ()];
433
+ if ( wat != wat1 ) {
434
+ Vec3 const & xyz1 = it1->ImageCoords ();
435
+ Vec3 dxyz = xyz1 + tVec - xyz0;
436
+ double D2 = dxyz.Magnitude2 ();
437
+ if (D2 < cut2_) {
438
+ double eval = Ecalc (atomi, mask_[it1->Idx ()], D2);
439
+ evals[basenum + wat] += eval;
440
+ evals[basenum + wat1] += eval;
441
+ }
442
+ }
443
+ } // END loop over atoms in neighbor cell
444
+ } // END loop over neighbor cells
445
+ } // END loop over atoms in thisCell
446
+ } // END cell not empty
447
+ } // END loop over grid cells
390
448
t_energy_.Stop ();
391
449
t_action_.Stop ();
392
450
return Action::OK;
@@ -405,10 +463,53 @@ bool Action_Spam::inside_sphere(Vec3 gp, Vec3 pt, double rad2) const {
405
463
(gp[2 ]-pt[2 ])*(gp[2 ]-pt[2 ]) < rad2 );
406
464
}
407
465
466
+ // Action_Spam::Calculate_Energy()
467
+ /* * Calculate energy between given residue and all other residues in the
468
+ * system within the cutoff.
469
+ */
470
+ double Action_Spam::Calculate_Energy (Frame const & frameIn, Residue const & res) {
471
+ // The first atom of the solvent residue we want the energy from
472
+ double result = 0 ;
473
+
474
+ // Now loop through all atoms in the residue and loop through the pairlist to
475
+ // get the energies
476
+ for (int i = res.FirstAtom (); i < res.LastAtom (); i++) {
477
+ Vec3 atm1 = Vec3 (frameIn.XYZ (i));
478
+ for (int j = 0 ; j < CurrentParm_->Natom (); j++) {
479
+ if (j >= res.FirstAtom () && j < res.LastAtom ()) continue ;
480
+ Vec3 atm2 = Vec3 (frameIn.XYZ (j));
481
+ double dist2;
482
+ // Get imaged distance
483
+ switch ( image_.ImageType () ) {
484
+ case NONORTHO : dist2 = DIST2_ImageNonOrtho (atm1, atm2, ucell_, recip_); break ;
485
+ case ORTHO : dist2 = DIST2_ImageOrtho (atm1, atm2, frameIn.BoxCrd ()); break ;
486
+ default : dist2 = DIST2_NoImage (atm1, atm2); break ;
487
+ }
488
+ if (dist2 < cut2_) {
489
+ double qiqj = atom_charge_[i] * atom_charge_[j];
490
+ NonbondType const & LJ = CurrentParm_->GetLJparam (i, j);
491
+ double r2 = 1 / dist2;
492
+ double r6 = r2 * r2 * r2;
493
+ // Shifted electrostatics: qiqj/r * (1-r/rcut)^2 + VDW
494
+ double shift = (1 - dist2 * onecut2_);
495
+ // result += qiqj / sqrt(dist2) * shift * shift + LJ.A() * r6 * r6 - LJ.B() * r6;
496
+ double eval = qiqj / sqrt (dist2) * shift * shift + LJ.A () * r6 * r6 - LJ.B () * r6;
497
+ // if (i > 2 && i < 6)
498
+ // mprintf("DEBUG: %6i %6i %8.3f %8.3f\n", i, j, sqrt(dist2), eval);
499
+ result += eval;
500
+ }
501
+ }
502
+ }
503
+ return result;
504
+ }
505
+
408
506
// Action_Spam::DoSPAM
409
507
/* * Carries out SPAM analysis on a typical system */
410
508
Action::RetType Action_Spam::DoSPAM (int frameNum, Frame& frameIn) {
411
509
t_action_.Start ();
510
+ // Calculate unit cell and fractional matrices for non-orthorhombic system
511
+ if ( image_.ImageType () == NONORTHO )
512
+ frameIn.BoxCrd ().ToRecip (ucell_, recip_);
412
513
t_resCom_.Start ();
413
514
/* A list of all solvent residues and the sites that they are reserved for. An
414
515
* unreserved solvent residue has an index -1. At the end, we will go through
@@ -417,8 +518,8 @@ Action::RetType Action_Spam::DoSPAM(int frameNum, Frame& frameIn) {
417
518
resPeakNum_.assign (solvent_residues_.size (), -1 );
418
519
// Tabulate all of the COMs
419
520
comlist_.clear ();
420
- for (std::vector<Residue> ::const_iterator res = solvent_residues_.begin ();
421
- res != solvent_residues_.end (); res++)
521
+ for (Rarray ::const_iterator res = solvent_residues_.begin ();
522
+ res != solvent_residues_.end (); res++)
422
523
comlist_.push_back (frameIn.VCenterOfMass (res->FirstAtom (), res->LastAtom ()));
423
524
t_resCom_.Stop ();
424
525
t_assign_.Start ();
@@ -450,8 +551,9 @@ Action::RetType Action_Spam::DoSPAM(int frameNum, Frame& frameIn) {
450
551
* this peak's data set in peakFrameData_. If a site is double-occupied, add
451
552
* -frameNum to this peak's data set in peakFrameData_.
452
553
*/
453
- std::vector<bool > occupied (peaks_.size (), false );
454
- std::vector<bool > doubled (peaks_.size (), false ); // to avoid double-additions
554
+ typedef std::vector<bool > Barray;
555
+ Barray occupied (peaks_.size (), false );
556
+ Barray doubled (peaks_.size (), false ); // to avoid double-additions
455
557
for (Iarray::const_iterator it = resPeakNum_.begin ();
456
558
it != resPeakNum_.end (); it++)
457
559
{
@@ -648,15 +750,15 @@ int Action_Spam::Calc_G_Wat(DataSet* dsIn, unsigned int peaknum)
648
750
#ifdef MPI
649
751
int Action_Spam::SyncAction () {
650
752
// Get total number of frames.
651
- std::vector< int > frames_on_rank ( trajComm_.Size () );
753
+ Iarray frames_on_rank ( trajComm_.Size () );
652
754
int myframes = Nframes_;
653
755
trajComm_.GatherMaster ( &myframes, 1 , MPI_INT, &frames_on_rank[0 ] );
654
756
if (trajComm_.Master ())
655
757
for (int rank = 1 ; rank < trajComm_.Size (); rank++)
656
758
Nframes_ += frames_on_rank[rank];
657
759
658
760
// Sync peakFrameData_
659
- std::vector< int > size_on_rank ( trajComm_.Size () );
761
+ Iarray size_on_rank ( trajComm_.Size () );
660
762
for (unsigned int i = 0 ; i != peakFrameData_.size (); i++)
661
763
{
662
764
Iarray& Data = peakFrameData_[i];
@@ -695,6 +797,8 @@ void Action_Spam::Print() {
695
797
t_assign_.WriteTiming (2 , " Peak assignment :" , t_action_.Total ());
696
798
t_occupy_.WriteTiming (2 , " Occupancy calc. :" , t_action_.Total ());
697
799
t_energy_.WriteTiming (2 , " Energy calc :" , t_action_.Total ());
800
+ if (purewater_)
801
+ pairList_.Timing (t_energy_.Total (), 3 );
698
802
t_reordr_.WriteTiming (2 , " Residue reordering :" , t_action_.Total ());
699
803
t_action_.WriteTiming (1 , " SPAM Action Total:" );
700
804
// Print the spam info file if we didn't do pure water
@@ -729,7 +833,7 @@ void Action_Spam::Print() {
729
833
730
834
unsigned int p = 0 ;
731
835
int n_peaks_no_energy = 0 ;
732
- for (std::vector<DataSet*> ::const_iterator ds = myDSL_.begin (); ds != myDSL_.end (); ++ds, ++p)
836
+ for (DSarray ::const_iterator ds = myDSL_.begin (); ds != myDSL_.end (); ++ds, ++p)
733
837
{
734
838
int err = Calc_G_Wat ( *ds, p );
735
839
if (err == 1 )
0 commit comments