PaStiX Handbook  6.2.1
solver.c
Go to the documentation of this file.
1 /**
2  * @file solver.c
3  *
4  * PaStiX solver structure basic functions.
5  *
6  * @copyright 2004-2021 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
7  * Univ. Bordeaux. All rights reserved.
8  *
9  * @version 6.2.0
10  * @author Mathieu Faverge
11  * @author Pierre Ramet
12  * @author Xavier Lacoste
13  * @author Tony Delarue
14  * @date 2021-01-03
15  *
16  **/
17 #include "common.h"
18 #include "blend/solver.h"
20 #include "sopalin/coeftab.h"
21 
22 #if defined(PASTIX_WITH_PARSEC)
24 #endif
25 
26 #if defined(PASTIX_WITH_STARPU)
28 #endif
29 
30 /**
31  *******************************************************************************
32  *
33  * @ingroup blend_dev_solver_null
34  *
35  * @brief Compute the memory size used by the solver sturcture itself.
36  *
37  * This function doesn't count the memory space of the numerical information,
38  * but only the sapce of the data structure that describes the matrix.
39  *
40  *******************************************************************************
41  *
42  * @param[in] solvptr
43  * The pointer to the solver matrix structure.
44  *
45  *******************************************************************************
46  *
47  * @return the memory size in octet of the solver structure.
48  *
49  *******************************************************************************/
50 static inline size_t
51 solver_size( const SolverMatrix *solvptr )
52 {
53  size_t mem = sizeof(SolverMatrix);
54 
55  /* cblk and blocks arrays */
56  if ( solvptr->cblktab ) {
57  mem += solvptr->cblknbr * sizeof( SolverCblk );
58  }
59  if ( solvptr->bloktab ) {
60  mem += solvptr->bloknbr * sizeof( SolverBlok );
61  }
62  if ( solvptr->browtab ) {
63  mem += solvptr->brownbr * sizeof( pastix_int_t );
64  }
65 #if defined(PASTIX_WITH_PARSEC)
66  if ( solvptr->parsec_desc ) {
67  mem += sizeof( parsec_sparse_matrix_desc_t );
68  }
69 #endif
70 #if defined(PASTIX_WITH_STARPU)
71  if ( solvptr->starpu_desc ) {
72  mem += sizeof( starpu_sparse_matrix_desc_t );
73  }
74 #endif
75 
76  /* /\* BubbleTree *\/ */
77  /* if ( solvptr->btree ) { */
78  /* mem += solvptr->bublnbr * sizeof( BubbleTree ); */
79  /* mem += solvptr->btree->nodemax * sizeof( BubbleTreeNode ); */
80  /* mem += solvptr->btree->nodemax * sizeof( int ); */
81  /* } */
82 
83  /* Tasks */
84  if ( solvptr->tasktab ) {
85  mem += solvptr->tasknbr * sizeof(Task);
86  }
87  if ( solvptr->ttsknbr ) {
88  int i;
89  mem += solvptr->thrdnbr * sizeof(pastix_int_t);
90  mem += solvptr->thrdnbr * sizeof(pastix_int_t*);
91 
92  for( i=0; i<solvptr->thrdnbr; i++ ) {
93  mem += solvptr->ttsknbr[i] * sizeof(pastix_int_t);
94  }
95  }
96 
97  return mem;
98 }
99 
100 /**
101  * @addtogroup blend_dev_solver
102  * @{
103  *
104  */
105 
106 /**
107  *******************************************************************************
108  *
109  * @brief Initialize the solver structure.
110  *
111  *******************************************************************************
112  *
113  * @param[inout] solvmtx
114  * The solver structure to initialize.
115  *
116  *******************************************************************************/
117 void
118 solverInit( SolverMatrix *solvmtx )
119 {
120  memset(solvmtx, 0, sizeof (SolverMatrix));
121  solvmtx->cblkmax1d = -1;
122  solvmtx->cblkmaxblk = 1;
123  return;
124 }
125 
126 /**
127  *******************************************************************************
128  *
129  * @brief Free the content of the solver matrix structure.
130  *
131  * All the arrays from the structure are freed and the structure is memset to 0
132  * at exit, but the solver itself is not freed. It will require a new call to
133  * solverInit if the memory space area needs to be reused for a new solver
134  * matrix.
135  *
136  *******************************************************************************
137  *
138  * @param[inout] solvmtx
139  * The pointer to the structure to free.
140  *
141  *******************************************************************************/
142 void
143 solverExit(SolverMatrix *solvmtx)
144 {
145  pastix_int_t i;
146 
147  coeftabExit( solvmtx );
148 
149  /* Free arrays of solvmtx */
150  if(solvmtx->cblktab) {
151  memFree_null(solvmtx->cblktab);
152  }
153  if(solvmtx->bloktab) {
154  memFree_null(solvmtx->bloktab);
155  }
156  if(solvmtx->browtab) {
157  memFree_null(solvmtx->browtab);
158  }
159  if(solvmtx->gcbl2loc) {
160  memFree_null(solvmtx->gcbl2loc);
161  }
162  if(solvmtx->tasktab) {
163  memFree_null(solvmtx->tasktab);
164  }
165  memFree_null(solvmtx->ttsknbr);
166  for (i=0;i<solvmtx->bublnbr;i++)
167  {
168  if (solvmtx->ttsktab[i] != NULL) {
169  memFree_null(solvmtx->ttsktab[i]);
170  }
171  }
172  memFree_null(solvmtx->ttsktab);
173 #if defined(PASTIX_WITH_STARPU)
174  {
175  if ( solvmtx->starpu_desc_rhs != NULL ) {
176  starpu_dense_matrix_destroy( solvmtx->starpu_desc_rhs );
177  free( solvmtx->starpu_desc_rhs );
178  }
179  solvmtx->starpu_desc_rhs = NULL;
180  }
181 #endif
182 }
183 
184 /**
185  *******************************************************************************
186  *
187  * @brief Print statistical information about the solver matrix structure.
188  *
189  *******************************************************************************
190  *
191  * @param[in] solvptr
192  * The pointer to the solver matrix structure.
193  *
194  *******************************************************************************/
195 void
196 solverPrintStats( const SolverMatrix *solvptr )
197 {
198  SolverCblk *cblk;
199  SolverBlok *blok;
200  size_t memstruct, memcoef;
201  pastix_int_t itercblk;
202  int64_t cblknbr;
203 
204  /* 0: Total, 1: 1d, 2: 2d */
205  int64_t fcol[3], lcol[3];
206  /* Average width of cblks, and height of off-diagonal blocks */
207  int64_t width[3] = { 0, 0, 0 };
208  int64_t height[3] = { 0, 0, 0 };
209  /* Number of cblks, and of blocks without diagonal blocks */
210  int64_t nbcblk[3] = { 0, 0, 0 };
211  int64_t nbblok[3] = { 0, 0, 0 };
212  int64_t fblok[3], lblok[3];
213  /* Number of blocks with teh regular diagonal partion of the matrix that includes subblocks */
214  int64_t nbpartblok[3] = { 0, 0, 0 };
215 
216  /* Compute the number of GEMM tasks in the multiple cases */
217  int64_t gemm_dense = 0;
218  int64_t gemm_nopart_full2 = 0;
219  int64_t gemm_nopart_hybrid = 0;
220  int64_t gemm_parsec_full2 = 0;
221  int64_t gemm_parsec_hybrid = 0;
222  int64_t gemm_starpu_full2 = 0;
223  int64_t gemm_starpu_hybrid = 0;
224  int64_t gemm_full1 = 0;
225 
226  cblknbr = solvptr->cblknbr;
227  cblk = solvptr->cblktab;
228  memcoef = 0;
229  for(itercblk=0; itercblk<cblknbr; itercblk++, cblk++)
230  {
231  pastix_int_t colnbr = cblk->lcolnum - cblk->fcolnum + 1;
232  pastix_int_t rownbr = cblk->stride;
233  pastix_int_t bcol_size = (cblk[1].fblokptr - cblk[0].fblokptr);
234  pastix_int_t brow_size[3];
235  pastix_int_t brow_csze[3] = { 0, 0, 0 };
236  pastix_int_t nbpblok = 0;
237 
238  brow_size[0] = cblk[1].brownum - cblk[0].brownum;
239  brow_size[1] = cblk[0].brown2d - cblk[0].brownum;
240  brow_size[2] = cblk[1].brownum - cblk[0].brown2d;
241  assert( brow_size[0] == (brow_size[1] + brow_size[2]) );
242 
243  memcoef += colnbr * rownbr;
244 
245  /* Update counters when no diagonal partitionning is considered and all blocks are considers */
246  gemm_nopart_full2 += brow_size[0] * bcol_size;
247  gemm_nopart_hybrid += brow_size[1] + (brow_size[2] * bcol_size);
248 
249  /* Compute the compressed version of the brow size */
250  {
251  pastix_int_t b, lcblk = -1;
252  pastix_int_t *browptr = solvptr->browtab + cblk[0].brownum;
253  for ( b = cblk[0].brownum; b < cblk[1].brownum; b++, browptr++ ) {
254  blok = solvptr->bloktab + (*browptr);
255  if ( blok->lcblknm != lcblk ) {
256  lcblk = blok->lcblknm;
257 
258  brow_csze[0]++;
259  if ( (solvptr->cblktab + lcblk)->cblktype & CBLK_TASKS_2D ) {
260  brow_csze[2]++;
261  }
262  else {
263  brow_csze[1]++;
264  }
265  }
266  }
267  assert( brow_csze[0] == (brow_csze[1] + brow_csze[2]) );
268  assert( brow_csze[0] <= brow_size[0] );
269  assert( brow_csze[1] <= brow_size[1] );
270  assert( brow_csze[2] <= brow_size[2] );
271  }
272 
273  /*
274  * Compute the compressed version of the bcol size
275  * The algorithm goes backward to avoid a double pass to compute StarPU
276  * number of tasks.
277  */
278  blok = cblk->fblokptr + 1;
279  while( blok < cblk[1].fblokptr ) {
280  while( (blok < cblk[1].fblokptr-1) &&
281  (blok[0].fcblknm == blok[1].fcblknm) &&
282  (blok[0].lcblknm == blok[1].lcblknm) )
283  {
284  blok++;
285  }
286  nbpblok++;
287  blok++;
288  }
289 
290  /* Compute the number of PaRSEC GEMM tasks in a left looking manner */
291  gemm_parsec_full2 += (nbpblok+1) * brow_size[0];
292  gemm_parsec_hybrid += ((nbpblok+1) * brow_size[2]) + brow_size[1];
293 
294  /* Compute the number of StarPU GEMM tasks in a right looking manner */
295  gemm_starpu_full2 += (nbpblok * (nbpblok+1)) / 2;
296 
297  if (cblk->cblktype & CBLK_TASKS_2D) {
298  gemm_starpu_hybrid += (nbpblok * (nbpblok+1)) / 2;
299 
300  nbpartblok[2] += nbpblok;
301  width[2] += colnbr;
302  height[2] += rownbr - colnbr;
303  }
304  else {
305  gemm_starpu_hybrid += bcol_size - 1;
306 
307  nbpartblok[1] += nbpblok;
308  width[1] += colnbr;
309  height[1] += rownbr - colnbr;
310  }
311 
312  nbpartblok[0] += nbpblok;
313  width[0] += colnbr;
314  height[0] += rownbr - colnbr;
315  }
316 
317  assert( (width[1] + width[2]) == solvptr->nodenbr );
318  assert( (width[1] + width[2]) == width[0] );
319  assert( (height[1] + height[2]) == height[0] );
320 
321  memstruct = solver_size( solvptr );
322 
323  gemm_dense = (cblknbr * ( cblknbr * cblknbr - 1 )) / 6;
324  gemm_full1 = solvptr->bloknbr - solvptr->cblknbr;
325 
326  fcol[0] = 0;
327  fcol[1] = 0;
328  fcol[2] = (solvptr->cblktab + solvptr->cblkmin2d)->fcolnum;
329 
330  lcol[0] = (solvptr->cblktab + solvptr->cblknbr )->fcolnum;
331  lcol[1] = (solvptr->cblktab + solvptr->cblkmax1d)->lcolnum + 1;
332  lcol[2] = (solvptr->cblktab + solvptr->cblknbr )->fcolnum;
333 
334  nbcblk[0] = cblknbr;
335  nbcblk[1] = (cblknbr - solvptr->nb2dcblk);
336  nbcblk[2] = solvptr->nb2dcblk;
337 
338  nbblok[0] = solvptr->bloknbr - cblknbr;
339  nbblok[1] = (solvptr->bloknbr - cblknbr) - (solvptr->nb2dblok - solvptr->nb2dcblk);
340  nbblok[2] = solvptr->nb2dblok - solvptr->nb2dcblk;
341 
342  fblok[0] = 0;
343  fblok[1] = 0;
344  fblok[2] = ((solvptr->cblktab + solvptr->cblkmin2d)->fblokptr - solvptr->bloktab);
345 
346  lblok[0] = solvptr->bloknbr;
347  lblok[1] = (solvptr->cblktab + solvptr->cblkmax1d + 1)->fblokptr - solvptr->bloktab;
348  lblok[2] = solvptr->bloknbr;
349 
350  fprintf( stdout,
351  " Solver Matrix statistics: | %-12s | %-12s | %-12s |\n"
352  " --------------------------------------------------------------------------------\n"
353  " Number of cblk | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
354  " Number of block | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
355  " Number of block (diag part.) | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
356  " Cblk: first | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
357  " last | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
358  " Block: first | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
359  " last | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
360  " rownum: first | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
361  " last | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
362  " Average width | %12.2lf | %12.2lf | %12.2lf |\n"
363  " Average height | %12.2lf | %12.2lf | %12.2lf |\n"
364  " Structure memory space %11.2lf %co\n"
365  " Number of coeficients stored %10ld\n",
366  /* Header */
367  "All", "1d", "2d",
368  /* Number of cblk */
369  nbcblk[0], nbcblk[1], nbcblk[2],
370  /* Number of blok without diagonal blocks (Add cblknbr to get the total) */
371  nbblok[0], nbblok[1], nbblok[2],
372  /*
373  * Number of block in the compressed version (count 1 per block in
374  * the matrix partition following the diagonal blocks
375  */
376  nbpartblok[0], nbpartblok[1], nbpartblok[2],
377  /* Cblk */
378  (int64_t)0, (int64_t)0, (int64_t)(solvptr->cblkmin2d),
379  (int64_t)(cblknbr), (int64_t)(solvptr->cblkmax1d + 1), (int64_t)(cblknbr),
380  /* Blok */
381  fblok[0], fblok[1], fblok[2],
382  lblok[0], lblok[1], lblok[2],
383  /* Rownum/Colnum */
384  fcol[0], fcol[1], fcol[2],
385  lcol[0], lcol[1], lcol[2],
386  /* Average width */
387  (double)(width[0]) / (double)(nbcblk[0]),
388  (double)(width[1]) / (double)(nbcblk[1]),
389  (double)(width[2]) / (double)(nbcblk[2]),
390  /* Average height */
391  (double)(height[0]) / (double)(nbblok[0]),
392  (double)(height[1]) / (double)(nbblok[1]),
393  (double)(height[2]) / (double)(nbblok[2]),
394  /* Memory space */
395  pastix_print_value( memstruct ),
396  pastix_print_unit( memstruct ),
397  /* Memory coefficient */
398  (long)memcoef );
399 
400  fprintf( stdout,
401  " Number of GEMM tasks: | %-12s | %-12s | %-12s | %-12s |\n"
402  " - All blocks | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
403  " - PaRSEC | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n"
404  " - StarPU | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " | %12" PRIi64 " |\n",
405  "Dense", "Full2d", "Hybrid", "Full1d",
406  gemm_dense, gemm_nopart_full2, gemm_nopart_hybrid, gemm_full1,
407  gemm_dense, gemm_parsec_full2, gemm_parsec_hybrid, gemm_full1,
408  gemm_dense, gemm_starpu_full2, gemm_starpu_hybrid, gemm_full1 );
409 }
410 
411 /**
412  *******************************************************************************
413  *
414  * @brief Instanciate the arrays for the requests according to the scheduler.
415  *
416  *******************************************************************************
417  *
418  * @param[inout] solvmtx
419  * The pointer to the solver matrix structure.
420  *
421  *******************************************************************************/
422 void
423 solverRequestInit( SolverMatrix *solvmtx )
424 {
425  MPI_Request *request;
426  pastix_int_t *reqindx;
427  pastix_int_t i, reqnbr;
428 
429  reqnbr = solvmtx->faninnbr + 1;
430  solvmtx->reqnbr = reqnbr;
431  solvmtx->reqlock = PASTIX_ATOMIC_UNLOCKED;
432 
433  MALLOC_INTERN( solvmtx->reqtab, reqnbr, MPI_Request );
434  MALLOC_INTERN( solvmtx->reqidx, reqnbr, pastix_int_t );
435 
436  request = solvmtx->reqtab;
437  reqindx = solvmtx->reqidx;
438  for ( i = 0; i < reqnbr; i++, request++, reqindx++ )
439  {
440  *request = MPI_REQUEST_NULL;
441  *reqindx = -1;
442  }
443  solverComMatrixInit( solvmtx );
444  return;
445 }
446 
447 /**
448  *******************************************************************************
449  *
450  * @brief Free the arrays related to the requests
451  *
452  *******************************************************************************
453  *
454  * @param[inout] solvmtx
455  * The pointer to the solver matrix structure.
456  *
457  *******************************************************************************/
458 void
459 solverRequestExit( SolverMatrix *solvmtx )
460 {
461  assert( solvmtx->reqnum == 0 );
462  assert( solvmtx->reqlock == PASTIX_ATOMIC_UNLOCKED );
463 
464  if( solvmtx->reqtab ) {
465  memFree_null( solvmtx->reqtab );
466  }
467  if( solvmtx->reqidx ) {
468  memFree_null( solvmtx->reqidx );
469  }
470  solverComMatrixGather( solvmtx );
471  solverComMatrixExit( solvmtx );
472 }
473 
474 /**
475  *******************************************************************************
476  *
477  * @brief Allocate the reception buffer, and initiate the first persistant
478  * reception
479  *
480  *******************************************************************************
481  *
482  * @param[in] side
483  * Define which side of the cblk must be tested.
484  * @arg PastixLCoef if lower part only
485  * @arg PastixUCoef if upper part only
486  * @arg PastixLUCoef if both sides.
487  *
488  * @param[inout] solvmtx
489  * The pointer to the solver matrix structure.
490  *
491  * @param[in] flttype
492  * Define which type are the coefficients.
493  * @arg PastixFloat
494  * @arg PastixDouble
495  * @arg PastixComplex32
496  * @arg PastixComplex64
497  *
498  *******************************************************************************/
499 void
501  SolverMatrix *solvmtx,
502  int flttype )
503 {
504  /* Compute the max size (in bytes) for the communication buffer */
505  pastix_int_t size = pastix_size_of(flttype) * solvmtx->maxrecv;
506  size *= (side == PastixLUCoef) ? 2 : 1;
507 
508  if( solvmtx->recvnbr == 0 ) {
509  return;
510  }
511 
512  assert( solvmtx->maxrecv > 0 );
513 
514  /* Init communication */
515  MALLOC_INTERN( solvmtx->rcoeftab, size, char );
516  MPI_Recv_init( solvmtx->rcoeftab, size,
517  MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG,
518  solvmtx->solv_comm, solvmtx->reqtab );
519  MPI_Start( solvmtx->reqtab );
520 
521  solvmtx->reqnum++;
522 #if defined(PASTIX_DEBUG_MPI)
523  fprintf( stderr, "[%2d] Start persistant recv from any source\n",
524  solvmtx->clustnum );
525 #endif
526 }
527 
528 /**
529  *******************************************************************************
530  *
531  * @brief Free the array linked to pending reception.
532  *
533  *******************************************************************************
534  *
535  * @param[inout] solvmtx
536  * The pointer to the solver matrix structure.
537  *
538  *******************************************************************************/
539 void
540 solverRecvExit( SolverMatrix *solvmtx )
541 {
542  /* In fact, the pointer should never been freed by this call */
543  assert( solvmtx->reqtab == NULL );
544  if( solvmtx->rcoeftab ) {
545  memFree_null( solvmtx->rcoeftab );
546  }
547 }
548 
549 /**
550  *@}
551  */
solver.h
SolverCblk
struct solver_cblk_s SolverCblk
Solver column block structure.
solver_cblk_s::fblokptr
SolverBlok * fblokptr
Definition: solver.h:134
solver_blok_s::lcblknm
pastix_int_t lcblknm
Definition: solver.h:109
solverRequestExit
void solverRequestExit(SolverMatrix *solvmtx)
Free the arrays related to the requests.
Definition: solver.c:459
solver_cblk_s::stride
pastix_int_t stride
Definition: solver.h:135
starpu_sparse_matrix_desc_t
struct starpu_sparse_matrix_desc_s starpu_sparse_matrix_desc_t
StarPU descriptor stucture for the sparse matrix.
solver_cblk_s
Solver column block structure.
Definition: solver.h:127
solverInit
void solverInit(SolverMatrix *solvmtx)
Initialize the solver structure.
Definition: solver.c:118
pastix_coefside_t
enum pastix_coefside_e pastix_coefside_t
Data blocks used in the kernel.
solverRecvExit
void solverRecvExit(SolverMatrix *solvmtx)
Free the array linked to pending reception.
Definition: solver.c:540
pastix_parsec.h
solver_blok_s
Solver block structure.
Definition: solver.h:107
solver_comm_matrix.h
solver_cblk_s::lcolnum
pastix_int_t lcolnum
Definition: solver.h:133
solverPrintStats
void solverPrintStats(const SolverMatrix *solvptr)
Print statistical information about the solver matrix structure.
Definition: solver.c:196
solverRecvInit
void solverRecvInit(pastix_coefside_t side, SolverMatrix *solvmtx, int flttype)
Allocate the reception buffer, and initiate the first persistant reception.
Definition: solver.c:500
starpu_dense_matrix_destroy
void starpu_dense_matrix_destroy(starpu_dense_matrix_desc_t *desc)
Free the StarPU descriptor of the dense matrix.
Definition: starpu_dense_matrix.c:170
solverComMatrixExit
void solverComMatrixExit(SolverMatrix *solvmtx)
Free the communication matrix.
Definition: solver_comm_matrix.c:51
solverRequestInit
void solverRequestInit(SolverMatrix *solvmtx)
Instanciate the arrays for the requests according to the scheduler.
Definition: solver.c:423
solver_cblk_s::brown2d
pastix_int_t brown2d
Definition: solver.h:138
solver_cblk_s::brownum
pastix_int_t brownum
Definition: solver.h:137
solverExit
void solverExit(SolverMatrix *solvmtx)
Free the content of the solver matrix structure.
Definition: solver.c:143
solverComMatrixGather
void solverComMatrixGather(SolverMatrix *solvmtx)
Gather the volume of communication and save it as a csv.
Definition: solver_comm_matrix.c:69
solverComMatrixInit
void solverComMatrixInit(SolverMatrix *solvmtx)
Initialize the communication matrix.
Definition: solver_comm_matrix.c:34
parsec_sparse_matrix_desc_s
Definition: pastix_parsec.h:33
coeftabExit
void coeftabExit(SolverMatrix *solvmtx)
Free the solver matrix structure.
Definition: coeftab.c:182
Task
struct task_s Task
The task structure for the numerical factorization.
solver_cblk_s::cblktype
int8_t cblktype
Definition: solver.h:130
PastixLUCoef
@ PastixLUCoef
Definition: api.h:456
coeftab.h
solver_cblk_s::fcolnum
pastix_int_t fcolnum
Definition: solver.h:132
pastix_starpu.h
solver_size
static size_t solver_size(const SolverMatrix *solvptr)
Compute the memory size used by the solver sturcture itself.
Definition: solver.c:51
SolverBlok
struct solver_blok_s SolverBlok
Solver block structure.