NAMD
ComputeGroupRestraintsCUDA.C
Go to the documentation of this file.
4 #include "SimParameters.h"
5 #include "Node.h"
6 #include "Molecule.h"
7 #include "InfoStream.h"
8 
9 #ifdef NODEGROUP_FORCE_REGISTER
10 GroupRestraintsCUDA::GroupRestraintsCUDA(const GroupRestraintParam *param) {
11  resParam = param;
12  groupName = param->GetGroupName();
13  restraintExp = param->GetExponent();
14  restraintK = param->GetForce();
15  inv_group1_mass = 0.0;
16  inv_group2_mass = 0.0;
17  const std::vector<int> &group1Index = param->GetGroup1AtomIndex();
18  const std::vector<int> &group2Index = param->GetGroup2AtomIndex();
19  numRestrainedGroup1 = group1Index.size();
20  numRestrainedGroup2 = group2Index.size();
21  totalNumRestrained = numRestrainedGroup1 + numRestrainedGroup2;
22  // If we defined a list of atoms for group 1, then we have to
23  // calculate the COM for group 1 at every steps
24  calcGroup1COM = (numRestrainedGroup1 ? true : false);
25  // groupAtomsSOAIndex stores SOAindex of group 1, followed by
26  // SOAindex of group 2
27  groupAtomsSOAIndex.resize(totalNumRestrained);
28  useDistMagnitude = param->GetUseDistMagnitude();
29  Vector center = param->GetResCenter();
30  Vector dir = param->GetResDirection();
31  resDirection = make_double3(dir.x, dir.y, dir.z);
32  resCenterVec = make_double3(center.x, center.y, center.z);
33 
34  // Allocate host and device memory
35  allocate_host<double>(&h_resEnergy, 1);
36  allocate_host<double3>(&h_diffCOM, 1);
37  allocate_host<double3>(&h_group1COM, 1);
38  allocate_host<double3>(&h_group2COM, 1);
39  allocate_host<double3>(&h_resForce, 1);
40  allocate_device<double3>(&d_group1COM, 1);
41  allocate_device<double3>(&d_group2COM, 1);
42  allocate_device<int>(&d_groupAtomsSOAIndex, totalNumRestrained);
43  allocate_device<unsigned int>(&d_tbcatomic, 1);
44  // Set the counter to zero
45  cudaCheck(cudaMemset(d_tbcatomic, 0, sizeof(unsigned int)));
46 
47  // Check the atom index and calculate he inverse mass
48  Molecule *mol = Node::Object()->molecule;
49  int totalAtoms = mol->numAtoms;
50  double total_mass = 0.0;
51 
52  for (int i = 0; i < numRestrainedGroup2; ++i) {
53  int index = group2Index[i];
54  if (index > -1 && index < totalAtoms) {
55  total_mass += mol->atommass(index);
56  } else {
57  char err_msg[512];
58  sprintf(err_msg, "Group restraints: Bad atom index for %s!"
59  " Atom indices must be within [%d, %d].\n", groupName, 0, totalAtoms - 1);
60  NAMD_die(err_msg);
61  }
62  }
63  inv_group2_mass = 1.0 / total_mass;
64 
65  // Do we need to calculate COM of group 1, or we have a
66  // reference position for it?
67  if (calcGroup1COM) {
68  total_mass = 0.0;
69  for (int i = 0; i < numRestrainedGroup1; ++i) {
70  int index = group1Index[i];
71  if (index > -1 && index < totalAtoms) {
72  total_mass += mol->atommass(index);
73  } else {
74  char err_msg[512];
75  sprintf(err_msg, "Group restraints: Bad atom index for %s!"
76  " Atom indices must be within [%d, %d].\n", groupName, 0, totalAtoms - 1);
77  NAMD_die(err_msg);
78  }
79  }
80  inv_group1_mass = 1.0 / total_mass;
81  } else {
82  // We defined the reference point for COM of group 1, so no need
83  // to calculate it, just copy it.
84  // Set the h_group1COM to reference COM position of group 1
85  Vector ref = param->GetGroupRes1Position();
86  h_group1COM->x = ref.x;
87  h_group1COM->y = ref.y;
88  h_group1COM->z = ref.z;
89  }
90 }
91 
92 GroupRestraintsCUDA::~GroupRestraintsCUDA() {
93  deallocate_host<double>(&h_resEnergy);
94  deallocate_host<double3>(&h_resForce);
95  deallocate_host<double3>(&h_diffCOM);
96  deallocate_host<double3>(&h_group1COM);
97  deallocate_host<double3>(&h_group2COM);
98  deallocate_device<double3>(&d_group1COM);
99  deallocate_device<double3>(&d_group2COM);
100  deallocate_device<int>(&d_groupAtomsSOAIndex);
101  deallocate_device<unsigned int>(&d_tbcatomic);
102 }
103 
105 void GroupRestraintsCUDA::updateAtoms(
106  std::vector<AtomMap*> &atomMapsList,
107  std::vector<CudaLocalRecord> &localRecords,
108  const int *h_globalToLocalID) {
109 
110  // If we need to calculate COM of group 1, we have to store
111  // index to SOA data structures for group 1
112  if(calcGroup1COM) {
113  const std::vector<int> &group1Index = resParam->GetGroup1AtomIndex();
114  if(numRestrainedGroup1 != group1Index.size()) {
115  char err_msg[512];
116  sprintf("Number of atoms in group 1 restraint for '%s' is changed!", groupName);
117  NAMD_bug(err_msg);
118  }
119 
120  // Map the global index to local position in SOA data structure
121  for(int i = 0 ; i < numRestrainedGroup1; ++i){
122  int gid = group1Index[i];
123  LocalID lid;
124  // Search for a valid localID in all atoms
125  for(int j = 0 ; j < atomMapsList.size(); ++j){
126  lid = atomMapsList[j]->localID(gid);
127  if( lid.pid != -1) {
128  break;
129  }
130  }
131 
132  // Fields of lid need to be != -1, bc the atom needs to be somewhere
133  // otherwise we have a bug
134  if(lid.pid == -1){
135  NAMD_bug("LocalAtomID not found in patchMap");
136  }
137 
138  // Converts global patch ID to its local position in our SOA data structures
139  int soaPid = h_globalToLocalID[lid.pid];
140  int soaIndex = localRecords[soaPid].bufferOffset + lid.index;
141 
142  groupAtomsSOAIndex[i] = soaIndex;
143  }
144  // Sort vector for better coalesce memory access. Just sort only group 1
145  std::sort(groupAtomsSOAIndex.begin(), groupAtomsSOAIndex.begin() + numRestrainedGroup1);
146  }
147 
148  // We always calculate the COM of group 2, so we store
149  // SOAIndex of group 2, after group 1 index
150  const std::vector<int> &group2Index = resParam->GetGroup2AtomIndex();
151  if(numRestrainedGroup2 != group2Index.size()) {
152  char err_msg[512];
153  sprintf("Number of atoms in group 2 restraint for '%s' is changed!", groupName);
154  NAMD_bug(err_msg);
155  }
156 
157  // Map the global index to local position in SOA data structure
158  for(int i = 0 ; i < numRestrainedGroup2; ++i){
159  int gid = group2Index[i];
160  LocalID lid;
161  // Search for a valid localID in all atoms
162  for(int j = 0 ; j < atomMapsList.size(); ++j){
163  lid = atomMapsList[j]->localID(gid);
164  if( lid.pid != -1) {
165  break;
166  }
167  }
168 
169  // Fields of lid need to be != -1, bc the atom needs to be somewhere
170  // otherwise we have a bug
171  if(lid.pid == -1){
172  NAMD_bug("LocalAtomID not found in patchMap");
173  }
174 
175  // Converts global patch ID to its local position in our SOA data structures
176  int soaPid = h_globalToLocalID[lid.pid];
177  int soaIndex = localRecords[soaPid].bufferOffset + lid.index;
178  // store the index for group 2, after group 1 index
179  groupAtomsSOAIndex[i + numRestrainedGroup1] = soaIndex;
180  }
181  // Sort vector for better coalesce memory access. Sort only for group 2
182  std::sort(groupAtomsSOAIndex.begin() + numRestrainedGroup1, groupAtomsSOAIndex.end());
183 
184  // Update the SOA index in device
185  copy_HtoD<int>(groupAtomsSOAIndex.data(), d_groupAtomsSOAIndex, totalNumRestrained);
186 }
187 
189 void GroupRestraintsCUDA::doForce(
190  const int timeStep,
191  const int doEnergy,
192  const int doVirial,
193  const int doOutput,
194  const Lattice &lat,
195  const char3* d_transform,
196  const float* d_mass,
197  const double* d_pos_x,
198  const double* d_pos_y,
199  const double* d_pos_z,
200  double* d_f_normal_x,
201  double* d_f_normal_y,
202  double* d_f_normal_z,
203  cudaTensor* d_virial,
204  double* h_extEnergy,
205  double3* h_extForce,
206  cudaTensor* h_extVirial,
207  cudaStream_t stream) {
208 
209  if (calcGroup1COM) {
210  computeGroupRestraint_2Group(
211  useDistMagnitude,
212  doEnergy,
213  doVirial,
214  this->numRestrainedGroup1,
215  this->totalNumRestrained,
216  this->restraintExp,
217  this->restraintK,
218  this->resCenterVec,
219  this->resDirection,
220  this->inv_group1_mass,
221  this->inv_group2_mass,
222  this->d_groupAtomsSOAIndex,
223  lat,
224  d_transform,
225  d_mass,
226  d_pos_x,
227  d_pos_y,
228  d_pos_z,
229  d_f_normal_x,
230  d_f_normal_y,
231  d_f_normal_z,
232  d_virial,
233  h_extVirial,
234  this->h_resEnergy,
235  this->h_resForce,
236  this->h_group1COM,
237  this->h_group2COM,
238  this->h_diffCOM,
239  this->d_group1COM,
240  this->d_group2COM,
241  this->d_tbcatomic,
242  stream);
243  } else {
244  computeGroupRestraint_1Group(
245  useDistMagnitude,
246  doEnergy,
247  doVirial,
248  this->numRestrainedGroup2,
249  this->restraintExp,
250  this->restraintK,
251  this->resCenterVec,
252  this->resDirection,
253  this->inv_group2_mass,
254  this->d_groupAtomsSOAIndex,
255  lat,
256  d_transform,
257  d_mass,
258  d_pos_x,
259  d_pos_y,
260  d_pos_z,
261  d_f_normal_x,
262  d_f_normal_y,
263  d_f_normal_z,
264  d_virial,
265  h_extVirial,
266  this->h_resEnergy,
267  this->h_resForce,
268  this->h_group1COM,
269  this->h_group2COM,
270  this->h_diffCOM,
271  this->d_group2COM,
272  this->d_tbcatomic,
273  stream);
274  }
275 
276 
277  if(doOutput){
278  cudaCheck(cudaStreamSynchronize(stream));
279  // sum up external energy and virial from this group
280  h_extEnergy[0] += h_resEnergy[0];
281  // If we have restraint to reference point, then we have net force
282  // otherwise the net force is zero for restraining two atom groups
283  if (!calcGroup1COM) {
284  h_extForce->x += h_resForce->x;
285  h_extForce->y += h_resForce->y;
286  h_extForce->z += h_resForce->z;
287  }
288 
289  char msg[1024];
290  sprintf(msg,"GRES: %9d %14s %14.4f %14.4f %14.4f %19.4f %14.4f %14.4f %14.4f\n",
291  timeStep, groupName, h_diffCOM->x, h_diffCOM->y, h_diffCOM->z,
292  h_resForce->x, h_resForce->y, h_resForce->z, h_resEnergy[0]);
293  iout << msg << endi;
294 
295  // {
296  // printf("!!!Accu. exForce: %14.8f %14.8f %14.8f, Vir.x: %14.8f %14.8f %14.8f,"
297  // "Vir.y: %14.8f %14.8f %14.8f, Vir.z: %14.8f %14.8f %14.8f \n",
298  // h_extForce->x, h_extForce->y, h_extForce->z,
299  // h_extVirial->xx, h_extVirial->xy, h_extVirial->xz,
300  // h_extVirial->yx, h_extVirial->yy, h_extVirial->yz,
301  // h_extVirial->zx, h_extVirial->zy, h_extVirial->zz);
302  // }
303  }
304 }
305 
306 // ###########################################################################
307 // # ComputeGroupRestraintsCUDA functions
308 // ###########################################################################
309 
310 ComputeGroupRestraintsCUDA::ComputeGroupRestraintsCUDA(const int ouputFreq,
311  const GroupRestraintList &resList) {
312  gResOutputFreq = ouputFreq;
313  const std::map<std::string, GroupRestraintParam*> & groupMap = resList.GetGroupResMap();
314  for (auto it = groupMap.begin(); it != groupMap.end(); ++it) {
315  GroupRestraintsCUDA * gResCUDA = new GroupRestraintsCUDA(it->second);
316  restraintsCUDAList.push_back(gResCUDA);
317  }
318 }
319 
320 ComputeGroupRestraintsCUDA::~ComputeGroupRestraintsCUDA() {
321  int numGroup = restraintsCUDAList.size();
322  for (int i = 0; i < numGroup; ++i) {
323  delete restraintsCUDAList[i];
324  }
325  restraintsCUDAList.clear();
326 }
327 
329 void ComputeGroupRestraintsCUDA::updateAtoms(
330  std::vector<AtomMap*> &atomMapsList,
331  std::vector<CudaLocalRecord> &localRecords,
332  const int *h_globalToLocalID) {
333 
334  int numGroup = restraintsCUDAList.size();
335  for (int i = 0; i < numGroup; ++i) {
336  restraintsCUDAList[i]->updateAtoms(atomMapsList, localRecords, h_globalToLocalID);
337  }
338 }
339 
341 void ComputeGroupRestraintsCUDA::doForce(
342  const int timeStep,
343  const int doEnergy,
344  const int doVirial,
345  const Lattice &lat,
346  const char3* d_transform,
347  const float* d_mass,
348  const double* d_pos_x,
349  const double* d_pos_y,
350  const double* d_pos_z,
351  double* d_f_normal_x,
352  double* d_f_normal_y,
353  double* d_f_normal_z,
354  cudaTensor* d_virial,
355  double* h_extEnergy,
356  double3* h_extForce,
357  cudaTensor* h_extVirial,
358  cudaStream_t stream) {
359 
360  const int doOutput = (timeStep % gResOutputFreq) == 0;
361  // Since output freq is same as energyOutputFrq, we need to calculate virial
362  // for outputting energy data
363  int doVirCalc = (doOutput ? 1 : doVirial);
364  int numGroup = restraintsCUDAList.size();
365 
366  // Reset the values before we add the energy, force, and virial value
367  // for each restraint group
368  h_extEnergy[0] = 0.0;
369  h_extForce->x = 0.0;
370  h_extForce->y = 0.0;
371  h_extForce->z = 0.0;
372  h_extVirial->xx = 0.0;
373  h_extVirial->xy = 0.0;
374  h_extVirial->xz = 0.0;
375  h_extVirial->yx = 0.0;
376  h_extVirial->yy = 0.0;
377  h_extVirial->yz = 0.0;
378  h_extVirial->zx = 0.0;
379  h_extVirial->zy = 0.0;
380  h_extVirial->zz = 0.0;
381 
382  if(doOutput){
383  if(timeStep % (100 * gResOutputFreq) == 0) {
384  char msg[1024];
385  sprintf(msg,"\nGRES_TITLE: %3s %14s %14s %14s %14s %19s %14s %14s %14s\n",
386  "TS", "GROUP_NAME", "DISTANCE.X", "DISTANCE.Y", "DISTANCE.Z",
387  "FORCE.X", "FORCE.Y", "FORCE.Z", "ENERGY");
388  iout << msg << endi;
389  }
390  }
391 
392  for (int gIdx = 0; gIdx < numGroup; ++gIdx) {
393  restraintsCUDAList[gIdx]->doForce(
394  timeStep, doEnergy, doVirCalc, doOutput, lat, d_transform,
395  d_mass, d_pos_x, d_pos_y, d_pos_z,
396  d_f_normal_x, d_f_normal_y, d_f_normal_z, d_virial,
397  h_extEnergy, h_extForce, h_extVirial, stream);
398  }
399  if(doOutput) {
400  iout <<"\n" << endi;;
401  }
402 }
403 
404 
405 
406 
407 #endif
static Node * Object()
Definition: Node.h:86
BigReal yy
Definition: CudaUtils.h:80
BigReal zz
Definition: CudaUtils.h:84
BigReal yx
Definition: CudaUtils.h:79
Definition: Vector.h:72
BigReal yz
Definition: CudaUtils.h:81
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
BigReal z
Definition: Vector.h:74
#define iout
Definition: InfoStream.h:51
Molecule stores the structural information for the system.
Definition: Molecule.h:175
const std::map< std::string, GroupRestraintParam * > & GetGroupResMap() const
int32 index
Definition: NamdTypes.h:290
Vector GetGroupRes1Position() const
Vector GetResDirection() const
NAMD_HOST_DEVICE double3 make_double3(float3 a)
Definition: Vector.h:343
void NAMD_bug(const char *err_msg)
Definition: common.C:195
BigReal xx
Definition: CudaUtils.h:76
const char * GetGroupName() const
BigReal zx
Definition: CudaUtils.h:82
BigReal x
Definition: Vector.h:74
int numAtoms
Definition: Molecule.h:585
void NAMD_die(const char *err_msg)
Definition: common.C:147
PatchID pid
Definition: NamdTypes.h:289
Real atommass(int anum) const
Definition: Molecule.h:1107
BigReal xz
Definition: CudaUtils.h:78
Vector GetResCenter() const
BigReal y
Definition: Vector.h:74
const std::vector< int > & GetGroup2AtomIndex() const
#define cudaCheck(stmt)
Definition: CudaUtils.h:233
bool GetUseDistMagnitude() const
Molecule * molecule
Definition: Node.h:179
const std::vector< int > & GetGroup1AtomIndex() const
BigReal zy
Definition: CudaUtils.h:83
BigReal xy
Definition: CudaUtils.h:77