void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT n, nel, s ; cs *A, *AT ; if (nargout > 1 || nargin != 3) { mexErrMsgTxt ("Usage: C = cs_frand(n,nel,s)") ; } n = mxGetScalar (pargin [0]) ; nel = mxGetScalar (pargin [1]) ; s = mxGetScalar (pargin [2]) ; n = CS_MAX (1,n) ; nel = CS_MAX (1,nel) ; s = CS_MAX (1,s) ; AT = cs_dl_frand (n, nel, s) ; A = cs_dl_transpose (AT, 1) ; cs_dl_spfree (AT) ; cs_dl_dropzeros (A) ; pargout [0] = cs_dl_mex_put_sparse (&A) ; }
/* add an entry to a triplet matrix; return 1 if ok, 0 otherwise */ int cs_entry (cs *T, int i, int j, double x) { if (!CS_TRIPLET (T) || i < 0 || j < 0) return (0) ; /* check inputs */ if (T->nz >= T->nzmax && !cs_sprealloc (T,2*(T->nzmax))) return (0) ; if (T->x) T->x [T->nz] = x ; T->i [T->nz] = i ; T->p [T->nz++] = j ; T->m = CS_MAX (T->m, i+1) ; T->n = CS_MAX (T->n, j+1) ; return (1) ; }
/* cs_qrsol: solve least squares or underdetermined problem */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT k, order ; if (nargout > 1 || nargin < 2 || nargin > 3) { mexErrMsgTxt ("Usage: x = cs_qrsol(A,b,order)") ; } order = (nargin < 3) ? 3 : mxGetScalar (pargin [2]) ; order = CS_MAX (order, 0) ; order = CS_MIN (order, 3) ; if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl *A, Amatrix ; cs_complex_t *x, *b ; A = cs_cl_mex_get_sparse (&Amatrix, 0, pargin [0]) ; /* get A */ b = cs_cl_mex_get_double (A->m, pargin [1]) ; /* get b */ x = cs_dl_calloc (CS_MAX (A->m, A->n), sizeof (cs_complex_t)) ; for (k = 0 ; k < A->m ; k++) x [k] = b [k] ; /* x = b */ cs_free (b) ; if (!cs_cl_qrsol (order, A, x)) /* x = A\x */ { mexErrMsgTxt ("QR solve failed") ; } pargout [0] = cs_cl_mex_put_double (A->n, x) ; /* return x */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl *A, Amatrix ; double *x, *b ; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ b = cs_dl_mex_get_double (A->m, pargin [1]) ; /* get b */ x = cs_dl_calloc (CS_MAX (A->m, A->n), sizeof (double)) ; /* x = b */ for (k = 0 ; k < A->m ; k++) x [k] = b [k] ; if (!cs_dl_qrsol (order, A, x)) /* x = A\x */ { mexErrMsgTxt ("QR solve failed") ; } cs_dl_mex_put_double (A->n, x, &(pargout [0])) ; /* return x */ cs_free (x) ; } }
/* allocate a sparse matrix (triplet form or compressed-column form) */ csr *csr_spalloc (int m, int n, int nzmax, int values, int triplet) { csr *A = (csr*)calloc (1, sizeof (csr)) ; /* allocate the csr struct */ if (!A) return (NULL) ; /* out of memory */ A->m = m ; /* define dimensions and nzmax */ A->n = n ; A->nzmax = nzmax = CS_MAX (nzmax, 1) ; A->nz = triplet ? 0 : -1 ; /* allocate triplet or comp.row */ A->p = (int*)malloc (triplet ? CS_MAX(nzmax,1) * sizeof (int) : CS_MAX(m+1,1) * sizeof (int)) ; A->j = (int*)malloc (CS_MAX(nzmax,1) * sizeof (int)) ; A->x = values ? (double*)malloc (CS_MAX(nzmax,1) * sizeof (double)) : NULL ; return ((!A->p || !A->j || (values && !A->x)) ? csr_spfree (A) : A) ; }
/* C = alpha*A + beta*B */ csr *csr_add (const csr *A, const csr *B, double alpha, double beta) { int p, j, nz = 0, anz, *Cp, *Cj, *Bp, m, n, bnz, *w, values ; double *x, *Bx, *Cx ; csr *C ; if (!CS_CSC (A) || !CS_CSC (B)) return (NULL) ; /* check inputs */ if ( (A->m != B->m) || (A->n != B->n) ) return (NULL); m = A->m ; anz = A->p [m] ; n = B->n ; Bp = B->p ; Bx = B->x ; bnz = Bp [m] ; w = (int*)calloc (CS_MAX(n,1), sizeof (int)) ; /* get workspace */ values = (A->x != NULL) && (Bx != NULL) ; x = values ? (double*)malloc (n * sizeof (double)) : NULL ; /* get workspace */ C = csr_spalloc (m, n, anz + bnz, values, 0) ; /* allocate result*/ if (!C || !w || (values && !x)) return (csr_done (C, w, x, 0)) ; Cp = C->p ; Cj = C->j ; Cx = C->x ; for (j = 0 ; j < n ; j++) { Cp [j] = nz ; /* row j of C starts here */ nz = csr_scatter (A, j, alpha, w, x, j+1, C, nz) ; /* alpha*A(j,:)*/ nz = csr_scatter (B, j, beta, w, x, j+1, C, nz) ; /* beta*B(j,:) */ if (values) for (p = Cp [j] ; p < nz ; p++) Cx [p] = x [Cj [p]] ; } Cp [m] = nz ; /* finalize the last row of C */ csr_sprealloc (C, 0) ; /* remove extra space from C */ return (csr_done (C, w, x, 1)) ; /* success; free workspace, return C */ }
/* infinity-norm of x */ static double norm (double *x, int n) { int i ; double normx = 0 ; for (i = 0 ; i < n ; i++) normx = CS_MAX (normx, fabs (x [i])) ; return (normx) ; }
/* read a problem from a file; use %g for integers to avoid int conflicts */ problem *get_problem (FILE *f, double tol) { cs *T, *A, *C ; int sym, m, n, mn, nz1, nz2 ; problem *Prob ; Prob = cs_calloc (1, sizeof (problem)) ; if (!Prob) return (NULL) ; T = cs_load (f) ; /* load triplet matrix T from a file */ Prob->A = A = cs_compress (T) ; /* A = compressed-column form of T */ cs_spfree (T) ; /* clear T */ if (!cs_dupl (A)) return (free_problem (Prob)) ; /* sum up duplicates */ Prob->sym = sym = is_sym (A) ; /* determine if A is symmetric */ m = A->m ; n = A->n ; mn = CS_MAX (m,n) ; nz1 = A->p [n] ; cs_dropzeros (A) ; /* drop zero entries */ nz2 = A->p [n] ; if (tol > 0) cs_droptol (A, tol) ; /* drop tiny entries (just to test) */ Prob->C = C = sym ? make_sym (A) : A ; /* C = A + triu(A,1)', or C=A */ if (!C) return (free_problem (Prob)) ; printf ("\n--- Matrix: %g-by-%g, nnz: %g (sym: %g: nnz %g), norm: %8.2e\n", (double) m, (double) n, (double) (A->p [n]), (double) sym, (double) (sym ? C->p [n] : 0), cs_norm (C)) ; if (nz1 != nz2) printf ("zero entries dropped: %g\n", (double) (nz1 - nz2)); if (nz2 != A->p [n]) printf ("tiny entries dropped: %g\n", (double) (nz2 - A->p [n])) ; Prob->b = cs_malloc (mn, sizeof (double)) ; Prob->x = cs_malloc (mn, sizeof (double)) ; Prob->resid = cs_malloc (mn, sizeof (double)) ; return ((!Prob->b || !Prob->x || !Prob->resid) ? free_problem (Prob) : Prob) ; }
static void _compute_minmax(cs_int_t n_vals, const cs_real_t var[], cs_real_t *min, cs_real_t *max) { cs_int_t i; cs_real_t _min = DBL_MAX, _max = -DBL_MAX; for (i = 0; i < n_vals; i++) { _min = CS_MIN(_min, var[i]); _max = CS_MAX(_max, var[i]); } #if defined(HAVE_MPI) if (cs_glob_n_ranks > 1) { MPI_Allreduce(&_min, min, 1, CS_MPI_REAL, MPI_MIN, cs_glob_mpi_comm); MPI_Allreduce(&_max, max, 1, CS_MPI_REAL, MPI_MAX, cs_glob_mpi_comm); } #endif if (cs_glob_n_ranks == 1) { *min = _min; *max = _max; } }
/* infinity-norm of x */ static double norm (cs_complex_t *x, cs_long_t n) { cs_long_t i ; double normx = 0 ; for (i = 0 ; i < n ; i++) normx = CS_MAX (normx, cabs (x [i])) ; return (normx) ; }
void *cs_realloc(void *p, int n, size_t size, int *ok) { void *pnew; pnew = realloc(p, CS_MAX (n,1) * size); /* realloc the block */ *ok = (pnew != NULL); /* realloc fails if pnew is NULL */ return ((*ok) ? pnew : p); /* return original p if failure */ }
/* C = A*B */ csr *csr_multiply (const csr *A, const csr *B) { int p, j, nz = 0, anz, *Cp, *Cj, *Ap, m, k, n, bnz, *w, values, *Aj; double *x, *Ax, *Cx ; csr *C ; if (!CS_CSC (A) || !CS_CSC (B)) return (NULL) ; /* check inputs */ k = A->n; if (k != B->m ) return(NULL); m = A->m ; anz = A->p [A->m] ; n = B->n ; Ap = A->p ; Aj = A->j ; Ax = A->x ; bnz = B->p [k] ; w = (int*)calloc (CS_MAX(n,1), sizeof (int)) ; /* get workspace */ values = (Ax != NULL) && (B->x != NULL) ; x = values ? (double*)malloc (n * sizeof (double)) : NULL ; /* get workspace */ C = csr_spalloc (m, n, anz + bnz, values, 0) ; /* allocate result */ if (!C || !w || (values && !x)) return (csr_done (C, w, x, 0)) ; Cp = C->p ; for (j = 0 ; j < m ; j++) { if (nz + n > C->nzmax && !csr_sprealloc (C, 2*(C->nzmax)+m)) { return (csr_done (C, w, x, 0)) ; /* out of memory */ } Cj = C->j ; Cx = C->x ; /* C->j and C->x may be reallocated */ Cp [j] = nz ; /* row j of C starts here */ for (p = Ap [j] ; p < Ap [j+1] ; p++) { nz = csr_scatter (B, Aj [p], Ax ? Ax [p] : 1, w, x, j+1, C, nz) ; } if (values) for (p = Cp [j] ; p < nz ; p++) Cx [p] = x [Cj [p]] ; } Cp [m] = nz ; /* finalize the last column of C */ csr_sprealloc (C, 0) ; /* remove extra space from C */ return (csr_done (C, w, x, 1)) ; /* success; free workspace, return C */ }
/* cs_lusol: solve A*x=b using a sparse LU factorization */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { double tol ; CS_INT order ; if (nargout > 1 || nargin < 2 || nargin > 4) { mexErrMsgTxt ("Usage: x = cs_lusol(A,b,order,tol)") ; } order = (nargin < 3) ? 2 : mxGetScalar (pargin [2]) ; order = CS_MAX (order, 0) ; order = CS_MIN (order, 3) ; if (nargin == 2) { tol = 1 ; /* normal partial pivoting */ } else if (nargin == 3) { tol = (order == 1) ? 0.001 : 1 ; /* tol = 0.001 for amd(A+A') */ } else { tol = mxGetScalar (pargin [3]) ; } if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl *A, Amatrix ; cs_complex_t *x ; A = cs_cl_mex_get_sparse (&Amatrix, 1, pargin [0]) ; /* get A */ x = cs_cl_mex_get_double (A->n, pargin [1]) ; /* x = b */ if (!cs_cl_lusol (order, A, x, tol)) /* x = A\x */ { mexErrMsgTxt ("failed (singular or out of memory)") ; } cs_cl_free (A->x) ; /* complex copy no longer needed */ pargout [0] = cs_cl_mex_put_double (A->n, x) ; /* return x */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl *A, Amatrix ; double *x, *b ; A = cs_dl_mex_get_sparse (&Amatrix, 1, 1, pargin [0]) ; /* get A */ b = cs_dl_mex_get_double (A->n, pargin [1]) ; /* get b */ x = cs_dl_mex_put_double (A->n, b, &(pargout [0])) ; /* x = b */ if (!cs_dl_lusol (order, A, x, tol)) /* x = A\x */ { mexErrMsgTxt ("failed (singular or out of memory)") ; } } }
cs *cs_symperm(const cs *A, const int *pinv, int values) { int i, j, p, q, i2, j2, n, *Ap, *Ai, *Cp, *Ci, *w; double *Cx, *Ax; cs *C; if (!CS_CSC (A)) return (NULL); /* check inputs */ n = A->n; Ap = A->p; Ai = A->i; Ax = A->x; C = cs_spalloc(n, n, Ap[n], values && (Ax != NULL), 0); /* alloc result*/ w = (int *) cs_calloc(n, sizeof(int)); /* get workspace */ if (!C || !w) return (cs_done(C, w, NULL, 0)); /* out of memory */ Cp = C->p; Ci = C->i; Cx = C->x; for (j = 0; j < n; j++) /* count entries in each column of C */ { j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */ for (p = Ap[j]; p < Ap[j + 1]; p++) { i = Ai[p]; if (i > j) continue; /* skip lower triangular part of A */ i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */ w[CS_MAX (i2, j2)]++; /* column count of C */ } } cs_cumsum(Cp, w, n); /* compute column pointers of C */ for (j = 0; j < n; j++) { j2 = pinv ? pinv[j] : j; /* column j of A is column j2 of C */ for (p = Ap[j]; p < Ap[j + 1]; p++) { i = Ai[p]; if (i > j) continue; /* skip lower triangular part of A*/ i2 = pinv ? pinv[i] : i; /* row i of A is row i2 of C */ Ci[q = w[CS_MAX (i2, j2)]++] = CS_MIN (i2, j2); if (Cx) Cx[q] = Ax[p]; } } return (cs_done(C, w, NULL, 1)); /* success; free workspace, return C */ }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { cs Amatrix, *A ; int m, n, mn, m2, n2, k, s, j, ij, sj, si, p, *Ap, *Ai ; double aij, *S, *Ax ; if (nargout > 1 || nargin < 1 || nargin > 2) { mexErrMsgTxt ("Usage: S = cs_thumb(A,k)") ; } A = cs_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ m = A->m ; n = A->n ; mn = CS_MAX (m,n) ; k = (nargin == 1) ? 256 : mxGetScalar (pargin [1]) ; /* get k */ /* s = size of each submatrix; A(1:s,1:s) maps to S(1,1) */ s = (mn < k) ? 1 : (int) ceil ((double) mn / (double) k) ; m2 = (int) ceil ((double) m / (double) s) ; n2 = (int) ceil ((double) n / (double) s) ; /* create S */ pargout [0] = mxCreateDoubleMatrix (m2, n2, mxREAL) ; S = mxGetPr (pargout [0]) ; Ap = A->p ; Ai = A->i ; Ax = A->x ; for (j = 0 ; j < n ; j++) { sj = j/s ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { si = Ai [p] / s ; ij = INDEX (si,sj,m2) ; aij = fabs (Ax [p]) ; if (ISNAN (aij)) aij = BIG_VALUE ; aij = CS_MIN (BIG_VALUE, aij) ; S [ij] = CS_MAX (S [ij], aij) ; } } }
/* 1-norm of a sparse matrix = max (sum (abs (A))), largest column sum */ double cs_norm (const cs *A) { int p, j, n, *Ap ; double *Ax, norm = 0, s ; if (!CS_CSC (A) || !A->x) return (-1) ; /* check inputs */ n = A->n ; Ap = A->p ; Ax = A->x ; for (j = 0 ; j < n ; j++) { for (s = 0, p = Ap [j] ; p < Ap [j+1] ; p++) s += fabs (Ax [p]) ; norm = CS_MAX (norm, s) ; } return (norm) ; }
/* allocate a sparse matrix (triplet form or compressed-column form) */ cs *cs_spalloc (int m, int n, int nzmax, int values, int triplet) { cs *A = cs_calloc (1, sizeof (cs)) ; /* allocate the cs struct */ if (!A) return (NULL) ; /* out of memory */ A->m = m ; /* define dimensions and nzmax */ A->n = n ; A->nzmax = nzmax = CS_MAX (nzmax, 1) ; A->nz = triplet ? 0 : -1 ; /* allocate triplet or comp.col */ A->p = cs_malloc (triplet ? nzmax : n+1, sizeof (int)) ; A->i = cs_malloc (nzmax, sizeof (int)) ; A->x = values ? cs_malloc (nzmax, sizeof (double)) : NULL ; return ((!A->p || !A->i || (values && !A->x)) ? cs_spfree (A) : A) ; }
/* get a MATLAB flint array and convert to int */ int *cs_mex_get_int (int n, const mxArray *Imatlab, int *imax, int lo) { double *p ; int i, k, *C = cs_malloc (n, sizeof (int)) ; cs_mex_check (1, n, 1, 0, 0, 1, Imatlab) ; p = mxGetPr (Imatlab) ; *imax = 0 ; for (k = 0 ; k < n ; k++) { i = p [k] ; C [k] = i - 1 ; if (i < lo) mexErrMsgTxt ("index out of bounds") ; *imax = CS_MAX (*imax, i) ; } return (C) ; }
/* cs_amd: approximate minimum degree ordering */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { cs Amatrix, *A ; int *P, order ; if (nargout > 1 || nargin < 1 || nargin > 2) { mexErrMsgTxt ("Usage: p = cs_amd(A,order)") ; } A = cs_mex_get_sparse (&Amatrix, 0, 0, pargin [0]) ; /* get A */ order = (nargin > 1) ? mxGetScalar (pargin [1]) : 1 ; /* get ordering */ order = CS_MAX (order, 1) ; order = CS_MIN (order, 3) ; P = cs_amd (order, A) ; /* min. degree ordering */ pargout [0] = cs_mex_put_int (P, A->n, 1, 1) ; /* return P */ }
/* get a MATLAB flint array and convert to CS_INT */ CS_INT *cs_dl_mex_get_int (CS_INT n, const mxArray *Imatlab, CS_INT *imax, int lo) { double *p ; CS_INT i, k, *C = cs_dl_malloc (n, sizeof (CS_INT)) ; cs_mex_check (1, n, 1, 0, 0, 1, Imatlab) ; if (mxIsComplex (Imatlab)) { mexErrMsgTxt ("integer input cannot be complex") ; } p = mxGetPr (Imatlab) ; *imax = 0 ; for (k = 0 ; k < n ; k++) { i = p [k] ; C [k] = i - 1 ; if (i < lo) mexErrMsgTxt ("index out of bounds") ; *imax = CS_MAX (*imax, i) ; } return (C) ; }
/* cs_lusol: solve A*x=b using a sparse LU factorization */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { cs *A, Amatrix ; csi order ; double *x, *b, tol ; if (nargout > 1 || nargin < 2 || nargin > 4) { mexErrMsgTxt ("Usage: x = cs_lusol(A,b,order,tol)") ; } A = cs_mex_get_sparse (&Amatrix, 1, 1, pargin [0]) ; /* get A */ b = cs_mex_get_double (A->n, pargin [1]) ; /* get b */ x = cs_mex_put_double (A->n, b, &(pargout [0])) ; /* x = b */ order = (nargin < 3) ? 2 : mxGetScalar (pargin [2]) ; order = CS_MAX (order, 0) ; order = CS_MIN (order, 3) ; if (nargin == 2) { tol = 1 ; /* normal partial pivoting */ } else if (nargin == 3) { tol = (order == 1) ? 0.001 : 1 ; /* tol = 0.001 for amd(A+A') */ } else { tol = mxGetScalar (pargin [3]) ; } if (!cs_lusol (order, A, x, tol)) /* x = A\x */ { mexErrMsgTxt ("LU factorization failed (singular or out of memory)") ; } }
/* C = A' */ csr *csr_transpose (const csr *A, int values) { int p, q, i, *Cp, *Cj, n, m, *Ap, *Aj, *w ; double *Cx, *Ax ; csr *C ; if (!CS_CSC (A)) return (NULL) ; /* check inputs */ m = A->m ; n = A->n ; Ap = A->p ; Aj = A->j ; Ax = A->x ; C = csr_spalloc (n, m, Ap [m], values && Ax, 0) ; /* allocate result */ w = (int*)calloc (CS_MAX(n,1), sizeof (int)) ; /* get workspace */ if (!C || !w) return (csr_done (C, w, NULL, 0)) ; /* out of memory */ Cp = C->p ; Cj = C->j ; Cx = C->x ; for (p = 0 ; p < Ap [m] ; p++) w [Aj [p]]++ ; /* col counts */ csr_cumsum (Cp, w, n) ; /* col pointers */ for (i = 0 ; i < m ; i++) { for (p = Ap [i] ; p < Ap [i+1] ; p++) { Cj [q = w [Aj [p]]++] = i ; /* place A(i,j) as entry C(j,i) */ if (Cx) Cx [q] = Ax [p] ; } } return (csr_done (C, w, NULL, 1)) ; /* success; free w and return C */ }
static void _update_bt_statistics(_box_tree_stats_t *bts, const fvm_box_tree_t *bt) { int dim; size_t i; size_t mem_required[3]; assert(bts != NULL); dim = fvm_box_tree_get_stats(bt, bts->depth, bts->n_leaves, bts->n_boxes, bts->n_threshold_leaves, bts->n_leaf_boxes, bts->mem_used, mem_required); bts->dim = dim; for (i = 0; i < 3; i++) bts->mem_required[i] = CS_MAX(bts->mem_required[i], mem_required[i]); }
/* p = amd(A+A') if symmetric is true, or amd(A'A) otherwise */ CS_INT *cs_amd (CS_INT order, const cs *A) /* order 0:natural, 1:Chol, 2:LU, 3:QR */ { cs *C, *A2, *AT ; CS_INT *Cp, *Ci, *last, *W, *len, *nv, *next, *P, *head, *elen, *degree, *w, *hhead, *ATp, *ATi, d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1, k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi, ok, cnz, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, n, m, t ; unsigned CS_INT h ; /* --- Construct matrix C ----------------------------------------------- */ if (!CS_CSC (A) || order <= 0 || order > 3) return (NULL) ; /* check */ AT = cs_transpose (A, 0) ; /* compute A' */ if (!AT) return (NULL) ; m = A->m ; n = A->n ; dense = CS_MAX (16, 10 * sqrt ((double) n)) ; /* find dense threshold */ dense = CS_MIN (n-2, dense) ; if (order == 1 && n == m) { C = cs_add (A, AT, 0, 0) ; /* C = A+A' */ } else if (order == 2) { ATp = AT->p ; /* drop dense columns from AT */ ATi = AT->i ; for (p2 = 0, j = 0 ; j < m ; j++) { p = ATp [j] ; /* column j of AT starts here */ ATp [j] = p2 ; /* new column j starts here */ if (ATp [j+1] - p > dense) continue ; /* skip dense col j */ for ( ; p < ATp [j+1] ; p++) ATi [p2++] = ATi [p] ; } ATp [m] = p2 ; /* finalize AT */ A2 = cs_transpose (AT, 0) ; /* A2 = AT' */ C = A2 ? cs_multiply (AT, A2) : NULL ; /* C=A'*A with no dense rows */ cs_spfree (A2) ; } else { C = cs_multiply (AT, A) ; /* C=A'*A */ } cs_spfree (AT) ; if (!C) return (NULL) ; cs_fkeep (C, &cs_diag, NULL) ; /* drop diagonal entries */ Cp = C->p ; cnz = Cp [n] ; P = cs_malloc (n+1, sizeof (CS_INT)) ; /* allocate result */ W = cs_malloc (8*(n+1), sizeof (CS_INT)) ; /* get workspace */ t = cnz + cnz/5 + 2*n ; /* add elbow room to C */ if (!P || !W || !cs_sprealloc (C, t)) return (cs_idone (P, C, W, 0)) ; len = W ; nv = W + (n+1) ; next = W + 2*(n+1) ; head = W + 3*(n+1) ; elen = W + 4*(n+1) ; degree = W + 5*(n+1) ; w = W + 6*(n+1) ; hhead = W + 7*(n+1) ; last = P ; /* use P as workspace for last */ /* --- Initialize quotient graph ---------------------------------------- */ for (k = 0 ; k < n ; k++) len [k] = Cp [k+1] - Cp [k] ; len [n] = 0 ; nzmax = C->nzmax ; Ci = C->i ; for (i = 0 ; i <= n ; i++) { head [i] = -1 ; /* degree list i is empty */ last [i] = -1 ; next [i] = -1 ; hhead [i] = -1 ; /* hash list i is empty */ nv [i] = 1 ; /* node i is just one node */ w [i] = 1 ; /* node i is alive */ elen [i] = 0 ; /* Ek of node i is empty */ degree [i] = len [i] ; /* degree of node i */ } mark = cs_wclear (0, 0, w, n) ; /* clear w */ elen [n] = -2 ; /* n is a dead element */ Cp [n] = -1 ; /* n is a root of assembly tree */ w [n] = 0 ; /* n is a dead element */ /* --- Initialize degree lists ------------------------------------------ */ for (i = 0 ; i < n ; i++) { d = degree [i] ; if (d == 0) /* node i is empty */ { elen [i] = -2 ; /* element i is dead */ nel++ ; Cp [i] = -1 ; /* i is a root of assembly tree */ w [i] = 0 ; } else if (d > dense) /* node i is dense */ { nv [i] = 0 ; /* absorb i into element n */ elen [i] = -1 ; /* node i is dead */ nel++ ; Cp [i] = CS_FLIP (n) ; nv [n]++ ; } else { if (head [d] != -1) last [head [d]] = i ; next [i] = head [d] ; /* put node i in degree list d */ head [d] = i ; } } while (nel < n) /* while (selecting pivots) do */ { /* --- Select node of minimum approximate degree -------------------- */ for (k = -1 ; mindeg < n && (k = head [mindeg]) == -1 ; mindeg++) ; if (next [k] != -1) last [next [k]] = -1 ; head [mindeg] = next [k] ; /* remove k from degree list */ elenk = elen [k] ; /* elenk = |Ek| */ nvk = nv [k] ; /* # of nodes k represents */ nel += nvk ; /* nv[k] nodes of A eliminated */ /* --- Garbage collection ------------------------------------------- */ if (elenk > 0 && cnz + mindeg >= nzmax) { for (j = 0 ; j < n ; j++) { if ((p = Cp [j]) >= 0) /* j is a live node or element */ { Cp [j] = Ci [p] ; /* save first entry of object */ Ci [p] = CS_FLIP (j) ; /* first entry is now CS_FLIP(j) */ } } for (q = 0, p = 0 ; p < cnz ; ) /* scan all of memory */ { if ((j = CS_FLIP (Ci [p++])) >= 0) /* found object j */ { Ci [q] = Cp [j] ; /* restore first entry of object */ Cp [j] = q++ ; /* new pointer to object j */ for (k3 = 0 ; k3 < len [j]-1 ; k3++) Ci [q++] = Ci [p++] ; } } cnz = q ; /* Ci [cnz...nzmax-1] now free */ } /* --- Construct new element ---------------------------------------- */ dk = 0 ; nv [k] = -nvk ; /* flag k as in Lk */ p = Cp [k] ; pk1 = (elenk == 0) ? p : cnz ; /* do in place if elen[k] == 0 */ pk2 = pk1 ; for (k1 = 1 ; k1 <= elenk + 1 ; k1++) { if (k1 > elenk) { e = k ; /* search the nodes in k */ pj = p ; /* list of nodes starts at Ci[pj]*/ ln = len [k] - elenk ; /* length of list of nodes in k */ } else { e = Ci [p++] ; /* search the nodes in e */ pj = Cp [e] ; ln = len [e] ; /* length of list of nodes in e */ } for (k2 = 1 ; k2 <= ln ; k2++) { i = Ci [pj++] ; if ((nvi = nv [i]) <= 0) continue ; /* node i dead, or seen */ dk += nvi ; /* degree[Lk] += size of node i */ nv [i] = -nvi ; /* negate nv[i] to denote i in Lk*/ Ci [pk2++] = i ; /* place i in Lk */ if (next [i] != -1) last [next [i]] = last [i] ; if (last [i] != -1) /* remove i from degree list */ { next [last [i]] = next [i] ; } else { head [degree [i]] = next [i] ; } } if (e != k) { Cp [e] = CS_FLIP (k) ; /* absorb e into k */ w [e] = 0 ; /* e is now a dead element */ } } if (elenk != 0) cnz = pk2 ; /* Ci [cnz...nzmax] is free */ degree [k] = dk ; /* external degree of k - |Lk\i| */ Cp [k] = pk1 ; /* element k is in Ci[pk1..pk2-1] */ len [k] = pk2 - pk1 ; elen [k] = -2 ; /* k is now an element */ /* --- Find set differences ----------------------------------------- */ mark = cs_wclear (mark, lemax, w, n) ; /* clear w if necessary */ for (pk = pk1 ; pk < pk2 ; pk++) /* scan 1: find |Le\Lk| */ { i = Ci [pk] ; if ((eln = elen [i]) <= 0) continue ;/* skip if elen[i] empty */ nvi = -nv [i] ; /* nv [i] was negated */ wnvi = mark - nvi ; for (p = Cp [i] ; p <= Cp [i] + eln - 1 ; p++) /* scan Ei */ { e = Ci [p] ; if (w [e] >= mark) { w [e] -= nvi ; /* decrement |Le\Lk| */ } else if (w [e] != 0) /* ensure e is a live element */ { w [e] = degree [e] + wnvi ; /* 1st time e seen in scan 1 */ } } } /* --- Degree update ------------------------------------------------ */ for (pk = pk1 ; pk < pk2 ; pk++) /* scan2: degree update */ { i = Ci [pk] ; /* consider node i in Lk */ p1 = Cp [i] ; p2 = p1 + elen [i] - 1 ; pn = p1 ; for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) /* scan Ei */ { e = Ci [p] ; if (w [e] != 0) /* e is an unabsorbed element */ { dext = w [e] - mark ; /* dext = |Le\Lk| */ if (dext > 0) { d += dext ; /* sum up the set differences */ Ci [pn++] = e ; /* keep e in Ei */ h += e ; /* compute the hash of node i */ } else { Cp [e] = CS_FLIP (k) ; /* aggressive absorb. e->k */ w [e] = 0 ; /* e is a dead element */ } } } elen [i] = pn - p1 + 1 ; /* elen[i] = |Ei| */ p3 = pn ; p4 = p1 + len [i] ; for (p = p2 + 1 ; p < p4 ; p++) /* prune edges in Ai */ { j = Ci [p] ; if ((nvj = nv [j]) <= 0) continue ; /* node j dead or in Lk */ d += nvj ; /* degree(i) += |j| */ Ci [pn++] = j ; /* place j in node list of i */ h += j ; /* compute hash for node i */ } if (d == 0) /* check for mass elimination */ { Cp [i] = CS_FLIP (k) ; /* absorb i into k */ nvi = -nv [i] ; dk -= nvi ; /* |Lk| -= |i| */ nvk += nvi ; /* |k| += nv[i] */ nel += nvi ; nv [i] = 0 ; elen [i] = -1 ; /* node i is dead */ } else { degree [i] = CS_MIN (degree [i], d) ; /* update degree(i) */ Ci [pn] = Ci [p3] ; /* move first node to end */ Ci [p3] = Ci [p1] ; /* move 1st el. to end of Ei */ Ci [p1] = k ; /* add k as 1st element in of Ei */ len [i] = pn - p1 + 1 ; /* new len of adj. list of node i */ h %= n ; /* finalize hash of i */ next [i] = hhead [h] ; /* place i in hash bucket */ hhead [h] = i ; last [i] = h ; /* save hash of i in last[i] */ } } /* scan2 is done */ degree [k] = dk ; /* finalize |Lk| */ lemax = CS_MAX (lemax, dk) ; mark = cs_wclear (mark+lemax, lemax, w, n) ; /* clear w */ /* --- Supernode detection ------------------------------------------ */ for (pk = pk1 ; pk < pk2 ; pk++) { i = Ci [pk] ; if (nv [i] >= 0) continue ; /* skip if i is dead */ h = last [i] ; /* scan hash bucket of node i */ i = hhead [h] ; hhead [h] = -1 ; /* hash bucket will be empty */ for ( ; i != -1 && next [i] != -1 ; i = next [i], mark++) { ln = len [i] ; eln = elen [i] ; for (p = Cp [i]+1 ; p <= Cp [i] + ln-1 ; p++) w [Ci [p]] = mark; jlast = i ; for (j = next [i] ; j != -1 ; ) /* compare i with all j */ { ok = (len [j] == ln) && (elen [j] == eln) ; for (p = Cp [j] + 1 ; ok && p <= Cp [j] + ln - 1 ; p++) { if (w [Ci [p]] != mark) ok = 0 ; /* compare i and j*/ } if (ok) /* i and j are identical */ { Cp [j] = CS_FLIP (i) ; /* absorb j into i */ nv [i] += nv [j] ; nv [j] = 0 ; elen [j] = -1 ; /* node j is dead */ j = next [j] ; /* delete j from hash bucket */ next [jlast] = j ; } else { jlast = j ; /* j and i are different */ j = next [j] ; } } } } /* --- Finalize new element------------------------------------------ */ for (p = pk1, pk = pk1 ; pk < pk2 ; pk++) /* finalize Lk */ { i = Ci [pk] ; if ((nvi = -nv [i]) <= 0) continue ;/* skip if i is dead */ nv [i] = nvi ; /* restore nv[i] */ d = degree [i] + dk - nvi ; /* compute external degree(i) */ d = CS_MIN (d, n - nel - nvi) ; if (head [d] != -1) last [head [d]] = i ; next [i] = head [d] ; /* put i back in degree list */ last [i] = -1 ; head [d] = i ; mindeg = CS_MIN (mindeg, d) ; /* find new minimum degree */ degree [i] = d ; Ci [p++] = i ; /* place i in Lk */ } nv [k] = nvk ; /* # nodes absorbed into k */ if ((len [k] = p-pk1) == 0) /* length of adj list of element k*/ { Cp [k] = -1 ; /* k is a root of the tree */ w [k] = 0 ; /* k is now a dead element */ } if (elenk != 0) cnz = p ; /* free unused space in Lk */ } /* --- Postordering ----------------------------------------------------- */ for (i = 0 ; i < n ; i++) Cp [i] = CS_FLIP (Cp [i]) ;/* fix assembly tree */ for (j = 0 ; j <= n ; j++) head [j] = -1 ; for (j = n ; j >= 0 ; j--) /* place unordered nodes in lists */ { if (nv [j] > 0) continue ; /* skip if j is an element */ next [j] = head [Cp [j]] ; /* place j in list of its parent */ head [Cp [j]] = j ; } for (e = n ; e >= 0 ; e--) /* place elements in lists */ { if (nv [e] <= 0) continue ; /* skip unless e is an element */ if (Cp [e] != -1) { next [e] = head [Cp [e]] ; /* place e in list of its parent */ head [Cp [e]] = e ; } } for (k = 0, i = 0 ; i <= n ; i++) /* postorder the assembly tree */ { if (Cp [i] == -1) k = cs_tdfs (i, k, head, next, P, w) ; } return (cs_idone (P, C, W, 1)) ; }
void cs_join_post_mesh(const char *mesh_name, const cs_join_mesh_t *join_mesh) { if (_cs_join_post_initialized == true) return; int i, j; cs_lnum_t n_vertices; const char *name = NULL; int *ifield = NULL; double *dfield = NULL; cs_gnum_t *vertex_gnum = NULL; cs_real_t *vertex_coord = NULL; cs_lnum_t *parent_vtx_num = NULL; fvm_nodal_t *post_mesh = NULL; fvm_writer_t *writer = _cs_join_post_param.writer; const int local_rank = CS_MAX(cs_glob_rank_id, 0); const cs_lnum_t face_list_shift[2] = {0, join_mesh->n_faces}; const cs_lnum_t *face_vertex_idx[1] = {join_mesh->face_vtx_idx}; const cs_lnum_t *face_vertex_lst[1] = {join_mesh->face_vtx_lst}; /* Define an fvm_nodal_mesh_t structure from a cs_join_mesh_t structure */ /* Create an empty fvm_nodal_t structure. */ if (mesh_name == NULL) name = join_mesh->name; else name = mesh_name; post_mesh = fvm_nodal_create(name, 3); /* Define fvm_nodal_t structure */ fvm_nodal_from_desc_add_faces(post_mesh, join_mesh->n_faces, NULL, 1, face_list_shift, face_vertex_idx, face_vertex_lst, NULL, NULL); /* Define vertex_coord for fvm_nodal_set_shared_vertices() */ BFT_MALLOC(vertex_coord, 3*join_mesh->n_vertices, cs_real_t); for (i = 0; i < join_mesh->n_vertices; i++) for (j = 0; j < 3; j++) vertex_coord[3*i+j] = (join_mesh->vertices[i]).coord[j]; fvm_nodal_set_shared_vertices(post_mesh, vertex_coord); /* Order faces by increasing global number */ fvm_nodal_order_faces(post_mesh, join_mesh->face_gnum); fvm_nodal_init_io_num(post_mesh, join_mesh->face_gnum, 2); /* Order vertices by increasing global number */ BFT_MALLOC(vertex_gnum, join_mesh->n_vertices, cs_gnum_t); for (i = 0; i < join_mesh->n_vertices; i++) vertex_gnum[i] = (join_mesh->vertices[i]).gnum; fvm_nodal_order_vertices(post_mesh, vertex_gnum); fvm_nodal_init_io_num(post_mesh, vertex_gnum, 0); /* Write current mesh */ fvm_writer_export_nodal(writer, post_mesh); BFT_FREE(vertex_gnum); BFT_FREE(vertex_coord); /* Write rank associated to each face */ BFT_MALLOC(ifield, join_mesh->n_faces, int); for (i = 0; i < join_mesh->n_faces; i++) ifield[i] = local_rank; _post_elt_ifield(post_mesh, _("Rank"), 1, ifield); BFT_FREE(ifield); /* Write vertex tolerance */ n_vertices = fvm_nodal_get_n_entities(post_mesh, 0); BFT_MALLOC(parent_vtx_num, n_vertices, cs_lnum_t); BFT_MALLOC(dfield, n_vertices, double); fvm_nodal_get_parent_num(post_mesh, 0, parent_vtx_num); for (i = 0; i < n_vertices; i++) { cs_join_vertex_t data = join_mesh->vertices[parent_vtx_num[i]-1]; dfield[i] = data.tolerance; } _post_vtx_dfield(post_mesh, _("VtxTolerance"), 1, dfield); BFT_FREE(parent_vtx_num); BFT_FREE(dfield); post_mesh = fvm_nodal_destroy(post_mesh); }
void *cs_calloc(int n, size_t size) { return (calloc(CS_MAX (n,1), size)); }
void *cs_malloc(int n, size_t size) { return (malloc(CS_MAX (n,1) * size)); }
static void _get_global_tolerance(cs_mesh_t *mesh, cs_real_t *vtx_tolerance) { cs_int_t i, rank, vtx_id, block_size, shift; cs_gnum_t first_vtx_gnum; cs_lnum_t n_vertices = mesh->n_vertices; double *g_vtx_tolerance = NULL, *send_list = NULL, *recv_list = NULL; cs_int_t *send_count = NULL, *recv_count = NULL; cs_int_t *send_shift = NULL, *recv_shift = NULL; cs_gnum_t *send_glist = NULL, *recv_glist = NULL; cs_gnum_t n_g_vertices = mesh->n_g_vertices; const cs_gnum_t *io_gnum = mesh->global_vtx_num; MPI_Comm mpi_comm = cs_glob_mpi_comm; const int local_rank = CS_MAX(cs_glob_rank_id, 0); const int n_ranks = cs_glob_n_ranks; /* Define a fvm_io_num_t structure on vertices */ block_size = n_g_vertices / n_ranks; if (n_g_vertices % n_ranks > 0) block_size += 1; /* Count the number of vertices to send to each rank */ /* ------------------------------------------------- */ BFT_MALLOC(send_count, n_ranks, int); BFT_MALLOC(recv_count, n_ranks, int); BFT_MALLOC(send_shift, n_ranks + 1, int); BFT_MALLOC(recv_shift, n_ranks + 1, int); send_shift[0] = 0; recv_shift[0] = 0; for (rank = 0; rank < n_ranks; rank++) send_count[rank] = 0; for (i = 0; i < n_vertices; i++) { rank = (io_gnum[i] - 1)/block_size; send_count[rank] += 1; } MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, mpi_comm); for (rank = 0; rank < n_ranks; rank++) { send_shift[rank + 1] = send_shift[rank] + send_count[rank]; recv_shift[rank + 1] = recv_shift[rank] + recv_count[rank]; } assert(send_shift[n_ranks] == n_vertices); /* Send the global numbering for each vertex */ /* ----------------------------------------- */ BFT_MALLOC(send_glist, n_vertices, cs_gnum_t); BFT_MALLOC(recv_glist, recv_shift[n_ranks], cs_gnum_t); for (rank = 0; rank < n_ranks; rank++) send_count[rank] = 0; for (i = 0; i < n_vertices; i++) { rank = (io_gnum[i] - 1)/block_size; shift = send_shift[rank] + send_count[rank]; send_count[rank] += 1; send_glist[shift] = io_gnum[i]; } MPI_Alltoallv(send_glist, send_count, send_shift, CS_MPI_GNUM, recv_glist, recv_count, recv_shift, CS_MPI_GNUM, mpi_comm); /* Send the vertex tolerance for each vertex */ /* ----------------------------------------- */ BFT_MALLOC(send_list, n_vertices, double); BFT_MALLOC(recv_list, recv_shift[n_ranks], double); for (rank = 0; rank < n_ranks; rank++) send_count[rank] = 0; for (i = 0; i < n_vertices; i++) { rank = (io_gnum[i] - 1)/block_size; shift = send_shift[rank] + send_count[rank]; send_count[rank] += 1; send_list[shift] = vtx_tolerance[i]; } MPI_Alltoallv(send_list, send_count, send_shift, MPI_DOUBLE, recv_list, recv_count, recv_shift, MPI_DOUBLE, mpi_comm); /* Define the global tolerance array */ BFT_MALLOC(g_vtx_tolerance, block_size, double); for (i = 0; i < block_size; i++) g_vtx_tolerance[i] = DBL_MAX; first_vtx_gnum = block_size * local_rank + 1; for (i = 0; i < recv_shift[n_ranks]; i++) { vtx_id = recv_glist[i] - first_vtx_gnum; g_vtx_tolerance[vtx_id] = CS_MIN(g_vtx_tolerance[vtx_id], recv_list[i]); } /* Replace local vertex tolerance by the new computed global tolerance */ for (i = 0; i < recv_shift[n_ranks]; i++) { vtx_id = recv_glist[i] - first_vtx_gnum; recv_list[i] = g_vtx_tolerance[vtx_id]; } MPI_Alltoallv(recv_list, recv_count, recv_shift, MPI_DOUBLE, send_list, send_count, send_shift, MPI_DOUBLE, mpi_comm); for (rank = 0; rank < n_ranks; rank++) send_count[rank] = 0; for (i = 0; i < n_vertices; i++) { rank = (io_gnum[i] - 1)/block_size; shift = send_shift[rank] + send_count[rank]; send_count[rank] += 1; vtx_tolerance[i] = send_list[shift]; } /* Free memory */ BFT_FREE(recv_glist); BFT_FREE(send_glist); BFT_FREE(send_list); BFT_FREE(recv_list); BFT_FREE(recv_count); BFT_FREE(send_count); BFT_FREE(recv_shift); BFT_FREE(send_shift); BFT_FREE(g_vtx_tolerance); }
static void wd_config_changed (struct cs_fsm* fsm, int32_t event, void * data) { int res; size_t len; char *state; objdb_value_types_t type; char *str; uint64_t tmp_value; uint64_t next_timeout; struct resource *ref = (struct resource*)data; char str_copy[256]; next_timeout = ref->check_timeout; res = api->object_key_get_typed (ref->handle, "poll_period", (void**)&str, &len, &type); if (res == 0) { memcpy(str_copy, str, len); str_copy[len] = '\0'; if (str_to_uint64_t(str_copy, &tmp_value, WD_MIN_TIMEOUT_MS, WD_MAX_TIMEOUT_MS) == CS_OK) { log_printf (LOGSYS_LEVEL_DEBUG, "poll_period changing from:%"PRIu64" to %"PRIu64".", ref->check_timeout, tmp_value); /* * To easy in the transition between poll_period's we are going * to make the first timeout the bigger of the new and old value. * This is to give the monitoring system time to adjust. */ next_timeout = CS_MAX(tmp_value, ref->check_timeout); ref->check_timeout = tmp_value; } else { log_printf (LOGSYS_LEVEL_WARNING, "Could NOT use poll_period:%s ms for resource %s", str, ref->name); } } res = api->object_key_get_typed (ref->handle, "recovery", (void*)&ref->recovery, &len, &type); if (res != 0) { /* key does not exist. */ log_printf (LOGSYS_LEVEL_WARNING, "resource %s missing a recovery key.", ref->name); cs_fsm_state_set(&ref->fsm, WD_S_STOPPED, ref); return; } res = api->object_key_get_typed (ref->handle, "state", (void*)&state, &len, &type); if (res != 0) { /* key does not exist. */ log_printf (LOGSYS_LEVEL_WARNING, "resource %s missing a state key.", ref->name); cs_fsm_state_set(&ref->fsm, WD_S_STOPPED, ref); return; } if (ref->check_timer) { api->timer_delete(ref->check_timer); ref->check_timer = NULL; } if (strcmp(wd_stopped_str, state) == 0) { cs_fsm_state_set(&ref->fsm, WD_S_STOPPED, ref); } else { api->timer_add_duration(next_timeout * MILLI_2_NANO_SECONDS, ref, wd_resource_check_fn, &ref->check_timer); cs_fsm_state_set(&ref->fsm, WD_S_RUNNING, ref); } }
static double toc (double t) { double s = tic () ; return (CS_MAX (0, s-t)) ; }
/* * return 0 - fully configured * return -1 - partially configured */ static int32_t wd_resource_create (hdb_handle_t resource_obj) { int res; size_t len; char *state; objdb_value_types_t type; char period_str[32]; char str_copy[256]; char *str; uint64_t tmp_value; struct resource *ref = malloc (sizeof (struct resource)); ref->handle = resource_obj; ref->check_timeout = WD_DEFAULT_TIMEOUT_MS; ref->check_timer = NULL; api->object_name_get (resource_obj, ref->name, &len); ref->name[len] = '\0'; ref->fsm.name = ref->name; ref->fsm.table = wd_fsm_table; ref->fsm.entries = sizeof(wd_fsm_table) / sizeof(struct cs_fsm_entry); ref->fsm.curr_entry = 0; ref->fsm.curr_state = WD_S_STOPPED; ref->fsm.state_to_str = wd_res_state_to_str; ref->fsm.event_to_str = wd_res_event_to_str; api->object_priv_set (resource_obj, NULL); res = api->object_key_get_typed (resource_obj, "poll_period", (void**)&str, &len, &type); if (res != 0) { len = snprintf (period_str, 32, "%"PRIu64"", ref->check_timeout); api->object_key_create_typed (resource_obj, "poll_period", &period_str, len, OBJDB_VALUETYPE_STRING); } else { memcpy(str_copy, str, len); str_copy[len] = '\0'; if (str_to_uint64_t(str_copy, &tmp_value, WD_MIN_TIMEOUT_MS, WD_MAX_TIMEOUT_MS) == CS_OK) { ref->check_timeout = tmp_value; } else { log_printf (LOGSYS_LEVEL_WARNING, "Could NOT use poll_period:%s ms for resource %s", str, ref->name); } } api->object_track_start (resource_obj, OBJECT_TRACK_DEPTH_RECURSIVE, wd_key_changed, NULL, wd_object_destroyed, NULL, ref); res = api->object_key_get_typed (resource_obj, "recovery", (void*)&ref->recovery, &len, &type); if (res != 0) { /* key does not exist. */ log_printf (LOGSYS_LEVEL_WARNING, "resource %s missing a recovery key.", ref->name); return -1; } res = api->object_key_get_typed (resource_obj, "state", (void*)&state, &len, &type); if (res != 0) { /* key does not exist. */ log_printf (LOGSYS_LEVEL_WARNING, "resource %s missing a state key.", ref->name); return -1; } res = api->object_key_get_typed (resource_obj, "last_updated", (void*)&ref->last_updated, &len, &type); if (res != 0) { /* key does not exist. */ ref->last_updated = 0; } /* * delay the first check to give the monitor time to start working. */ tmp_value = CS_MAX(ref->check_timeout * 2, WD_DEFAULT_TIMEOUT_MS); api->timer_add_duration(tmp_value * MILLI_2_NANO_SECONDS, ref, wd_resource_check_fn, &ref->check_timer); cs_fsm_state_set(&ref->fsm, WD_S_RUNNING, ref); return 0; }