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