KTH framework for Nek5000 toolboxes; testing version  0.0.1
crs_hypre.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "gslib.h"
6 #include "crs_hypre.h"
7 
8 #ifdef HYPRE
9 
10 #define NPARAM 10
11 double hypre_param[NPARAM];
12 
13 static struct hypre_crs_data **handle_array = 0;
14 static int handle_max = 0;
15 static int handle_n = 0;
16 
17 struct hypre_crs_data *ccrs_hypre_setup( uint n, const ulong *id,
18  uint nz, const uint *Ai, const uint *Aj, const double *Av,
19  const uint null_space, const struct comm *comm,
20  const double *param)
21 {
22  struct hypre_crs_data *hypre_data = tmalloc(struct hypre_crs_data, 1);
23 
24  hypre_data->nullspace = null_space;
25 
26  comm_dup(&hypre_data->comm,comm);
27  hypre_data->gs_top = gs_setup((const slong*)id,n,&hypre_data->comm, 1,
28  gs_auto, 1);
29 
30  // Build CRS matrix in hypre format and initialize stuff
31  build_hypre_matrix(hypre_data, n, id, nz, Ai, Aj, Av);
32 
33  // Compute total number of unique IDs and tni
34  double tmp = (double)hypre_data->un;
35  double buf;
36  comm_allreduce(&hypre_data->comm,gs_double,gs_add,&tmp,1,&buf);
37  hypre_data->tni = 1./tmp;
38 
39  // Create AMG solver
40  HYPRE_BoomerAMGCreate(&hypre_data->solver);
41  HYPRE_Solver solver = hypre_data->solver;
42 
43  int uparam = (int) param[0];
44 
45  // Set AMG parameters
46  if (uparam) {
47  int i;
48  for (i = 0; i < NPARAM; i++) {
49  hypre_param[i] = param[i+1];
50  if (comm->id == 0)
51  printf("Custom HYPREsettings[%d]: %.2f\n", i+1, hypre_param[i]);
52  }
53  } else {
54  hypre_param[0] = 10; /* HMIS */
55  hypre_param[1] = 6; /* Extended+i */
56  hypre_param[2] = 0; /* not used */
57  hypre_param[3] = 3; /* SOR smoother for crs level */
58  hypre_param[4] = 1;
59  hypre_param[5] = 0.25;
60  hypre_param[6] = 0.1;
61  hypre_param[7] = 0.0;
62  hypre_param[8] = 0.01;
63  hypre_param[9] = 0.05;
64  }
65 
66  HYPRE_BoomerAMGSetCoarsenType(solver,hypre_param[0]);
67  HYPRE_BoomerAMGSetInterpType(solver,hypre_param[1]);
68  if (null_space == 1 || uparam) {
69 // HYPRE_BoomerAMGSetRelaxType(solver, hypre_param[2]);
70  HYPRE_BoomerAMGSetCycleRelaxType(solver, hypre_param[3], 3);
71  HYPRE_BoomerAMGSetCycleNumSweeps(solver, hypre_param[4], 3);
72  }
73  HYPRE_BoomerAMGSetStrongThreshold(solver,hypre_param[5]);
74  HYPRE_BoomerAMGSetNonGalerkinTol(solver,hypre_param[6]);
75  HYPRE_BoomerAMGSetLevelNonGalerkinTol(solver,hypre_param[7], 0);
76  HYPRE_BoomerAMGSetLevelNonGalerkinTol(solver,hypre_param[8], 1);
77  HYPRE_BoomerAMGSetLevelNonGalerkinTol(solver,hypre_param[9], 2);
78 
79  HYPRE_BoomerAMGSetMinCoarseSize(solver,2);
80  HYPRE_BoomerAMGSetMaxIter(solver,1);
81  HYPRE_BoomerAMGSetPrintLevel(solver,1);
82  HYPRE_BoomerAMGSetTol(solver,0.0);
83 
84  // Create and initialize rhs and solution vectors
85  HYPRE_Int ilower = hypre_data->ilower;
86  HYPRE_Int iupper = ilower + (HYPRE_Int)(hypre_data->un) - 1;
87 
88  HYPRE_IJVectorCreate(hypre_data->comm.c,ilower,iupper,&hypre_data->b);
89  HYPRE_IJVector b = hypre_data->b;
90  HYPRE_IJVectorCreate(hypre_data->comm.c,ilower,iupper,&hypre_data->x);
91  HYPRE_IJVector x = hypre_data->x;
92  HYPRE_IJVectorSetObjectType(b,HYPRE_PARCSR);
93  HYPRE_IJVectorSetObjectType(x,HYPRE_PARCSR);
94  HYPRE_IJVectorInitialize(b);
95  HYPRE_IJVectorInitialize(x);
96  HYPRE_IJVectorAssemble(b);
97  HYPRE_IJVectorAssemble(x);
98 
99  // Perform AMG setup
100  HYPRE_ParVector par_b;
101  HYPRE_ParVector par_x;
102  HYPRE_IJVectorGetObject(b,(void**) &par_b);
103  HYPRE_IJVectorGetObject(x,(void**) &par_x);
104 
105  HYPRE_ParCSRMatrix par_A;
106  HYPRE_IJMatrixGetObject(hypre_data->A,(void**) &par_A);
107 
108  HYPRE_BoomerAMGSetup(solver,par_A,par_b,par_x);
109 
110  return hypre_data;
111 }
112 
113 sint set_BoomerAMG_parameters(HYPRE_Solver *solver_ptr, const double *param)
114 {
115  HYPRE_Solver solver = *solver_ptr;
116 
117  return 0;
118 }
119 
120 void build_hypre_matrix(struct hypre_crs_data *hypre_data, uint n, const ulong
121  *id, uint nz_unassembled, const uint *Ai, const uint* Aj, const double *Av)
122 {
123  struct crystal cr;
124  struct comm comm;
125  struct gs_data* gs_top;
126  struct array uid;
127  ulong *uid_p = uid.ptr;
128  struct rid *rid_map = tmalloc(struct rid,n);
129  struct array mat;
130  uint k;
131  struct rnz *out;
132  uint *umap;
133 
134  comm = hypre_data->comm;
135  gs_top = hypre_data->gs_top;
136 
137  // Initialize crystal router
138  crystal_init(&cr, &comm);
139 
140  // Assign degrees of freedom
141  assign_dofs_hypre(&uid,rid_map,id,n,comm.id,gs_top,&cr.data,&comm);
142 
143  // Build unassembled matrix
144  array_init(struct rnz,&mat,nz_unassembled);
145  for(out=mat.ptr,k=0;k<nz_unassembled;++k) {
146  uint i=Ai[k], j=Aj[k]; double a=Av[k];
147  if(id[i]==0 || id[j]==0 || fabs(a)==0) continue;
148  out->v = a, out->i=rid_map[i], out->j=rid_map[j];
149  ++out;
150  }
151  mat.n = out-(struct rnz*)mat.ptr;
152  free(rid_map);
153 
154  // Assemble the matrix
155  const ulong *const uid_ptr = uid.ptr;
156  const uint pid = comm.id, np = comm.np;
157  struct array nonlocal_id;
158  uint nnz;
159  const struct rnz *nz, *enz;
160  const struct labelled_rid *rlbl;
161 
162  mat_distribute(&mat,row_distr,col_major,&cr);
163  nnz = mat.n;
164 
165  mat_list_nonlocal_sorted(&nonlocal_id,&mat,row_distr,uid_ptr,&cr);
166  rlbl = nonlocal_id.ptr;
167 
168  // Build Hypre matrix
169  hypre_data->un = uid.n;
170 
171  HYPRE_Int ilower = (HYPRE_Int)(uid_ptr[0]);
172  hypre_data->ilower = ilower;
173  HYPRE_Int iupper = ilower + (HYPRE_Int)(uid.n) - 1;
174 
175  HYPRE_IJMatrixCreate(comm.c,ilower,iupper,ilower,iupper,&hypre_data->A);
176  HYPRE_IJMatrix A_ij = hypre_data->A;
177  HYPRE_IJMatrixSetObjectType(A_ij,HYPRE_PARCSR);
178  HYPRE_IJMatrixInitialize(A_ij);
179 
180  HYPRE_Int mati, matj;
181  double matv;
182  HYPRE_Int nrows = 1, ncols = 1;
183 
184  for(nz=mat.ptr,enz=nz+nnz;nz!=enz;++nz)
185  {
186  mati = (HYPRE_Int)(uid_ptr[nz->i.i]);
187  matv = nz->v;
188  if(nz->j.p==pid)
189  {
190  matj = (HYPRE_Int)(uid_ptr[nz->j.i]);
191  }
192  else
193  {
194  const uint jp = nz->j.p, ji = nz->j.i;
195  while(rlbl->rid.p<jp) ++rlbl;
196  if(rlbl->rid.p!=jp) printf("Error when assembling matrix\n");
197  while(rlbl->rid.i<ji) ++rlbl;
198  if(rlbl->rid.i!=ji) printf("Error when assembling matrix\n");
199  matj = (HYPRE_Int)(rlbl->id);
200  }
201  HYPRE_IJMatrixSetValues(A_ij, nrows, &ncols, &mati, &matj, &matv);
202  }
203 
204  // Free data not necessary anymore
205  array_free(&uid);
206  array_free(&mat);
207  array_free(&nonlocal_id);
208 
209  // Get the mapping
210  hypre_data->umap=assign_dofs_hypre(&uid,0, id,n,pid,gs_top,&cr.data,&comm);
211  array_free(&uid);
212  crystal_free(&cr);
213 
214  HYPRE_IJMatrixAssemble(A_ij);
215 }
216 
217 void ccrs_hypre_solve(double *x, struct hypre_crs_data *data, double *b)
218 {
219  uint i; const uint un = data->un; const uint *const umap = data->umap;
220  HYPRE_Int ilower = data->ilower;
221  HYPRE_IJVector ij_x = data->x;
222  HYPRE_IJVector ij_b = data->b;
223  HYPRE_IJMatrix ij_A = data->A;
224  HYPRE_Solver solver = data->solver;
225 
226  HYPRE_ParVector par_x;
227  HYPRE_ParVector par_b;
228  HYPRE_ParCSRMatrix par_A;
229 
230  gs(b, gs_double,gs_add, 1, data->gs_top, 0);
231  for(i=0;i<un;++i)
232  {
233  HYPRE_Int ii = ilower + (HYPRE_Int)i;
234  double bb = b[umap[i]];
235  HYPRE_IJVectorSetValues(ij_b,1,&ii,&bb);
236  }
237 
238  HYPRE_IJVectorAssemble(ij_b);
239  HYPRE_IJVectorGetObject(ij_b,(void**) &par_b);
240 
241  HYPRE_IJVectorAssemble(ij_x);
242  HYPRE_IJVectorGetObject(ij_x,(void **) &par_x);
243 
244  HYPRE_IJMatrixGetObject(ij_A,(void**) &par_A);
245 
246  HYPRE_BoomerAMGSolve(solver,par_A,par_b,par_x);
247 
248  double avg = 0.0;
249  for(i=0;i<un;++i)
250  {
251  HYPRE_Int ii = ilower + (HYPRE_Int)i;
252  double xx;
253  HYPRE_IJVectorGetValues(ij_x,1,&ii,&xx);
254  x[umap[i]] = xx;
255  if (data->nullspace) avg += xx;
256  }
257 
258  if (data->nullspace)
259  {
260  double buf;
261  comm_allreduce(&data->comm,gs_double,gs_add,&avg,1,&buf);
262  avg = avg*data->tni;
263  for(i=0;i<un;++i) x[umap[i]] -= avg;
264  }
265 
266  gs(x, gs_double,gs_add, 0, data->gs_top, 0);
267 }
268 
269 void ccrs_hypre_free(struct hypre_crs_data *data)
270 {
271  HYPRE_BoomerAMGDestroy(data->solver);
272  HYPRE_IJMatrixDestroy(data->A);
273  HYPRE_IJVectorDestroy(data->x);
274  HYPRE_IJVectorDestroy(data->b);
275  comm_free(&data->comm);
276  gs_free(data->gs_top);
277  free(data->umap);
278  free(data);
279 }
280 
281 // Functions borrowed from amg.c
282 /*
283  The user ids id[n] are assigned to unique procs.
284 
285  Output
286  uid --- ulong array; uid[0 ... uid.n-1] are the ids owned by this proc
287  rid_map --- id[i] is uid[ rid_map[i].i ] on proc rid_map[i].p
288  map = assign_dofs_hypre(...) --- uid[i] is id[map[i]]
289 
290  map is returned only when rid_map is null, and vice versa
291 */
292 static uint *assign_dofs_hypre(struct array *const uid,
293  struct rid *const rid_map,
294  const ulong *const id, const uint n,
295  const uint p,
296  struct gs_data *gs_top, buffer *const buf,
297  struct comm *comm)
298 {
299  uint i,count, *map=0;
300  struct rid *const rid = rid_map?rid_map:tmalloc(struct rid,n);
301  for(i=0;i<n;++i) rid[i].p=p, rid[i].i=i;
302  gs_vec(n?&rid[0].p:0,2, gs_sint,gs_add,0, gs_top,buf);
303  for(count=0,i=0;i<n;++i) {
304  if(rid[i].i==i && id[i]!=0 && rid[i].p==p) ++count; }
305  array_init(ulong,uid,count); uid->n=count;
306  if(rid_map==0) {
307  map=tmalloc(uint,count);
308  for(count=0,i=0;i<n;++i) {
309  if(rid[i].i==i && id[i]!=0 && rid[i].p==p) map[count++]=i; }
310  }
311  { // HYPRE NUMBERING
312  ulong scan_out[2],scan_buf[2],uln;
313  uln = (ulong) uid->n;
314  comm_scan(scan_out,comm,gs_long,gs_add,&uln,1,scan_buf);
315  ulong uilow = scan_out[0];
316  ulong *const uid_p = uid->ptr;
317  for(count=0,i=0;i<n;++i) if(rid[i].i==i && id[i]!=0 && rid[i].p==p)
318  uid_p[count]=uilow+(ulong)count, rid[i].i=count, ++count;
319  //
320  }
321  if(rid_map) gs_vec(n?&rid[0].p:0,2, gs_sint,gs_add,0, gs_top,buf);
322  else free(rid);
323  return map;
324 }
325 
326 static void mat_sort(struct array *const mat,
327  const enum mat_order order, buffer *const buf)
328 {
329  switch(order) {
330  case col_major: sarray_sort_4(struct rnz,mat->ptr,mat->n,
331  j.p,0,j.i,0, i.p,0,i.i,0, buf); break;
332  case row_major: sarray_sort_4(struct rnz,mat->ptr,mat->n,
333  i.p,0,i.i,0, j.p,0,j.i,0, buf); break;
334  }
335 }
336 
337 /* assumes matrix is already sorted */
338 static void mat_condense_sorted(struct array *const mat)
339 {
340  struct rnz *dst,*src, *const end=(struct rnz*)mat->ptr+mat->n;
341  if(mat->n<=1) return;
342  for(dst=mat->ptr;;++dst) {
343  if(dst+1==end) return;
344  if(nz_pos_equal(dst[0],dst[1])) break;
345  }
346  for(src=dst+1;src!=end;++src) {
347  if(nz_pos_equal(*dst,*src))
348  dst->v += src->v;
349  else
350  *(++dst) = *src;
351  }
352  mat->n = (dst+1)-(struct rnz*)mat->ptr;
353 }
354 
355 static void mat_condense(
356  struct array *const mat, const enum mat_order order, buffer *const buf)
357 {
358  mat_sort(mat,order,buf); mat_condense_sorted(mat);
359 }
360 
361 static void mat_distribute(
362  struct array *const mat, const enum distr d, const enum mat_order o,
363  struct crystal *const cr)
364 {
365  switch(d) {
366  case row_distr: mat_condense(mat,row_major,&cr->data);
367  sarray_transfer(struct rnz,mat, i.p,0, cr); break;
368  case col_distr: mat_condense(mat,col_major,&cr->data);
369  sarray_transfer(struct rnz,mat, j.p,0, cr); break;
370  }
371  mat_condense(mat,o,&cr->data);
372 }
373 
374 static void mat_list_nonlocal_sorted(
375  struct array *const nonlocal_id,
376  const struct array *const mat, const enum distr d,
377  const ulong *uid, struct crystal *const cr)
378  {
379  const uint pid = cr->comm.id;
380  struct rid last_rid;
381  const struct rnz *p, *const e=(const struct rnz*)mat->ptr+mat->n;
382  uint count; struct labelled_rid *out, *end;
383 #define BUILD_LIST(k) do { \
384  last_rid.p=UINT_MAX,last_rid.i=UINT_MAX; \
385  for(count=0,p=mat->ptr;p!=e;++p) { \
386  if(p->k.p==pid || rid_equal(last_rid,p->k)) continue; \
387  last_rid=p->k; ++count; \
388  } \
389  array_init(struct labelled_rid, nonlocal_id, count); \
390  nonlocal_id->n=count; out=nonlocal_id->ptr; \
391  last_rid.p=UINT_MAX,last_rid.i=UINT_MAX; \
392  for(p=mat->ptr;p!=e;++p) { \
393  if(p->k.p==pid || rid_equal(last_rid,p->k)) continue; \
394  (out++)->rid=last_rid=p->k; \
395  } \
396  } while(0)
397  switch(d) {
398  case row_distr: BUILD_LIST(j); break;
399  case col_distr: BUILD_LIST(i); break;
400  }
401  #undef BUILD_LIST
402  sarray_transfer(struct labelled_rid,nonlocal_id,rid.p,1,cr);
403  for(out=nonlocal_id->ptr,end=out+nonlocal_id->n;out!=end;++out)
404  out->id=uid[out->rid.i];
405  sarray_transfer(struct labelled_rid,nonlocal_id,rid.p,1,cr);
406  sarray_sort_2(struct labelled_rid,nonlocal_id->ptr,nonlocal_id->n,
407  rid.p,0, rid.i,0, &cr->data);
408  }
409 
410  static void mat_list_nonlocal(
411  struct array *const nonlocal_id,
412  struct array *const mat, const enum distr d,
413  const ulong *uid, struct crystal *const cr)
414  {
415  switch(d) {
416  case row_distr: mat_sort(mat,col_major,&cr->data); break;
417  case col_distr: mat_sort(mat,row_major,&cr->data); break;
418  }
419  mat_list_nonlocal_sorted(nonlocal_id,mat,d,uid,cr);
420  }
421 
422 #else
423 
424 struct hypre_crs_data* ccrs_hypre_setup( uint n, const ulong *id,
425  uint nz, const uint *Ai, const uint *Aj, const double *Av,
426  const uint null_space, const struct comm *comm,
427  const double *param)
428 {
429  fail(1,__FILE__,__LINE__,"recompile with HYPRE support.");
430  exit(EXIT_FAILURE);
431  return NULL;
432 }
433 
434 void ccrs_hypre_solve(double *x, struct hypre_crs_data *data, double *b)
435 {
436  fail(1,__FILE__,__LINE__,"recompile with HYPRE support.");
437  exit(EXIT_FAILURE);
438  while(1);
439 }
440 
441 
442 void ccrs_hypre_free(struct hypre_crs_data *data)
443 {
444  fail(1,__FILE__,__LINE__,"recompile with HYPRE support.");
445  exit(EXIT_FAILURE);
446  while(1);
447 }
448 
449 #endif
mat_order
Definition: crs_amg.c:1087
@ row_major
Definition: crs_amg.c:1087
@ col_major
Definition: crs_amg.c:1087
#define rid_equal(a, b)
Definition: crs_amg.c:1090
distr
Definition: crs_amg.c:1088
@ col_distr
Definition: crs_amg.c:1088
@ row_distr
Definition: crs_amg.c:1088
#define BUILD_LIST(k)
#define nz_pos_equal(a, b)
Definition: crs_amg.c:1096
void ccrs_hypre_free(struct hypre_crs_data *data)
Definition: crs_hypre.c:442
struct hypre_crs_data * ccrs_hypre_setup(uint n, const ulong *id, uint nz, const uint *Ai, const uint *Aj, const double *Av, const uint null_space, const struct comm *comm, const double *param)
Definition: crs_hypre.c:424
void ccrs_hypre_solve(double *x, struct hypre_crs_data *data, double *b)
Definition: crs_hypre.c:434
void build_hypre_matrix(struct hypre_crs_data *hypre_data, uint n, const ulong *id, uint nz_unassembled, const uint *Ai, const uint *Aj, const double *Av)
struct rid rid
Definition: crs_amg.c:1148
ulong id
Definition: crs_amg.c:1148
Definition: crs_amg.c:231
uint i
Definition: crs_amg.c:231
uint p
Definition: crs_amg.c:231
Definition: crs_amg.c:1093
struct rid i j
Definition: crs_amg.c:1094
double v
Definition: crs_amg.c:1094