NAMD
LincsSolver.C
Go to the documentation of this file.
1 /*
2  * This class is for solving the long-chain constraints
3  * for the Martini model with LINCS algorithm by CG method.
4  */
5 #include <cstdlib>
6 #include <cerrno>
7 #include <cstdio>
8 #include <cerrno>
9 #include <cstring>
10 #include "LincsSolver.h"
11 #include <cmath>
12 #define BUFFSIZE 1024
13 
15 {
17  int* IA; //rows
18  int* JA; //colums
19 }; //store in coordinate format
20 
21 typedef struct atomData
22 {
24  int patchID;
25  int offset;
28 
29 } atomData;
30 
31 typedef struct constraintTuple
32 {
33  int i, j;
36 
37 static void* Malloc(size_t size)
38 {
39  void* ptr = malloc(size);
40  if(errno != 0)
41  {
42  perror("malloc error");
43  NAMD_die("malloc error");
44  }
45  return ptr;
46 }
47 
48 static void* Realloc(void* src, size_t size)
49 {
50  if(src == NULL)
51  return Malloc(size);
52  void* ptr = realloc(src, size);
53  if(errno != 0)
54  {
55  perror("realloc error");
56  NAMD_die("realloc error");
57  }
58  return ptr;
59 }
60 
61 static void* Calloc(size_t size, size_t elem)
62 {
63  void* ptr = calloc(size, elem);
64  if(errno != 0)
65  {
66  perror("calloc error");
67  NAMD_die("calloc error");
68  }
69  return ptr;
70 }
71 
72 void LincsSolver::multiplyR(BigReal* dest, BigReal* src)
73 {
74  memset(dest, 0, sizeof(BigReal)*num_constraints);
75  for(int i = 0; i < 6*num_constraints; i++)
76  {
77  int col = B->JA[i];
78  int row = B->IA[i];
79 
80  dest[row] += B->aij[i] * src[col];
81  }
82 }
83 
84 void LincsSolver::multiplyC(BigReal* dest, BigReal* src)
85 {
86  memset(dest, 0, sizeof(BigReal)*num_atoms*3);
87  for(int i = 0; i < 6*num_constraints; i++)
88  {
89  int row = B->JA[i];
90  int col = B->IA[i];
91 
92  dest[row] += B->aij[i] * src[col];
93  }
94 }
95 
96 void LincsSolver::matMultiply(BigReal* dest, BigReal* src)
97 {
98  BigReal* tmp = (BigReal*)Malloc(sizeof(BigReal)*3*num_atoms);
99  multiplyC(tmp, src);
100  for(int i = 0; i < num_atoms; ++i)
101  {
102  BigReal m = inv_mass[i];
103  tmp[3*i+0] *= m;
104  tmp[3*i+1] *= m;
105  tmp[3*i+2] *= m;
106  }
107  multiplyR(dest, tmp);
108  free(tmp);
109 }
110 
111 void LincsSolver::vecAdd(BigReal* dest, BigReal* src1, BigReal* src2, BigReal a)
112 {
113  for(int i = 0; i < num_constraints; ++i)
114  dest[i] = src1[i]+a*src2[i];
115 }
116 
117 BigReal LincsSolver::vecDot(BigReal* a, BigReal* b)
118 {
119  BigReal x = 0.;
120  for(int i = 0; i < num_constraints; ++i)
121  x += a[i] * b[i];
122  return x;
123 }
124 
125 //solve (B^M^-1B^T)x=b
126 void LincsSolver::conjugateGradient(BigReal* x, BigReal* b)
127 {
128  BigReal* r = (BigReal*)Malloc(sizeof(BigReal)*num_constraints);
129  BigReal* p = (BigReal*)Malloc(sizeof(BigReal)*num_constraints);
130  BigReal* tmp = (BigReal*)Malloc(sizeof(BigReal)*num_constraints);
131 
132  matMultiply(r, x);
133  vecAdd(r,b,r,-1);
134  memcpy(p, r, sizeof(BigReal)*num_constraints);
135  for(int i = 0; i < maxLoops; ++i)
136  {
137  matMultiply(tmp, p);
138  BigReal r2_old = vecDot(r,r);
139  BigReal alpha = r2_old/vecDot(p, tmp);
140  vecAdd(x,x,p,alpha);
141  vecAdd(r,r,tmp,-alpha);
142  BigReal r2 = vecDot(r,r);
143  if(r2 < tol*tol)
144  break;
145  BigReal beta = r2/r2_old;
146  vecAdd(p,r,p,beta);
147  }
148  matMultiply(r,x);
149  vecAdd(r,b,r,-1);
150  free(tmp);
151  free(p);
152  free(r);
153 }
154 
155 static int intPairCmp(const void* a1, const void* a2)
156 {
159  if(a->i < b->i)
160  return -1;
161  else if(a->i > b->i)
162  return 1;
163  else
164  {
165  if(a->j < b->j)
166  return -1;
167  else
168  return 1;
169  }
170 }
171 
172 static int intCmp(const void* a1, const void* a2)
173 {
174  int* a = (int*)a1;
175  int* b = (int*)a2;
176  if(*a < *b)
177  return -1;
178  else if(*a > *b)
179  return 1;
180  else
181  return 0;
182 }
183 
184 int LincsSolver::Map(int i)
185 {
186  int* ptr = (int*)bsearch(&i, globalIndex, num_atoms, sizeof(int), &intCmp);
187  if(ptr == NULL)
188  {
189  fprintf(stderr, "error mapping for %d\n", i);
190  NAMD_die("Error in mapping");
191  }
192  return (int)((size_t)(ptr-globalIndex));
193 }
194 
195 static void swapInt(int* v, int a, int b)
196 {
197  int tmp = v[a];
198  v[a] = v[b];
199  v[b] = tmp;
200 }
201 
202 static void swapBigReal(BigReal* v, int a, int b)
203 {
204  BigReal tmp = v[a];
205  v[a] = v[b];
206  v[b] = tmp;
207 }
208 
209 static void swapVector3(BigReal* v, int a, int b)
210 {
211  BigReal tmp;
212  for(int i = 0; i < 3; ++i)
213  {
214  tmp = v[3*a+i];
215  v[3*a+i] = v[3*b+i];
216  v[3*b+i] = tmp;
217  }
218 }
219 
220 int LincsSolver::partition(int left, int right)
221 {
222  int pivot = globalIndex[right];
223  int i = (left-1);
224 
225  for (int j = left; j <= right- 1; j++)
226  {
227  // If current element is smaller than or
228  // equal to pivot
229  if (globalIndex[j] <= pivot)
230  {
231  i++;// increment index of smaller element
232  swapInt(globalIndex, i, j);
233  swapInt(patchID, i, j);
234  swapInt(offset, i, j);
235  swapBigReal(inv_mass, i, j);
236  swapVector3(ref, i, j);
237  }
238  }
239  swapInt(globalIndex, i+1, right);
240  swapInt(patchID, i+1, right);
241  swapInt(offset, i+1, right);
242  swapBigReal(inv_mass, i+1, right);
243  swapVector3(ref, i+1, right);
244  return i + 1;
245 }
246 
247 void LincsSolver::sortAtom(int left, int right)
248 {
249  if (left < right)
250  {
251  int pi = partition(left, right);
252  // Separately sort elements before
253  // partition and after partition
254  sortAtom(left, pi-1);
255  sortAtom(pi+1, right);
256  }
257 }
258 
259 void LincsSolver::sortConstraints()
260 {
261  qsort(constraintList, num_constraints, sizeof(constraintTuple), &intPairCmp);
262 }
263 #ifdef DEBUG
264 void LincsSolver::showDataRead(void* Data, void* Constraints)
265 {
266  atomData* data = (atomData*)Data;
267  constraintTuple* constraints = (constraintTuple*)Constraints;
268 
269  fprintf(stdout, "Atom data:\n");
270  for(int i = 0; i < num_atoms; ++i)
271  fprintf(stdout,"%d %f %f %f\n", data[i].globalIndex, data[i].posx, data[i].posy, data[i].posz);
272 
273  fprintf(stdout, "\n");
274  for(int i = 0; i < num_atoms; ++i)
275  fprintf(stdout,"%d %f %f %f\n", globalIndex[i], ref[3*i+0], ref[3*i+1], ref[3*i+2]);
276 
277  fprintf(stdout, "\nconstraints:\n");
278  for(int i = 0; i < num_constraints; ++i)
279  fprintf(stdout, "%d %d %f\n", constraints[i].i, constraints[i].j, constraints[i].dist);
280 
281  fprintf(stdout, "\n");
282  for(int i = 0; i < num_constraints; ++i)
283  fprintf(stdout, "%d %d %f\n", constraintList[i].i, constraintList[i].j, constraintList[i].dist);
284 
285 }
286 
287 void LincsSolver::checkConvergence()
288 {
289  for(int idx = 0; idx < num_constraints; ++idx)
290  {
291  int i = constraintList[idx].i;
292  int j = constraintList[idx].j;
293  BigReal dist = constraintList[idx].dist;
294  int col_i = Map(i);
295  int col_j = Map(j);
296  BigReal x1, x2, y1, y2, z1, z2;
297  x1 = ref[3*col_i+0];
298  x2 = ref[3*col_j+0];
299  y1 = ref[3*col_i+1];
300  y2 = ref[3*col_j+1];
301  z1 = ref[3*col_i+2];
302  z2 = ref[3*col_j+2];
303  BigReal r = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
304  }
305 }
306 #endif
307 void LincsSolver::copy(void* Data, void* Constraints)
308 {
309  int size = BUFFSIZE;
310  int count = 0;
311 
312  globalIndex = (int*)Malloc(sizeof(int)*size);
313  patchID = (int*)Malloc(sizeof(int)*size);
314  offset = (int*)Malloc(sizeof(int)*size);
315  inv_mass = (BigReal*)Malloc(sizeof(BigReal)*size);
316  ref = (BigReal*)Malloc(sizeof(BigReal)*size*3);
317  //let's cast it
318  atomData* data = (atomData*)Data;
319  while(data->globalIndex > -1)
320  {
321  globalIndex[count] = data->globalIndex;
322  patchID [count] = data->patchID;
323  offset [count] = data->offset;
324  inv_mass [count] = data->inv_mass;
325  ref [3*count+0] = data->posx;
326  ref [3*count+1] = data->posy;
327  ref [3*count+2] = data->posz;
328  ++count;
329  ++data;
330  if(count >= size)
331  {
332  size <<= 1;
333  //alloc more memory
334  globalIndex = (int*)Realloc(globalIndex, sizeof(int)*size);
335  patchID = (int*)Realloc(patchID, sizeof(int)*size);
336  offset = (int*)Realloc(offset, sizeof(int)*size);
337  inv_mass = (BigReal*)Realloc(inv_mass, sizeof(BigReal)*size);
338  ref = (BigReal*)Realloc(ref, sizeof(BigReal)*size*3);
339  }
340  }
341  num_atoms = count;
342  globalIndex = (int*)Realloc(globalIndex, sizeof(int)*num_atoms);
343  patchID = (int*)Realloc(patchID, sizeof(int)*num_atoms);
344  offset = (int*)Realloc(offset, sizeof(int)*num_atoms);
345  inv_mass = (BigReal*)Realloc(inv_mass, sizeof(BigReal)*num_atoms);
346  ref = (BigReal*)Realloc(ref, sizeof(BigReal)*num_atoms*3);
347 
348  size = BUFFSIZE;
349  constraintList = (constraintTuple*)Malloc(sizeof(constraintTuple)*size);
350  count = 0;
351  constraintTuple* constraints = (constraintTuple*)Constraints;
352  while(constraints->i > -1)
353  {
354 
355  int i = constraints->i;
356  int j = constraints->j;
357  if(i > j)
358  {
359  int k = i;
360  i = j;
361  j = k;
362  }
363  constraintList[count].i = i;
364  constraintList[count].j = j;
365  constraintList[count++].dist = (constraints++)->dist;
366 
367  if(count >= size)
368  {
369  size <<= 1;
370  constraintList = (constraintTuple*)Realloc(constraintList,size*sizeof(constraintTuple));
371  }
372  }
373  num_constraints = count;
374  constraintList = (constraintTuple*)Realloc(constraintList, sizeof(constraintTuple)*num_constraints);
375 }
376 
377 
378 void LincsSolver::buildBMatrix()
379 {
380  B = (sparseMatrix*)Malloc(sizeof(sparseMatrix));
381  B->aij = (BigReal*)Malloc(sizeof(BigReal)*6*num_constraints);
382  B->IA = (int*)Malloc(sizeof(int)*6*num_constraints);
383  B->JA = (int*)Malloc(sizeof(int)*6*num_constraints);
384  for(int idx = 0; idx < num_constraints; ++idx)
385  {
386  int i = constraintList[idx].i;
387  int j = constraintList[idx].j;
388  //record all idexes, this is not memory optimized
389  int col_i = Map(i);
390  int col_j = Map(j);
391  for(int k = 0; k < 6; ++k)
392  B->IA[6*idx+k] = idx;
393  for(int k = 0; k < 3; ++k)
394  {
395  B->JA[6*idx+k] = 3*col_i+k;
396  B->JA[6*idx+3+k] = 3*col_j+k;
397  }
398  //build matrix element
399  BigReal x1,x2,y1,y2,z1,z2,d2;
400  x1 = ref[3*col_i+0];
401  y1 = ref[3*col_i+1];
402  z1 = ref[3*col_i+2];
403 
404  x2 = ref[3*col_j+0];
405  y2 = ref[3*col_j+1];
406  z2 = ref[3*col_j+2];
407 
408  d2 = (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2);
409  d2 = sqrt(d2);
410  B->aij[6*idx+0] = (x1-x2)/d2;
411  B->aij[6*idx+1] = (y1-y2)/d2;
412  B->aij[6*idx+2] = (z1-z2)/d2;
413  B->aij[6*idx+3] = -B->aij[6*idx+0];
414  B->aij[6*idx+4] = -B->aij[6*idx+1];
415  B->aij[6*idx+5] = -B->aij[6*idx+2];
416  }
417 }
418 
420 {
421  destroy();
422  copy(data, constraints);
423  sortAtom(0, num_atoms-1);
424  sortConstraints();
425  buildBMatrix();
426  #ifdef DEBUG
427  showDataRead(data, constraints);
428  checkConvergence();
429  #endif
430 }
431 
433 {
434  BigReal* b = (BigReal*)Malloc(sizeof(BigReal)*num_constraints);
435  BigReal* x = (BigReal*)Malloc(sizeof(BigReal)*num_constraints);
436  multiplyR(b, ref);
437  for(int i = 0; i < num_constraints; ++i)
438  b[i] -= constraintList[i].dist;
439  memset(x, 0 , sizeof(BigReal)*num_constraints);
440  conjugateGradient(x, b);
441  BigReal* tmp = (BigReal*)Malloc(sizeof(BigReal)*num_atoms*3);
442  multiplyC(tmp, x);
443  for(int i = 0; i < num_atoms; ++i)
444  {
445  BigReal m = inv_mass[i];
446  ref[3*i+0] -= tmp[3*i+0]*m;
447  ref[3*i+1] -= tmp[3*i+1]*m;
448  ref[3*i+2] -= tmp[3*i+2]*m;
449  }
450  multiplyR(b, ref);
451  for(int idx = 0; idx < num_constraints; ++idx)
452  {
453  int i = constraintList[idx].i;
454  int j = constraintList[idx].j;
455  BigReal d = constraintList[idx].dist;
456  int col_i = Map(i);
457  int col_j = Map(j);
458  BigReal x1, x2, y1, y2, z1, z2;
459  x1 = ref[3*col_i+0];
460  x2 = ref[3*col_j+0];
461  y1 = ref[3*col_i+1];
462  y2 = ref[3*col_j+1];
463  z1 = ref[3*col_i+2];
464  z2 = ref[3*col_j+2];
465  BigReal l = (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2);
466 
467  b[idx] -= sqrt(2.0*d*d-l);
468  }
469  memset(x, 0 , sizeof(BigReal)*num_constraints);
470  conjugateGradient(x, b);
471  multiplyC(tmp, x);
472  for(int i = 0; i < num_atoms; ++i)
473  {
474  BigReal m = inv_mass[i];
475  ref[3*i+0] -= tmp[3*i+0]*m;
476  ref[3*i+1] -= tmp[3*i+1]*m;
477  ref[3*i+2] -= tmp[3*i+2]*m;
478  }
479  #ifdef DEBUG
480  checkConvergence();
481  #endif
482  free(b);
483  free(x);
484  free(tmp);
485 }
486 void LincsSolver::destroy()
487 {
488  if(ref != NULL)
489  free(ref);
490  ref = NULL;
491  if(inv_mass != NULL)
492  free(inv_mass);
493  inv_mass = NULL;
494  if(offset != NULL)
495  free(offset);
496  offset = NULL;
497  if(patchID != NULL)
498  free(patchID);
499  patchID = NULL;
500  if(globalIndex != NULL)
501  free(globalIndex);
502  globalIndex = NULL;
503  if(constraintList != NULL)
504  free(constraintList);
505  constraintList = NULL;
506  if(B != NULL)
507  {
508  free(B->aij);
509  B->aij = NULL;
510  free(B->IA);
511  B->IA = NULL;
512  free(B->JA);
513  B->JA = NULL;
514  free(B);
515  B = NULL;
516  }
517 }
518 
int offset
Definition: LincsSolver.C:25
static void * Realloc(void *src, size_t size)
Definition: LincsSolver.C:48
static int intCmp(const void *a1, const void *a2)
Definition: LincsSolver.C:172
static void swapBigReal(BigReal *v, int a, int b)
Definition: LincsSolver.C:202
void solve()
interface to run the solver with CG.
Definition: LincsSolver.C:432
static void swapInt(int *v, int a, int b)
Definition: LincsSolver.C:195
void setUpSolver(atomData *, constraintTuple *)
interface to set up the solver with two given arrays of data.
Definition: LincsSolver.C:419
int globalIndex
Definition: LincsSolver.C:23
static void swapVector3(BigReal *v, int a, int b)
Definition: LincsSolver.C:209
struct atomData atomData
static int intPairCmp(const void *a1, const void *a2)
Definition: LincsSolver.C:155
void NAMD_die(const char *err_msg)
Definition: common.C:147
BigReal posy
Definition: LincsSolver.C:26
static void * Calloc(size_t size, size_t elem)
Definition: LincsSolver.C:61
static void * Malloc(size_t size)
Definition: LincsSolver.C:37
BigReal * aij
Definition: LincsSolver.C:16
BigReal posz
Definition: LincsSolver.C:26
BigReal posx
Definition: LincsSolver.C:26
BigReal inv_mass
Definition: LincsSolver.C:27
struct constraintTuple constraintTuple
#define BUFFSIZE
Definition: LincsSolver.C:12
double BigReal
Definition: common.h:123
int patchID
Definition: LincsSolver.C:24