Skip to content

Commit 68d7b76

Browse files
authored
Merge pull request #539 from drroe/spam_pairlist
Add pair list to SPAM pure water calc and properly image distances
2 parents db6a1ea + 0d6f2c0 commit 68d7b76

File tree

12 files changed

+29789
-29674
lines changed

12 files changed

+29789
-29674
lines changed

src/Action_Spam.cpp

Lines changed: 167 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
8787

8888
// Get energy cutoff
8989
double cut = actionArgs.getKeyDouble("cut", 12.0);
90+
if (purewater_) {
91+
if (pairList_.InitPairList( cut, 0.1, debug_ )) return Action::ERR;
92+
}
9093
cut2_ = cut * cut;
9194
doublecut_ = 2 * cut;
9295
onecut2_ = 1 / cut2_;
@@ -96,6 +99,7 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
9699
DataSet* ds = init.DSL().AddSet(DataSet::DOUBLE, MetaData(ds_name));
97100
if (ds == 0) return Action::ERR;
98101
if (datafile != 0) datafile->AddDataSet( ds );
102+
ds->ModifyDim(Dimension::X).SetLabel("Index");
99103
myDSL_.push_back( ds );
100104
DG_BULK_ = 0.0;
101105
DH_BULK_ = 0.0;
@@ -205,6 +209,7 @@ Action::RetType Action_Spam::Init(ArgList& actionArgs, ActionInit& init, int deb
205209
mprintf("\tCalculating bulk value for pure solvent\n");
206210
if (datafile != 0)
207211
mprintf("\tPrinting solvent energies to %s\n", datafile->DataFilename().full());
212+
mprintf("\tData set '%s' index is water # * frame.\n", myDSL_[0]->legend());
208213
mprintf("\tUsing a %.2f Angstrom non-bonded cutoff with shifted EEL.\n",
209214
sqrt(cut2_));
210215
if (reorder_)
@@ -261,19 +266,31 @@ Action::RetType Action_Spam::Setup(ActionSetup& setup) {
261266
mprinterr("Error: SPAM: The box appears to be too small for your cutoff!\n");
262267
return Action::ERR;
263268
}
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+
}
264276
// Set up the solvent_residues_ vector
265-
int resnum = 0;
277+
mask_.ResetMask();
278+
int idx = 0;
279+
watidx_.resize( setup.Top().Natom(), -1 );
266280
for (Topology::res_iterator res = setup.Top().ResStart();
267281
res != setup.Top().ResEnd(); res++)
268282
{
269283
if (res->Name().Truncated() == solvname_) {
270284
solvent_residues_.push_back(*res);
271285
// Tabulate COM
272286
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?
274290
mass += setup.Top()[i].Mass();
291+
}
292+
idx++;
275293
}
276-
resnum++;
277294
}
278295
if (solvent_residues_.empty()) {
279296
mprinterr("Error: No solvent residues found with name '%s'\n", solvname_.c_str());
@@ -285,6 +302,11 @@ Action::RetType Action_Spam::Setup(ActionSetup& setup) {
285302
mprintf("\tFound %zu solvent residues [%s]\n", solvent_residues_.size(),
286303
solvname_.c_str());
287304

305+
// Set up pair list
306+
if (purewater_) {
307+
if (pairList_.SetupPairList( currentBox )) return Action::ERR;
308+
}
309+
288310
// Set up the charge array and check that we have enough info
289311
if (SetupParms(setup.Top())) return Action::ERR;
290312

@@ -311,45 +333,9 @@ int Action_Spam::SetupParms(Topology const& ParmIn) {
311333
return 0;
312334
}
313335

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-
347336
// Action_Spam::DoAction()
348337
Action::RetType Action_Spam::DoAction(int frameNum, ActionFrame& frm) {
349338
Nframes_++;
350-
// Calculate unit cell and fractional matrices for non-orthorhombic system
351-
if ( image_.ImageType() == NONORTHO )
352-
frm.Frm().BoxCrd().ToRecip(ucell_, recip_);
353339
// Check that our box is still big enough...
354340
overflow_ = overflow_ || frm.Frm().BoxCrd().BoxX() < doublecut_ ||
355341
frm.Frm().BoxCrd().BoxY() < doublecut_ ||
@@ -360,33 +346,105 @@ Action::RetType Action_Spam::DoAction(int frameNum, ActionFrame& frm) {
360346
return DoSPAM(frameNum, frm.ModifyFrm());
361347
}
362348

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+
363372
// 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+
*/
370378
Action::RetType Action_Spam::DoPureWater(int frameNum, Frame const& frameIn)
371379
{
372380
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;
375384
int basenum = frameNum * solvent_residues_.size();
376385
DataSet_double& evals = static_cast<DataSet_double&>( *myDSL_[0] );
377386
// Make room for each solvent residue energy this frame.
378387
evals.Resize( evals.Size() + solvent_residues_.size() );
379388
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++)
382391
{
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
390448
t_energy_.Stop();
391449
t_action_.Stop();
392450
return Action::OK;
@@ -405,10 +463,53 @@ bool Action_Spam::inside_sphere(Vec3 gp, Vec3 pt, double rad2) const {
405463
(gp[2]-pt[2])*(gp[2]-pt[2]) < rad2 );
406464
}
407465

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+
408506
// Action_Spam::DoSPAM
409507
/** Carries out SPAM analysis on a typical system */
410508
Action::RetType Action_Spam::DoSPAM(int frameNum, Frame& frameIn) {
411509
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_);
412513
t_resCom_.Start();
413514
/* A list of all solvent residues and the sites that they are reserved for. An
414515
* 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) {
417518
resPeakNum_.assign(solvent_residues_.size(), -1);
418519
// Tabulate all of the COMs
419520
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++)
422523
comlist_.push_back(frameIn.VCenterOfMass(res->FirstAtom(), res->LastAtom()));
423524
t_resCom_.Stop();
424525
t_assign_.Start();
@@ -450,8 +551,9 @@ Action::RetType Action_Spam::DoSPAM(int frameNum, Frame& frameIn) {
450551
* this peak's data set in peakFrameData_. If a site is double-occupied, add
451552
* -frameNum to this peak's data set in peakFrameData_.
452553
*/
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
455557
for (Iarray::const_iterator it = resPeakNum_.begin();
456558
it != resPeakNum_.end(); it++)
457559
{
@@ -648,15 +750,15 @@ int Action_Spam::Calc_G_Wat(DataSet* dsIn, unsigned int peaknum)
648750
#ifdef MPI
649751
int Action_Spam::SyncAction() {
650752
// Get total number of frames.
651-
std::vector<int> frames_on_rank( trajComm_.Size() );
753+
Iarray frames_on_rank( trajComm_.Size() );
652754
int myframes = Nframes_;
653755
trajComm_.GatherMaster( &myframes, 1, MPI_INT, &frames_on_rank[0] );
654756
if (trajComm_.Master())
655757
for (int rank = 1; rank < trajComm_.Size(); rank++)
656758
Nframes_ += frames_on_rank[rank];
657759

658760
// Sync peakFrameData_
659-
std::vector<int> size_on_rank( trajComm_.Size() );
761+
Iarray size_on_rank( trajComm_.Size() );
660762
for (unsigned int i = 0; i != peakFrameData_.size(); i++)
661763
{
662764
Iarray& Data = peakFrameData_[i];
@@ -695,6 +797,8 @@ void Action_Spam::Print() {
695797
t_assign_.WriteTiming(2, "Peak assignment :", t_action_.Total());
696798
t_occupy_.WriteTiming(2, "Occupancy calc. :", t_action_.Total());
697799
t_energy_.WriteTiming(2, "Energy calc :", t_action_.Total());
800+
if (purewater_)
801+
pairList_.Timing(t_energy_.Total(), 3);
698802
t_reordr_.WriteTiming(2, "Residue reordering :", t_action_.Total());
699803
t_action_.WriteTiming(1, "SPAM Action Total:");
700804
// Print the spam info file if we didn't do pure water
@@ -729,7 +833,7 @@ void Action_Spam::Print() {
729833

730834
unsigned int p = 0;
731835
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)
733837
{
734838
int err = Calc_G_Wat( *ds, p );
735839
if (err == 1)

0 commit comments

Comments
 (0)