1 #include "hxt_tools.h"
2 #include "hxt_linear_system_lu.h"
3 
4 //#define CONMAX 2000
5 
6 #ifdef CONMAX
connectivityInsert(int * connectivity,int i,int j)7 static HXTStatus connectivityInsert(int *connectivity, int i, int j)
8 {
9   for (int k = 0; k < CONMAX; ++k) {
10     int *p = connectivity + CONMAX*i + k;
11     if (*p == -1)
12       *p = j;
13     if (*p == j)
14       return HXT_STATUS_OK;
15   }
16   return HXT_ERROR_MSG(HXT_STATUS_ERROR, "node %i has more than %i neighbours\n", i, CONMAX);
17 }
18 #endif
19 
20 struct HXTLinearSystemLUStruct{
21   double *M;
22   int *rowStart;
23   int *rowEnd;
24   int *rowLuEnd;
25   double **rows;
26   double *x;
27   int *nodeMap;
28   uint32_t *elements;
29   int nNodesByElement;
30   int nElements;
31   int nNodes;
32   int nFields;
33   int n;
34   int flaglu;
35 };
36 
37 struct HXTConnectivity {
38   int nNodes;
39   int quantum;
40   int *degree;
41   int *allocated;
42   int **nodeConnectivity;
43 };
44 
allocConnectivity(struct HXTConnectivity * c,int n,int q)45 static HXTStatus allocConnectivity (struct HXTConnectivity *c, int n, int q)
46 {
47   c->nNodes = n;
48   c->quantum = q;
49   HXT_CHECK( hxtMalloc(&c->allocated,        sizeof(int) * c->nNodes) );
50   HXT_CHECK( hxtMalloc(&c->degree,           sizeof(int) * c->nNodes) );
51   HXT_CHECK( hxtMalloc(&c->nodeConnectivity, sizeof(int*) * c->nNodes) );
52 
53   for (int i=0;i<c->nNodes;i++){
54     c->allocated[i] = c->quantum;
55     c->degree [i] = 0;
56     HXT_CHECK( hxtMalloc(&c->nodeConnectivity[i], sizeof(int) * c-> allocated[i]) );
57   }
58   return HXT_STATUS_OK;
59 }
60 
freeConnectivity(struct HXTConnectivity * c)61 static HXTStatus freeConnectivity (struct HXTConnectivity *c)
62 {
63   for (int i=0;i<c->nNodes;i++){
64     HXT_CHECK( hxtFree(&c->nodeConnectivity[i]) );
65   }
66   HXT_CHECK( hxtFree(&c->nodeConnectivity) );
67   HXT_CHECK( hxtFree(&c->degree) );
68   HXT_CHECK( hxtFree(&c->allocated) );
69   c-> nNodes = 0;
70   return HXT_STATUS_OK;
71 }
72 
73 
addToConnectivity(struct HXTConnectivity * c,int myRow,int myCol)74 static HXTStatus addToConnectivity (struct HXTConnectivity *c, int myRow, int myCol){
75   if (myRow >= c->nNodes) return HXT_ERROR(HXT_STATUS_ERROR);
76 
77   if (c->allocated[myRow] == c->degree[myRow]){
78     c->allocated[myRow]*= 2;
79     HXT_CHECK( hxtRealloc(&c->nodeConnectivity[myRow], sizeof(int) * c->allocated[myRow]) );
80   }
81   for (int i=0;i<c->degree[myRow];i++){
82     if (c-> nodeConnectivity [myRow][i] == myCol) return HXT_STATUS_OK;
83   }
84   c-> nodeConnectivity [myRow][c->degree[myRow]] = myCol;
85   c->degree[myRow]++;
86   return HXT_STATUS_OK;
87 }
88 
89 
reverseCuthillMckee(HXTLinearSystemLU * system,int * ordering)90 static HXTStatus reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering)
91 {
92 #ifdef CONMAX
93   int *nodeConnectivity;
94   HXT_CHECK( hxtMalloc(&nodeConnectivity, sizeof(int)*system->nNodes*CONMAX) );
95   for (int i = 0; i < system->nNodes*CONMAX; ++i) {
96     nodeConnectivity[i] = -1;
97   }
98 #else
99   struct HXTConnectivity myConnectivity;
100   HXT_CHECK( allocConnectivity (&myConnectivity,system->nNodes,9) ); // 7 is the average connectivity of a triangular mesh, we put a llitle more
101 #endif
102 
103   for (int i = 0; i < system->nElements; ++i) {
104     uint32_t *el = system->elements + i*system->nNodesByElement;
105     for (int k = 0; k < system->nNodesByElement; ++k){
106       for (int l = 0; l < system->nNodesByElement; ++l){
107         if (k == l) continue;
108 #ifdef CONMAX
109         HXT_CHECK( connectivityInsert(nodeConnectivity, el[k], el[l]) );
110         HXT_CHECK( connectivityInsert(nodeConnectivity, el[l], el[k]) );
111 #else
112 	HXT_CHECK( addToConnectivity(&myConnectivity,el[k], el[l]) );
113 	HXT_CHECK( addToConnectivity(&myConnectivity,el[l], el[k]) );
114 #endif
115       }
116     }
117   }
118 #ifdef CONMAX
119 
120   int *nodeDegree;
121   HXT_CHECK( hxtMalloc(&nodeDegree, sizeof(int)*system->nNodes) );
122   for (int i = 0; i < system->nNodes; ++i) {
123     nodeDegree[i] = 0;
124     for (int j = 0; j < CONMAX; ++j) {
125       if (nodeConnectivity[CONMAX*i+j] == -1)
126 	break;
127       nodeDegree[i] += 1;
128     }
129   }
130 #else
131   int *nodeDegree = myConnectivity.degree;
132 #endif
133 
134   int *queue;
135   HXT_CHECK( hxtMalloc(&queue, sizeof(int)*system->nNodes) );
136   queue[0] = 0;
137   for (int i = 0; i < system->nNodes; ++i){
138     ordering[i] = -1;
139     if ((nodeDegree[queue[0]] == 0 || nodeDegree[queue[0]] > nodeDegree[i]) && nodeDegree[i] != 0){
140       queue[0] = i;
141     }
142   }
143   int stageStart = 0;
144   int stageEnd = 1;
145   int queueEnd = 1;
146   int id = 0;
147   while(stageStart != stageEnd) {
148     for (int i = stageStart; i < stageEnd; ++i) {
149       int c = queue[i];
150       ordering[c] = id++;
151       for(int j = 0; j < nodeDegree[c]; ++j) {
152 #ifdef CONMAX
153         int o = nodeConnectivity[c*CONMAX+j];
154 #else
155         int o = myConnectivity.nodeConnectivity[c][j];
156 #endif
157         if (ordering[o] == -1) {
158           ordering[o] = -2;
159 #if 1
160           queue[queueEnd++] = o;
161 #else
162           int k = stageEnd;
163           while(k < queueEnd && nodeDegree[queue[k]] < nodeDegree[o])
164             k++;
165           for (int l = queueEnd; l > k; --l)
166             queue[l] = queue[l-1];
167           queue[k] = o;
168           queueEnd++;
169 #endif
170         }
171       }
172     }
173     stageStart = stageEnd;
174     stageEnd = queueEnd;
175   }
176   for (int i = 0; i < system->nNodes; ++i)
177     if(ordering[i] >= 0)
178       ordering[i] = id-1-ordering[i];
179   HXT_CHECK( hxtFree(&queue) );
180 
181 #ifdef CONMAX
182   HXT_CHECK( hxtFree(&nodeDegree) );
183   HXT_CHECK( hxtFree(&nodeConnectivity) );
184 #else
185   HXT_CHECK( freeConnectivity (&myConnectivity) );
186 #endif
187   return HXT_STATUS_OK;
188 }
189 
190 
191 #define PADDING (SIMD_ALIGN/8)
192 
193 // y[from:to] += a*x[from:to]
194 // y and x must be 256-bit aligned
195 // memory should be allocated in consequence
rowAxpy(double a,double * __restrict__ px,double * __restrict__ py,int from,int to)196 static void rowAxpy(double a, double *__restrict__ px, double *__restrict__ py, int from, int to)
197 {
198   // Can't use the aligned attribute on function arguments.
199   hxtDeclareAligned double * __restrict__ x = px;
200   hxtDeclareAligned double * __restrict__ y = py;
201 
202   int i = from;
203   int pfrom = (from+7)&(~7);
204   if (pfrom > to)
205     pfrom = to;
206   for (; i < pfrom; ++i)
207     y[i] += a*x[i];
208   for (; i+15 < to; i+=16) {
209     hxtDeclareAligned double * __restrict__ X = x + i;
210     hxtDeclareAligned double * __restrict__ Y = y + i;
211     for (int j = 0; j < 16; ++j){
212       Y[j] += a * X[j];
213     }
214   }
215   for (; i+7 < to; i+=8) {
216     hxtDeclareAligned double * __restrict__ X = x + i;
217     hxtDeclareAligned double * __restrict__ Y = y + i;
218     for (int j = 0; j < 8; ++j)
219       Y[j] += a * X[j];
220   }
221   for (; i+3 < to; i+=4) {
222     double * __restrict__ X = x + i;
223     double * __restrict__ Y = y + i;
224     for (int j = 0; j < 4; ++j)
225       Y[j] += a * X[j];
226   }
227   for (; i < to; i++)
228     y[i] += a*x[i];
229 }
230 
231 
imin(int a,int b)232 static int imin(int a, int b) {
233   return a < b ? a : b;
234 }
235 
rowReduction(double * __restrict__ px,double * __restrict__ py,int from,int to)236 static double rowReduction(double *__restrict__ px, double *__restrict__ py, int from, int to)
237 {
238   double r = 0;
239   hxtDeclareAligned double * __restrict__ x = px;
240   hxtDeclareAligned double * __restrict__ y = py;
241 
242   int i = from;
243   int pfrom = (from+7)&(~7);
244   for (; i < imin(pfrom, to); ++i)
245     r += x[i] * y[i];
246   double R[8];
247   for (; i+7 < to; i+=8) {
248     hxtDeclareAligned double * __restrict__ X = x + i;
249     hxtDeclareAligned double * __restrict__ Y = y + i;
250     for (int j = 0; j < 8; ++j)
251       R[j] = X[j]*Y[j];
252     r += R[0]+R[1]+R[2]+R[3]+R[4]+R[5]+R[6]+R[7];
253   }
254   for (; i < to; ++i)
255     r += x[i] * y[i];
256   return r;
257 }
258 
rowZero(double * __restrict__ px,int from,int to)259 static void rowZero(double *__restrict__ px, int from, int to)
260 {
261   hxtDeclareAligned double * __restrict__ x = px;
262 
263   int i = from;
264   int pfrom = (from+7)&(~7);
265   for (; i < imin(pfrom, to); ++i)
266     x[i] = 0;
267   for (; i+7 < to; i+=8) {
268     hxtDeclareAligned double * __restrict__ X = x + i;
269     for (int j = 0; j < 8; ++j)
270       X[j] = 0;
271   }
272   for (; i < to; ++i)
273     x[i] = 0;
274 }
275 
LUPDecompose(HXTLinearSystemLU * system)276 static HXTStatus LUPDecompose(HXTLinearSystemLU *system){
277   int i,j;
278   int N = system->n;
279   double **A = system->rows;
280   for(i=0;i<N;i++){
281     for(j=i+1;j<system->rowLuEnd[i];j++){
282       if (fabs(A[i][i]) < 1e-12)
283         return HXT_ERROR_MSG(HXT_STATUS_FAILED, "zero pivot on line %i : %g", i, A[i][i]);
284       if(i < system->rowStart[j] || A[j][i] == 0.)
285         continue;
286       A[j][i]/=A[i][i];
287       rowAxpy(-A[j][i],A[i],A[j],i+1,system->rowEnd[i]);
288     }
289   }
290   return HXT_STATUS_OK;
291 }
292 
LUPSolve(HXTLinearSystemLU * system,double * b)293 static void LUPSolve(HXTLinearSystemLU *system, double *b){
294   double *x = system->x;
295   int N = system->n;
296   double **A = system->rows;
297 
298   for(int i=0;i<N;i++){
299     x[i] = b[i] - rowReduction(A[i], x, system->rowStart[i], i);
300   }
301   for(int i=N-1;i>=0;i--){
302     x[i] -= rowReduction(A[i], x, i+1, imin(system->rowEnd[i], N));
303 
304     if(fabs(A[i][i])<1e-8)
305       HXT_WARNING("pivot is close to be zero! %d\n",i);
306     x[i] = x[i]/A[i][i];
307   }
308 }
309 
hxtLinearSystemLUCreate(HXTLinearSystemLU ** pSystem,int nElements,int nNodesByElement,int nFields,uint32_t * elements)310 HXTStatus hxtLinearSystemLUCreate(HXTLinearSystemLU **pSystem, int nElements, int nNodesByElement, int nFields, uint32_t *elements)
311 {
312   HXTLinearSystemLU *system;
313   HXT_CHECK( hxtMalloc(&system, sizeof(HXTLinearSystemLU)) );
314   *pSystem = system;
315   system->nFields = nFields;
316   system->nNodesByElement = nNodesByElement;
317   system->nElements = nElements;
318   system->elements = elements;
319   uint32_t nNodes = 0;
320   for (int i = 0; i < nElements*nNodesByElement; ++i)
321     if(elements[i]+1 > nNodes)
322       nNodes = elements[i]+1;
323   system->nNodes = nNodes;
324   system->n = nNodes *nFields;
325   HXT_CHECK( hxtMalloc(&system->nodeMap, sizeof(int)*nNodes) );
326   HXT_CHECK( reverseCuthillMckee(system, system->nodeMap) );
327   int nUsedNodes = 0;
328   for (uint32_t i = 0; i < nNodes; ++i)
329     if (system->nodeMap[i] >= 0)
330       nUsedNodes ++;
331   system->n = nUsedNodes*system->nFields;
332   int *nodeRowStart, *nodeRowEnd;
333   HXT_CHECK( hxtMalloc(&nodeRowStart, sizeof(int)*nUsedNodes) );
334   HXT_CHECK( hxtMalloc(&nodeRowEnd, sizeof(int)*nUsedNodes) );
335   for (int i = 0; i < nUsedNodes; ++i) {
336     nodeRowEnd[i] = 0;
337     nodeRowStart[i] = nUsedNodes;
338   }
339   for (int i = 0; i < nElements; ++i) {
340     uint32_t *el = elements + i*nNodesByElement;
341     for (int j = 0; j < nNodesByElement; ++j) {
342       int n0 = system->nodeMap[el[j]];
343       for (int k = 0; k < nNodesByElement; ++k) {
344         int n1 = system->nodeMap[el[k]];
345         if (n1 < 0 || n0 < 0) continue;
346         if (nodeRowStart[n0] > n1)
347           nodeRowStart[n0] = n1;
348         if (nodeRowEnd[n0] < n1)
349           nodeRowEnd[n0] = n1;
350       }
351     }
352   }
353   int totalSize = 0;
354   HXT_CHECK( hxtMalloc(&system->rowStart, sizeof(int)*system->n) );
355   HXT_CHECK( hxtMalloc(&system->rowEnd, sizeof(int)*system->n) );
356   HXT_CHECK( hxtMalloc(&system->rowLuEnd, sizeof(int)*system->n) );
357   for (int i = 0; i < nUsedNodes; ++i) {
358     for (int j = 0; j < nFields; ++j) {
359       int k = i*nFields +j;
360       system->rowStart[k] = nodeRowStart[i]*nFields;
361       system->rowEnd[k] = nodeRowEnd[i]*nFields+nFields;
362       system->rowLuEnd[k] = k;
363     }
364   }
365   for (int i = 0; i < system->n; ++i) {
366     for (int j = system->rowStart[i]; j < i; ++j) {
367       if (system->rowLuEnd[j] < i+1) system->rowLuEnd[j] = i+1;
368       if (system->rowEnd[i] < system->rowEnd[j]) system->rowEnd[i] = system->rowEnd[j];
369     }
370   }
371   for (int i = 0; i < system->n; ++i) {
372     int start = totalSize - system->rowStart[i];
373     int paddedStart = (start+PADDING-1)&~(PADDING-1);
374     totalSize += system->rowEnd[i]-system->rowStart[i]+(paddedStart-start);
375   }
376   HXT_CHECK( hxtFree(&nodeRowStart) );
377   HXT_CHECK( hxtFree(&nodeRowEnd) );
378 
379   HXT_CHECK( hxtAlignedMalloc(&system->M, sizeof(double)*totalSize) );
380 
381   HXT_CHECK( hxtMalloc(&system->rows, sizeof(double*)*system->n) );
382   for (int i = 0; i < totalSize; ++i)
383     system->M[i] = 0.0;
384 
385   system->rows[0] = system->M;
386   totalSize = 0;
387   for (int i = 0; i < system->n; ++i){
388     int start = totalSize - system->rowStart[i];
389     int paddedStart = (start+PADDING-1)&~(PADDING-1);
390     totalSize += system->rowEnd[i]-system->rowStart[i]+(paddedStart-start);
391     system->rows[i] = system->M + paddedStart;
392   }
393 
394   HXT_CHECK( hxtAlignedMalloc(&system->x, sizeof(double)*system->n) );
395   return HXT_STATUS_OK;
396 }
397 
hxtLinearSystemLUAddToMatrix(HXTLinearSystemLU * system,int el0,int el1,const double * localMatrix)398 HXTStatus hxtLinearSystemLUAddToMatrix(HXTLinearSystemLU *system, int el0, int el1, const double *localMatrix){
399   if(system->flaglu==1)
400     return HXT_ERROR_MSG(HXT_STATUS_FAILED, "the system has been already factorised!");
401   int nn = system->nNodesByElement;
402   uint32_t *e0 = system->elements + el0*nn;
403   uint32_t *e1 = system->elements + el1*nn;
404   int nf = system->nFields;
405   for (int i = 0; i < nn; ++i) {
406     for (int inf = 0; inf < nf; ++inf) {
407       int ii = system->nodeMap[e0[i]]*nf + inf;
408       for (int j = 0; j < nn; ++j) {
409         for (int jnf = 0; jnf < nf; ++jnf) {
410           int jj = system->nodeMap[e1[j]]*nf + jnf;
411           system->rows[ii][jj] += localMatrix[(inf*nn+i)*nf*nn+jnf*nn+j];
412         }
413       }
414     }
415   }
416   return HXT_STATUS_OK;
417 }
418 
hxtLinearSystemLUAddToRhs(HXTLinearSystemLU * system,double * rhs,int el0,const double * localVector)419 HXTStatus hxtLinearSystemLUAddToRhs(HXTLinearSystemLU *system, double *rhs, int el0, const double *localVector)
420 {
421   int nFields = system->nFields;
422   int nn = system->nNodesByElement;
423   uint32_t *e0 = system->elements + el0*nn;
424   for (int i = 0; i < nFields; ++i) {
425     for (int j = 0; j < nn; ++j) {
426       int m = system->nodeMap[e0[j]]*nFields+i;
427       rhs[m] += localVector[i*nn+j];
428     }
429   }
430   return HXT_STATUS_OK;
431 }
432 
hxtLinearSystemLUZeroMatrix(HXTLinearSystemLU * system)433 HXTStatus hxtLinearSystemLUZeroMatrix(HXTLinearSystemLU *system)
434 {
435   system->flaglu = 0;
436   for (int i = 0; i < system->n; ++i){
437     rowZero(system->rows[i], system->rowStart[i], system->rowEnd[i]);
438   }
439   return HXT_STATUS_OK;
440 }
441 
hxtLinearSystemLUSetMatrixRowIdentity(HXTLinearSystemLU * system,int node,int field)442 HXTStatus hxtLinearSystemLUSetMatrixRowIdentity(HXTLinearSystemLU *system, int node, int field)
443 {
444   if (node >= system->nNodes || system->nodeMap[node] < 0) {
445     HXT_WARNING("ignoring boundary condition on node %i", node);
446     return HXT_STATUS_OK;
447   }
448   int row = system->nodeMap[node]*system->nFields + field;
449   rowZero(system->rows[row], system->rowStart[row], system->rowEnd[row]);
450   system->rows[row][row] = 1.;
451   return HXT_STATUS_OK;
452 }
453 
hxtLinearSystemLUSetMatrixRowFieldCombinaison(HXTLinearSystemLU * system,int node,int field,double * coeff)454 HXTStatus hxtLinearSystemLUSetMatrixRowFieldCombinaison(HXTLinearSystemLU *system, int node, int field, double *coeff)
455 {
456   if (system->nodeMap[node] < 0) {
457     HXT_WARNING("ignoring boundary condition on node %i", node);
458     return HXT_STATUS_OK;
459   }
460   int row0 = system->nodeMap[node]*system->nFields;
461   int row = row0+field;
462   rowZero(system->rows[row], system->rowStart[row], system->rowEnd[row]);
463   for (int i = 0; i < system->nFields; ++i) {
464     system->rows[row][row0+i] = coeff[i];
465   }
466   return HXT_STATUS_OK;
467 }
468 
hxtLinearSystemLUSetRhsEntry(HXTLinearSystemLU * system,double * rhs,int node,int field,double v)469 HXTStatus hxtLinearSystemLUSetRhsEntry(HXTLinearSystemLU *system, double *rhs, int node, int field, double v)
470 {
471   if (system->nodeMap[node] < 0) {
472     return HXT_STATUS_OK;
473   }
474   int row = system->nodeMap[node]*system->nFields + field;
475   rhs[row] = v;
476   return HXT_STATUS_OK;
477 }
478 
hxtLinearSystemLUAddMatrixEntry(HXTLinearSystemLU * system,int node0,int field0,int node1,int field1,double v)479 HXTStatus hxtLinearSystemLUAddMatrixEntry(HXTLinearSystemLU *system, int node0, int field0, int node1, int field1, double v)
480 {
481   if(system->flaglu==1)
482     return HXT_ERROR_MSG(HXT_STATUS_FAILED, "the system has been already factorised!");
483   if (system->nodeMap[node0] < 0 || system->nodeMap[node1] < 0)
484     return HXT_ERROR_MSG(HXT_STATUS_FAILED, "node %i or %i not in the domain", node0, node1);
485   int row0 = system->nodeMap[node0]*system->nFields + field0;
486   int col1 = system->nodeMap[node1]*system->nFields + field1;
487 
488   system->rows[row0][col1] += v;
489   return HXT_STATUS_OK;
490 }
491 
hxtLinearSystemLUAddRhsEntry(HXTLinearSystemLU * system,double * rhs,int node,int field,double v)492 HXTStatus hxtLinearSystemLUAddRhsEntry(HXTLinearSystemLU *system, double *rhs, int node, int field, double v)
493 {
494   if (system->nodeMap[node] < 0)
495     return HXT_STATUS_OK;
496   int row = system->nodeMap[node]*system->nFields + field;
497   rhs[row] += v;
498   return HXT_STATUS_OK;
499 }
500 
hxtLinearSystemLUSolve(HXTLinearSystemLU * system,double * rhs,double * solution)501 HXTStatus hxtLinearSystemLUSolve(HXTLinearSystemLU *system, double *rhs, double *solution){
502   if(system->flaglu==0){
503     HXT_CHECK( LUPDecompose(system) );
504     system->flaglu=1;
505   }
506 
507   LUPSolve(system, rhs);
508   for (int i = 0; i < system->nNodes; ++i){
509     int ii = system->nodeMap[i];
510     for (int j = 0; j < system->nFields; ++j){
511       solution[i*system->nFields+j] = ii < 0 ? 0. : system->x[ii*system->nFields+j];
512     }
513   }
514   return HXT_STATUS_OK;
515 }
516 
hxtLinearSystemLUHasConverged(HXTLinearSystemLU * lsys,int * converged)517 HXTStatus hxtLinearSystemLUHasConverged(HXTLinearSystemLU *lsys, int *converged)
518 {
519   // Fixme: is this really implemented correctly ? XD
520   HXT_UNUSED(lsys); // unused argument
521 
522   *converged = 1;
523   return HXT_STATUS_OK;
524 }
525 
hxtLinearSystemLUDelete(HXTLinearSystemLU ** pSystem)526 HXTStatus hxtLinearSystemLUDelete(HXTLinearSystemLU **pSystem)
527 {
528   HXTLinearSystemLU *system = *pSystem;
529   if (system == NULL)
530     return HXT_STATUS_OK;
531   HXT_CHECK( hxtAlignedFree(&system->x) );
532   HXT_CHECK( hxtAlignedFree(&system->M) );
533   HXT_CHECK( hxtFree(&system->rows) );
534   HXT_CHECK( hxtFree(&system->rowStart) );
535   HXT_CHECK( hxtFree(&system->rowEnd) );
536   HXT_CHECK( hxtFree(&system->rowLuEnd) );
537   HXT_CHECK( hxtFree(&system->nodeMap) );
538   HXT_CHECK( hxtFree(&system) );
539   *pSystem = NULL;
540   return HXT_STATUS_OK;
541 }
542 
hxtLinearSystemLUGetRhsNorm(HXTLinearSystemLU * system,double * rhs,double * pNorm)543 HXTStatus hxtLinearSystemLUGetRhsNorm(HXTLinearSystemLU *system, double *rhs, double *pNorm)
544 {
545   double norm = 0;
546   for (int i = 0; i < system->n;++i)
547       norm += rhs[i]*rhs[i];
548   *pNorm =  sqrt(norm);
549   return HXT_STATUS_OK;
550 }
551 
hxtLinearSystemLUSize(HXTLinearSystemLU * lsys,int * size)552 HXTStatus hxtLinearSystemLUSize(HXTLinearSystemLU *lsys, int *size)
553 {
554   *size = lsys->n;
555   return HXT_STATUS_OK;
556 }
557