1 #include <../src/mat/impls/htool/htool.hpp> /*I "petscmat.h" I*/ 2 #include <petscblaslapack.h> 3 #include <set> 4 5 const char *const MatHtoolCompressorTypes[] = { "sympartialACA", "fullACA", "SVD" }; 6 const char *const MatHtoolClusteringTypes[] = { "PCARegular", "PCAGeometric", "BoundingBox1Regular", "BoundingBox1Geometric" }; 7 const char HtoolCitation[] = "@article{marchand2020two,\n" 8 " Author = {Marchand, Pierre and Claeys, Xavier and Jolivet, Pierre and Nataf, Fr\\'ed\\'eric and Tournier, Pierre-Henri},\n" 9 " Title = {Two-level preconditioning for $h$-version boundary element approximation of hypersingular operator with {GenEO}},\n" 10 " Year = {2020},\n" 11 " Publisher = {Elsevier},\n" 12 " Journal = {Numerische Mathematik},\n" 13 " Volume = {146},\n" 14 " Pages = {597--628},\n" 15 " Url = {https://github.com/htool-ddm/htool}\n" 16 "}\n"; 17 static PetscBool HtoolCite = PETSC_FALSE; 18 19 static PetscErrorCode MatGetDiagonal_Htool(Mat A,Vec v) 20 { 21 Mat_Htool *a = (Mat_Htool*)A->data; 22 PetscScalar *x; 23 PetscBool flg; 24 25 PetscFunctionBegin; 26 PetscCall(MatHasCongruentLayouts(A,&flg)); 27 PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only congruent layouts supported"); 28 PetscCall(VecGetArrayWrite(v,&x)); 29 a->hmatrix->copy_local_diagonal(x); 30 PetscCall(VecRestoreArrayWrite(v,&x)); 31 PetscCall(VecScale(v,a->s)); 32 PetscFunctionReturn(0); 33 } 34 35 static PetscErrorCode MatGetDiagonalBlock_Htool(Mat A,Mat *b) 36 { 37 Mat_Htool *a = (Mat_Htool*)A->data; 38 Mat B; 39 PetscScalar *ptr; 40 PetscBool flg; 41 42 PetscFunctionBegin; 43 PetscCall(MatHasCongruentLayouts(A,&flg)); 44 PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Only congruent layouts supported"); 45 PetscCall(PetscObjectQuery((PetscObject)A,"DiagonalBlock",(PetscObject*)&B)); /* same logic as in MatGetDiagonalBlock_MPIDense() */ 46 if (!B) { 47 PetscCall(MatCreateDense(PETSC_COMM_SELF,A->rmap->n,A->rmap->n,A->rmap->n,A->rmap->n,NULL,&B)); 48 PetscCall(MatDenseGetArrayWrite(B,&ptr)); 49 a->hmatrix->copy_local_diagonal_block(ptr); 50 PetscCall(MatDenseRestoreArrayWrite(B,&ptr)); 51 PetscCall(MatPropagateSymmetryOptions(A,B)); 52 PetscCall(MatScale(B,a->s)); 53 PetscCall(PetscObjectCompose((PetscObject)A,"DiagonalBlock",(PetscObject)B)); 54 *b = B; 55 PetscCall(MatDestroy(&B)); 56 } else *b = B; 57 PetscFunctionReturn(0); 58 } 59 60 static PetscErrorCode MatMult_Htool(Mat A,Vec x,Vec y) 61 { 62 Mat_Htool *a = (Mat_Htool*)A->data; 63 const PetscScalar *in; 64 PetscScalar *out; 65 66 PetscFunctionBegin; 67 PetscCall(VecGetArrayRead(x,&in)); 68 PetscCall(VecGetArrayWrite(y,&out)); 69 a->hmatrix->mvprod_local_to_local(in,out); 70 PetscCall(VecRestoreArrayRead(x,&in)); 71 PetscCall(VecRestoreArrayWrite(y,&out)); 72 PetscCall(VecScale(y,a->s)); 73 PetscFunctionReturn(0); 74 } 75 76 /* naive implementation of MatMultAdd() needed for FEM-BEM coupling via MATNEST */ 77 static PetscErrorCode MatMultAdd_Htool(Mat A,Vec v1,Vec v2,Vec v3) 78 { 79 Mat_Htool *a = (Mat_Htool*)A->data; 80 Vec tmp; 81 const PetscScalar scale = a->s; 82 83 PetscFunctionBegin; 84 PetscCall(VecDuplicate(v2,&tmp)); 85 PetscCall(VecCopy(v2,v3)); /* no-op in MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]) since VecCopy() checks for x == y */ 86 a->s = 1.0; /* set s to 1.0 since VecAXPY() may be used to scale the MatMult() output Vec */ 87 PetscCall(MatMult_Htool(A,v1,tmp)); 88 PetscCall(VecAXPY(v3,scale,tmp)); 89 PetscCall(VecDestroy(&tmp)); 90 a->s = scale; /* set s back to its original value */ 91 PetscFunctionReturn(0); 92 } 93 94 static PetscErrorCode MatMultTranspose_Htool(Mat A,Vec x,Vec y) 95 { 96 Mat_Htool *a = (Mat_Htool*)A->data; 97 const PetscScalar *in; 98 PetscScalar *out; 99 100 PetscFunctionBegin; 101 PetscCall(VecGetArrayRead(x,&in)); 102 PetscCall(VecGetArrayWrite(y,&out)); 103 a->hmatrix->mvprod_transp_local_to_local(in,out); 104 PetscCall(VecRestoreArrayRead(x,&in)); 105 PetscCall(VecRestoreArrayWrite(y,&out)); 106 PetscCall(VecScale(y,a->s)); 107 PetscFunctionReturn(0); 108 } 109 110 static PetscErrorCode MatIncreaseOverlap_Htool(Mat A,PetscInt is_max,IS is[],PetscInt ov) 111 { 112 std::set<PetscInt> set; 113 const PetscInt *idx; 114 PetscInt *oidx,size,bs[2]; 115 PetscMPIInt csize; 116 117 PetscFunctionBegin; 118 PetscCall(MatGetBlockSizes(A,bs,bs+1)); 119 if (bs[0] != bs[1]) bs[0] = 1; 120 for (PetscInt i=0; i<is_max; ++i) { 121 /* basic implementation that adds indices by shifting an IS by -ov, -ov+1..., -1, 1..., ov-1, ov */ 122 /* needed to avoid subdomain matrices to replicate A since it is dense */ 123 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is[i]),&csize)); 124 PetscCheck(csize == 1,PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported parallel IS"); 125 PetscCall(ISGetSize(is[i],&size)); 126 PetscCall(ISGetIndices(is[i],&idx)); 127 for (PetscInt j=0; j<size; ++j) { 128 set.insert(idx[j]); 129 for (PetscInt k=1; k<=ov; ++k) { /* for each layer of overlap */ 130 if (idx[j] - k >= 0) set.insert(idx[j] - k); /* do not insert negative indices */ 131 if (idx[j] + k < A->rmap->N && idx[j] + k < A->cmap->N) set.insert(idx[j] + k); /* do not insert indices greater than the dimension of A */ 132 } 133 } 134 PetscCall(ISRestoreIndices(is[i],&idx)); 135 PetscCall(ISDestroy(is+i)); 136 if (bs[0] > 1) { 137 for (std::set<PetscInt>::iterator it=set.cbegin(); it!=set.cend(); it++) { 138 std::vector<PetscInt> block(bs[0]); 139 std::iota(block.begin(),block.end(),(*it/bs[0])*bs[0]); 140 set.insert(block.cbegin(),block.cend()); 141 } 142 } 143 size = set.size(); /* size with overlap */ 144 PetscCall(PetscMalloc1(size,&oidx)); 145 for (const PetscInt j : set) *oidx++ = j; 146 oidx -= size; 147 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,size,oidx,PETSC_OWN_POINTER,is+i)); 148 } 149 PetscFunctionReturn(0); 150 } 151 152 static PetscErrorCode MatCreateSubMatrices_Htool(Mat A,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat *submat[]) 153 { 154 Mat_Htool *a = (Mat_Htool*)A->data; 155 Mat D,B,BT; 156 const PetscScalar *copy; 157 PetscScalar *ptr; 158 const PetscInt *idxr,*idxc,*it; 159 PetscInt nrow,m,i; 160 PetscBool flg; 161 162 PetscFunctionBegin; 163 if (scall != MAT_REUSE_MATRIX) { 164 PetscCall(PetscCalloc1(n,submat)); 165 } 166 for (i=0; i<n; ++i) { 167 PetscCall(ISGetLocalSize(irow[i],&nrow)); 168 PetscCall(ISGetLocalSize(icol[i],&m)); 169 PetscCall(ISGetIndices(irow[i],&idxr)); 170 PetscCall(ISGetIndices(icol[i],&idxc)); 171 if (scall != MAT_REUSE_MATRIX) { 172 PetscCall(MatCreateDense(PETSC_COMM_SELF,nrow,m,nrow,m,NULL,(*submat)+i)); 173 } 174 PetscCall(MatDenseGetArrayWrite((*submat)[i],&ptr)); 175 if (irow[i] == icol[i]) { /* same row and column IS? */ 176 PetscCall(MatHasCongruentLayouts(A,&flg)); 177 if (flg) { 178 PetscCall(ISSorted(irow[i],&flg)); 179 if (flg) { /* sorted IS? */ 180 it = std::lower_bound(idxr,idxr+nrow,A->rmap->rstart); 181 if (it != idxr+nrow && *it == A->rmap->rstart) { /* rmap->rstart in IS? */ 182 if (std::distance(idxr,it) + A->rmap->n <= nrow) { /* long enough IS to store the local diagonal block? */ 183 for (PetscInt j=0; j<A->rmap->n && flg; ++j) if (PetscUnlikely(it[j] != A->rmap->rstart+j)) flg = PETSC_FALSE; 184 if (flg) { /* complete local diagonal block in IS? */ 185 /* fast extraction when the local diagonal block is part of the submatrix, e.g., for PCASM or PCHPDDM 186 * [ B C E ] 187 * A = [ B D E ] 188 * [ B F E ] 189 */ 190 m = std::distance(idxr,it); /* shift of the coefficient (0,0) of block D from above */ 191 PetscCall(MatGetDiagonalBlock_Htool(A,&D)); 192 PetscCall(MatDenseGetArrayRead(D,©)); 193 for (PetscInt k=0; k<A->rmap->n; ++k) { 194 PetscCall(PetscArraycpy(ptr+(m+k)*nrow+m,copy+k*A->rmap->n,A->rmap->n)); /* block D from above */ 195 } 196 PetscCall(MatDenseRestoreArrayRead(D,©)); 197 if (m) { 198 a->wrapper->copy_submatrix(nrow,m,idxr,idxc,ptr); /* vertical block B from above */ 199 /* entry-wise assembly may be costly, so transpose already-computed entries when possible */ 200 if (A->symmetric == PETSC_BOOL3_TRUE || A->hermitian == PETSC_BOOL3_TRUE) { 201 PetscCall(MatCreateDense(PETSC_COMM_SELF,A->rmap->n,m,A->rmap->n,m,ptr+m,&B)); 202 PetscCall(MatDenseSetLDA(B,nrow)); 203 PetscCall(MatCreateDense(PETSC_COMM_SELF,m,A->rmap->n,m,A->rmap->n,ptr+m*nrow,&BT)); 204 PetscCall(MatDenseSetLDA(BT,nrow)); 205 if (A->hermitian == PETSC_BOOL3_TRUE && PetscDefined(USE_COMPLEX)) { 206 PetscCall(MatHermitianTranspose(B,MAT_REUSE_MATRIX,&BT)); 207 } else { 208 PetscCall(MatTranspose(B,MAT_REUSE_MATRIX,&BT)); 209 } 210 PetscCall(MatDestroy(&B)); 211 PetscCall(MatDestroy(&BT)); 212 } else { 213 for (PetscInt k=0; k<A->rmap->n; ++k) { /* block C from above */ 214 a->wrapper->copy_submatrix(m,1,idxr,idxc+m+k,ptr+(m+k)*nrow); 215 } 216 } 217 } 218 if (m+A->rmap->n != nrow) { 219 a->wrapper->copy_submatrix(nrow,std::distance(it+A->rmap->n,idxr+nrow),idxr,idxc+m+A->rmap->n,ptr+(m+A->rmap->n)*nrow); /* vertical block E from above */ 220 /* entry-wise assembly may be costly, so transpose already-computed entries when possible */ 221 if (A->symmetric == PETSC_BOOL3_TRUE || A->hermitian == PETSC_BOOL3_TRUE) { 222 PetscCall(MatCreateDense(PETSC_COMM_SELF,A->rmap->n,nrow-(m+A->rmap->n),A->rmap->n,nrow-(m+A->rmap->n),ptr+(m+A->rmap->n)*nrow+m,&B)); 223 PetscCall(MatDenseSetLDA(B,nrow)); 224 PetscCall(MatCreateDense(PETSC_COMM_SELF,nrow-(m+A->rmap->n),A->rmap->n,nrow-(m+A->rmap->n),A->rmap->n,ptr+m*nrow+m+A->rmap->n,&BT)); 225 PetscCall(MatDenseSetLDA(BT,nrow)); 226 if (A->hermitian == PETSC_BOOL3_TRUE && PetscDefined(USE_COMPLEX)) { 227 PetscCall(MatHermitianTranspose(B,MAT_REUSE_MATRIX,&BT)); 228 } else { 229 PetscCall(MatTranspose(B,MAT_REUSE_MATRIX,&BT)); 230 } 231 PetscCall(MatDestroy(&B)); 232 PetscCall(MatDestroy(&BT)); 233 } else { 234 for (PetscInt k=0; k<A->rmap->n; ++k) { /* block F from above */ 235 a->wrapper->copy_submatrix(std::distance(it+A->rmap->n,idxr+nrow),1,it+A->rmap->n,idxc+m+k,ptr+(m+k)*nrow+m+A->rmap->n); 236 } 237 } 238 } 239 } /* complete local diagonal block not in IS */ 240 } else flg = PETSC_FALSE; /* IS not long enough to store the local diagonal block */ 241 } else flg = PETSC_FALSE; /* rmap->rstart not in IS */ 242 } /* unsorted IS */ 243 } 244 } else flg = PETSC_FALSE; /* different row and column IS */ 245 if (!flg) a->wrapper->copy_submatrix(nrow,m,idxr,idxc,ptr); /* reassemble everything */ 246 PetscCall(ISRestoreIndices(irow[i],&idxr)); 247 PetscCall(ISRestoreIndices(icol[i],&idxc)); 248 PetscCall(MatDenseRestoreArrayWrite((*submat)[i],&ptr)); 249 PetscCall(MatScale((*submat)[i],a->s)); 250 } 251 PetscFunctionReturn(0); 252 } 253 254 static PetscErrorCode MatDestroy_Htool(Mat A) 255 { 256 Mat_Htool *a = (Mat_Htool*)A->data; 257 PetscContainer container; 258 MatHtoolKernelTranspose *kernelt; 259 260 PetscFunctionBegin; 261 PetscCall(PetscObjectChangeTypeName((PetscObject)A,NULL)); 262 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_seqdense_C",NULL)); 263 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_mpidense_C",NULL)); 264 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_seqdense_C",NULL)); 265 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_mpidense_C",NULL)); 266 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetHierarchicalMat_C",NULL)); 267 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolSetKernel_C",NULL)); 268 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationSource_C",NULL)); 269 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationTarget_C",NULL)); 270 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolUsePermutation_C",NULL)); 271 PetscCall(PetscObjectQuery((PetscObject)A,"KernelTranspose",(PetscObject*)&container)); 272 if (container) { /* created in MatTranspose_Htool() */ 273 PetscCall(PetscContainerGetPointer(container,(void**)&kernelt)); 274 PetscCall(MatDestroy(&kernelt->A)); 275 PetscCall(PetscFree(kernelt)); 276 PetscCall(PetscContainerDestroy(&container)); 277 PetscCall(PetscObjectCompose((PetscObject)A,"KernelTranspose",NULL)); 278 } 279 if (a->gcoords_source != a->gcoords_target) { 280 PetscCall(PetscFree(a->gcoords_source)); 281 } 282 PetscCall(PetscFree(a->gcoords_target)); 283 PetscCall(PetscFree2(a->work_source,a->work_target)); 284 delete a->wrapper; 285 delete a->hmatrix; 286 PetscCall(PetscFree(A->data)); 287 PetscFunctionReturn(0); 288 } 289 290 static PetscErrorCode MatView_Htool(Mat A,PetscViewer pv) 291 { 292 Mat_Htool *a = (Mat_Htool*)A->data; 293 PetscBool flg; 294 295 PetscFunctionBegin; 296 PetscCall(PetscObjectTypeCompare((PetscObject)pv,PETSCVIEWERASCII,&flg)); 297 if (flg) { 298 PetscCall(PetscViewerASCIIPrintf(pv,"symmetry: %c\n",a->hmatrix->get_symmetry_type())); 299 if (PetscAbsScalar(a->s-1.0) > PETSC_MACHINE_EPSILON) { 300 #if defined(PETSC_USE_COMPLEX) 301 PetscCall(PetscViewerASCIIPrintf(pv,"scaling: %g+%gi\n",(double)PetscRealPart(a->s),(double)PetscImaginaryPart(a->s))); 302 #else 303 PetscCall(PetscViewerASCIIPrintf(pv,"scaling: %g\n",(double)a->s)); 304 #endif 305 } 306 PetscCall(PetscViewerASCIIPrintf(pv,"minimum cluster size: %" PetscInt_FMT "\n",a->bs[0])); 307 PetscCall(PetscViewerASCIIPrintf(pv,"maximum block size: %" PetscInt_FMT "\n",a->bs[1])); 308 PetscCall(PetscViewerASCIIPrintf(pv,"epsilon: %g\n",(double)a->epsilon)); 309 PetscCall(PetscViewerASCIIPrintf(pv,"eta: %g\n",(double)a->eta)); 310 PetscCall(PetscViewerASCIIPrintf(pv,"minimum target depth: %" PetscInt_FMT "\n",a->depth[0])); 311 PetscCall(PetscViewerASCIIPrintf(pv,"minimum source depth: %" PetscInt_FMT "\n",a->depth[1])); 312 PetscCall(PetscViewerASCIIPrintf(pv,"compressor: %s\n",MatHtoolCompressorTypes[a->compressor])); 313 PetscCall(PetscViewerASCIIPrintf(pv,"clustering: %s\n",MatHtoolClusteringTypes[a->clustering])); 314 PetscCall(PetscViewerASCIIPrintf(pv,"compression ratio: %s\n",a->hmatrix->get_infos("Compression_ratio").c_str())); 315 PetscCall(PetscViewerASCIIPrintf(pv,"space saving: %s\n",a->hmatrix->get_infos("Space_saving").c_str())); 316 PetscCall(PetscViewerASCIIPrintf(pv,"number of dense (resp. low rank) matrices: %s (resp. %s)\n",a->hmatrix->get_infos("Number_of_dmat").c_str(),a->hmatrix->get_infos("Number_of_lrmat").c_str())); 317 PetscCall(PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) dense block sizes: (%s, %s, %s)\n",a->hmatrix->get_infos("Dense_block_size_min").c_str(),a->hmatrix->get_infos("Dense_block_size_mean").c_str(),a->hmatrix->get_infos("Dense_block_size_max").c_str())); 318 PetscCall(PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) low rank block sizes: (%s, %s, %s)\n",a->hmatrix->get_infos("Low_rank_block_size_min").c_str(),a->hmatrix->get_infos("Low_rank_block_size_mean").c_str(),a->hmatrix->get_infos("Low_rank_block_size_max").c_str())); 319 PetscCall(PetscViewerASCIIPrintf(pv,"(minimum, mean, maximum) ranks: (%s, %s, %s)\n",a->hmatrix->get_infos("Rank_min").c_str(),a->hmatrix->get_infos("Rank_mean").c_str(),a->hmatrix->get_infos("Rank_max").c_str())); 320 } 321 PetscFunctionReturn(0); 322 } 323 324 static PetscErrorCode MatScale_Htool(Mat A,PetscScalar s) 325 { 326 Mat_Htool *a = (Mat_Htool*)A->data; 327 328 PetscFunctionBegin; 329 a->s *= s; 330 PetscFunctionReturn(0); 331 } 332 333 /* naive implementation of MatGetRow() needed for MatConvert_Nest_AIJ() */ 334 static PetscErrorCode MatGetRow_Htool(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v) 335 { 336 Mat_Htool *a = (Mat_Htool*)A->data; 337 PetscInt *idxc; 338 PetscBLASInt one = 1,bn; 339 340 PetscFunctionBegin; 341 if (nz) *nz = A->cmap->N; 342 if (idx || v) { /* even if !idx, need to set idxc for htool::copy_submatrix() */ 343 PetscCall(PetscMalloc1(A->cmap->N,&idxc)); 344 for (PetscInt i=0; i<A->cmap->N; ++i) idxc[i] = i; 345 } 346 if (idx) *idx = idxc; 347 if (v) { 348 PetscCall(PetscMalloc1(A->cmap->N,v)); 349 if (a->wrapper) a->wrapper->copy_submatrix(1,A->cmap->N,&row,idxc,*v); 350 else reinterpret_cast<htool::VirtualGenerator<PetscScalar>*>(a->kernelctx)->copy_submatrix(1,A->cmap->N,&row,idxc,*v); 351 PetscCall(PetscBLASIntCast(A->cmap->N,&bn)); 352 PetscCallBLAS("BLASscal",BLASscal_(&bn,&a->s,*v,&one)); 353 } 354 if (!idx) { 355 PetscCall(PetscFree(idxc)); 356 } 357 PetscFunctionReturn(0); 358 } 359 360 static PetscErrorCode MatRestoreRow_Htool(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v) 361 { 362 PetscFunctionBegin; 363 if (nz) *nz = 0; 364 if (idx) { 365 PetscCall(PetscFree(*idx)); 366 } 367 if (v) { 368 PetscCall(PetscFree(*v)); 369 } 370 PetscFunctionReturn(0); 371 } 372 373 static PetscErrorCode MatSetFromOptions_Htool(PetscOptionItems *PetscOptionsObject,Mat A) 374 { 375 Mat_Htool *a = (Mat_Htool*)A->data; 376 PetscInt n; 377 PetscBool flg; 378 379 PetscFunctionBegin; 380 PetscOptionsHeadBegin(PetscOptionsObject,"Htool options"); 381 PetscCall(PetscOptionsInt("-mat_htool_min_cluster_size","Minimal leaf size in cluster tree",NULL,a->bs[0],a->bs,NULL)); 382 PetscCall(PetscOptionsInt("-mat_htool_max_block_size","Maximal number of coefficients in a dense block",NULL,a->bs[1],a->bs + 1,NULL)); 383 PetscCall(PetscOptionsReal("-mat_htool_epsilon","Relative error in Frobenius norm when approximating a block",NULL,a->epsilon,&a->epsilon,NULL)); 384 PetscCall(PetscOptionsReal("-mat_htool_eta","Admissibility condition tolerance",NULL,a->eta,&a->eta,NULL)); 385 PetscCall(PetscOptionsInt("-mat_htool_min_target_depth","Minimal cluster tree depth associated with the rows",NULL,a->depth[0],a->depth,NULL)); 386 PetscCall(PetscOptionsInt("-mat_htool_min_source_depth","Minimal cluster tree depth associated with the columns",NULL,a->depth[1],a->depth + 1,NULL)); 387 n = 0; 388 PetscCall(PetscOptionsEList("-mat_htool_compressor","Type of compression","MatHtoolCompressorType",MatHtoolCompressorTypes,PETSC_STATIC_ARRAY_LENGTH(MatHtoolCompressorTypes),MatHtoolCompressorTypes[MAT_HTOOL_COMPRESSOR_SYMPARTIAL_ACA],&n,&flg)); 389 if (flg) a->compressor = MatHtoolCompressorType(n); 390 n = 0; 391 PetscCall(PetscOptionsEList("-mat_htool_clustering","Type of clustering","MatHtoolClusteringType",MatHtoolClusteringTypes,PETSC_STATIC_ARRAY_LENGTH(MatHtoolClusteringTypes),MatHtoolClusteringTypes[MAT_HTOOL_CLUSTERING_PCA_REGULAR],&n,&flg)); 392 if (flg) a->clustering = MatHtoolClusteringType(n); 393 PetscOptionsHeadEnd(); 394 PetscFunctionReturn(0); 395 } 396 397 static PetscErrorCode MatAssemblyEnd_Htool(Mat A,MatAssemblyType type) 398 { 399 Mat_Htool *a = (Mat_Htool*)A->data; 400 const PetscInt *ranges; 401 PetscInt *offset; 402 PetscMPIInt size; 403 char S = PetscDefined(USE_COMPLEX) && A->hermitian == PETSC_BOOL3_TRUE ? 'H' : (A->symmetric == PETSC_BOOL3_TRUE ? 'S' : 'N'),uplo = S == 'N' ? 'N' : 'U'; 404 htool::VirtualGenerator<PetscScalar> *generator = nullptr; 405 std::shared_ptr<htool::VirtualCluster> t,s = nullptr; 406 std::shared_ptr<htool::VirtualLowRankGenerator<PetscScalar>> compressor = nullptr; 407 408 PetscFunctionBegin; 409 PetscCall(PetscCitationsRegister(HtoolCitation,&HtoolCite)); 410 delete a->wrapper; 411 delete a->hmatrix; 412 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size)); 413 PetscCall(PetscMalloc1(2*size,&offset)); 414 PetscCall(MatGetOwnershipRanges(A,&ranges)); 415 for (PetscInt i=0; i<size; ++i) { 416 offset[2*i] = ranges[i]; 417 offset[2*i+1] = ranges[i+1] - ranges[i]; 418 } 419 switch (a->clustering) { 420 case MAT_HTOOL_CLUSTERING_PCA_GEOMETRIC: 421 t = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::GeometricSplitting>>>(a->dim); 422 break; 423 case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_GEOMETRIC: 424 t = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::GeometricSplitting>>>(a->dim); 425 break; 426 case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_REGULAR: 427 t = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::RegularSplitting>>>(a->dim); 428 break; 429 default: 430 t = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::RegularSplitting>>>(a->dim); 431 } 432 t->set_minclustersize(a->bs[0]); 433 t->build(A->rmap->N,a->gcoords_target,offset); 434 if (a->kernel) a->wrapper = new WrapperHtool(A->rmap->N,A->cmap->N,a->dim,a->kernel,a->kernelctx); 435 else { 436 a->wrapper = NULL; 437 generator = reinterpret_cast<htool::VirtualGenerator<PetscScalar>*>(a->kernelctx); 438 } 439 if (a->gcoords_target != a->gcoords_source) { 440 PetscCall(MatGetOwnershipRangesColumn(A,&ranges)); 441 for (PetscInt i=0; i<size; ++i) { 442 offset[2*i] = ranges[i]; 443 offset[2*i+1] = ranges[i+1] - ranges[i]; 444 } 445 switch (a->clustering) { 446 case MAT_HTOOL_CLUSTERING_PCA_GEOMETRIC: 447 s = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::GeometricSplitting>>>(a->dim); 448 break; 449 case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_GEOMETRIC: 450 s = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::GeometricSplitting>>>(a->dim); 451 break; 452 case MAT_HTOOL_CLUSTERING_BOUNDING_BOX_1_REGULAR: 453 s = std::make_shared<htool::Cluster<htool::BoundingBox1<htool::SplittingTypes::RegularSplitting>>>(a->dim); 454 break; 455 default: 456 s = std::make_shared<htool::Cluster<htool::PCA<htool::SplittingTypes::RegularSplitting>>>(a->dim); 457 } 458 s->set_minclustersize(a->bs[0]); 459 s->build(A->cmap->N,a->gcoords_source,offset); 460 S = uplo = 'N'; 461 } 462 PetscCall(PetscFree(offset)); 463 switch (a->compressor) { 464 case MAT_HTOOL_COMPRESSOR_FULL_ACA: 465 compressor = std::make_shared<htool::fullACA<PetscScalar>>(); 466 break; 467 case MAT_HTOOL_COMPRESSOR_SVD: 468 compressor = std::make_shared<htool::SVD<PetscScalar>>(); 469 break; 470 default: 471 compressor = std::make_shared<htool::sympartialACA<PetscScalar>>(); 472 } 473 a->hmatrix = dynamic_cast<htool::VirtualHMatrix<PetscScalar>*>(new htool::HMatrix<PetscScalar>(t,s ? s : t,a->epsilon,a->eta,S,uplo)); 474 a->hmatrix->set_compression(compressor); 475 a->hmatrix->set_maxblocksize(a->bs[1]); 476 a->hmatrix->set_mintargetdepth(a->depth[0]); 477 a->hmatrix->set_minsourcedepth(a->depth[1]); 478 if (s) a->hmatrix->build(a->wrapper ? *a->wrapper : *generator,a->gcoords_target,a->gcoords_source); 479 else a->hmatrix->build(a->wrapper ? *a->wrapper : *generator,a->gcoords_target); 480 PetscFunctionReturn(0); 481 } 482 483 static PetscErrorCode MatProductNumeric_Htool(Mat C) 484 { 485 Mat_Product *product = C->product; 486 Mat_Htool *a = (Mat_Htool*)product->A->data; 487 const PetscScalar *in; 488 PetscScalar *out; 489 PetscInt N,lda; 490 491 PetscFunctionBegin; 492 MatCheckProduct(C,1); 493 PetscCall(MatGetSize(C,NULL,&N)); 494 PetscCall(MatDenseGetLDA(C,&lda)); 495 PetscCheck(lda == C->rmap->n,PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported leading dimension (%" PetscInt_FMT " != %" PetscInt_FMT ")",lda,C->rmap->n); 496 PetscCall(MatDenseGetArrayRead(product->B,&in)); 497 PetscCall(MatDenseGetArrayWrite(C,&out)); 498 switch (product->type) { 499 case MATPRODUCT_AB: 500 a->hmatrix->mvprod_local_to_local(in,out,N); 501 break; 502 case MATPRODUCT_AtB: 503 a->hmatrix->mvprod_transp_local_to_local(in,out,N); 504 break; 505 default: 506 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatProductType %s is not supported",MatProductTypes[product->type]); 507 } 508 PetscCall(MatDenseRestoreArrayWrite(C,&out)); 509 PetscCall(MatDenseRestoreArrayRead(product->B,&in)); 510 PetscCall(MatScale(C,a->s)); 511 PetscFunctionReturn(0); 512 } 513 514 static PetscErrorCode MatProductSymbolic_Htool(Mat C) 515 { 516 Mat_Product *product = C->product; 517 Mat A,B; 518 PetscBool flg; 519 520 PetscFunctionBegin; 521 MatCheckProduct(C,1); 522 A = product->A; 523 B = product->B; 524 PetscCall(PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQDENSE,MATMPIDENSE,"")); 525 PetscCheck(flg,PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"MatProduct_AB not supported for %s",((PetscObject)product->B)->type_name); 526 switch (product->type) { 527 case MATPRODUCT_AB: 528 if (C->rmap->n == PETSC_DECIDE || C->cmap->n == PETSC_DECIDE || C->rmap->N == PETSC_DECIDE || C->cmap->N == PETSC_DECIDE) { 529 PetscCall(MatSetSizes(C,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N)); 530 } 531 break; 532 case MATPRODUCT_AtB: 533 if (C->rmap->n == PETSC_DECIDE || C->cmap->n == PETSC_DECIDE || C->rmap->N == PETSC_DECIDE || C->cmap->N == PETSC_DECIDE) { 534 PetscCall(MatSetSizes(C,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N)); 535 } 536 break; 537 default: 538 SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[product->type]); 539 } 540 PetscCall(MatSetType(C,MATDENSE)); 541 PetscCall(MatSetUp(C)); 542 PetscCall(MatSetOption(C,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE)); 543 PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY)); 544 PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY)); 545 C->ops->productsymbolic = NULL; 546 C->ops->productnumeric = MatProductNumeric_Htool; 547 PetscFunctionReturn(0); 548 } 549 550 static PetscErrorCode MatProductSetFromOptions_Htool(Mat C) 551 { 552 PetscFunctionBegin; 553 MatCheckProduct(C,1); 554 if (C->product->type == MATPRODUCT_AB || C->product->type == MATPRODUCT_AtB) C->ops->productsymbolic = MatProductSymbolic_Htool; 555 PetscFunctionReturn(0); 556 } 557 558 static PetscErrorCode MatHtoolGetHierarchicalMat_Htool(Mat A,const htool::VirtualHMatrix<PetscScalar> **hmatrix) 559 { 560 Mat_Htool *a = (Mat_Htool*)A->data; 561 562 PetscFunctionBegin; 563 *hmatrix = a->hmatrix; 564 PetscFunctionReturn(0); 565 } 566 567 /*@C 568 MatHtoolGetHierarchicalMat - Retrieves the opaque pointer to a Htool virtual matrix stored in a MATHTOOL. 569 570 Input Parameter: 571 . A - hierarchical matrix 572 573 Output Parameter: 574 . hmatrix - opaque pointer to a Htool virtual matrix 575 576 Level: advanced 577 578 .seealso: `MATHTOOL` 579 @*/ 580 PETSC_EXTERN PetscErrorCode MatHtoolGetHierarchicalMat(Mat A,const htool::VirtualHMatrix<PetscScalar> **hmatrix) 581 { 582 PetscFunctionBegin; 583 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 584 PetscValidPointer(hmatrix,2); 585 PetscTryMethod(A,"MatHtoolGetHierarchicalMat_C",(Mat,const htool::VirtualHMatrix<PetscScalar>**),(A,hmatrix)); 586 PetscFunctionReturn(0); 587 } 588 589 static PetscErrorCode MatHtoolSetKernel_Htool(Mat A,MatHtoolKernel kernel,void *kernelctx) 590 { 591 Mat_Htool *a = (Mat_Htool*)A->data; 592 593 PetscFunctionBegin; 594 a->kernel = kernel; 595 a->kernelctx = kernelctx; 596 delete a->wrapper; 597 if (a->kernel) a->wrapper = new WrapperHtool(A->rmap->N,A->cmap->N,a->dim,a->kernel,a->kernelctx); 598 PetscFunctionReturn(0); 599 } 600 601 /*@C 602 MatHtoolSetKernel - Sets the kernel and context used for the assembly of a MATHTOOL. 603 604 Input Parameters: 605 + A - hierarchical matrix 606 . kernel - computational kernel (or NULL) 607 - kernelctx - kernel context (if kernel is NULL, the pointer must be of type htool::VirtualGenerator<PetscScalar>*) 608 609 Level: advanced 610 611 .seealso: `MATHTOOL`, `MatCreateHtoolFromKernel()` 612 @*/ 613 PETSC_EXTERN PetscErrorCode MatHtoolSetKernel(Mat A,MatHtoolKernel kernel,void *kernelctx) 614 { 615 PetscFunctionBegin; 616 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 617 if (!kernelctx) PetscValidFunction(kernel,2); 618 if (!kernel) PetscValidPointer(kernelctx,3); 619 PetscTryMethod(A,"MatHtoolSetKernel_C",(Mat,MatHtoolKernel,void*),(A,kernel,kernelctx)); 620 PetscFunctionReturn(0); 621 } 622 623 static PetscErrorCode MatHtoolGetPermutationSource_Htool(Mat A,IS* is) 624 { 625 Mat_Htool *a = (Mat_Htool*)A->data; 626 std::vector<PetscInt> source; 627 628 PetscFunctionBegin; 629 source = a->hmatrix->get_source_cluster()->get_local_perm(); 630 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A),source.size(),source.data(),PETSC_COPY_VALUES,is)); 631 PetscCall(ISSetPermutation(*is)); 632 PetscFunctionReturn(0); 633 } 634 635 /*@C 636 MatHtoolGetPermutationSource - Gets the permutation associated to the source cluster. 637 638 Input Parameter: 639 . A - hierarchical matrix 640 641 Output Parameter: 642 . is - permutation 643 644 Level: advanced 645 646 .seealso: `MATHTOOL`, `MatHtoolGetPermutationTarget()`, `MatHtoolUsePermutation()` 647 @*/ 648 PETSC_EXTERN PetscErrorCode MatHtoolGetPermutationSource(Mat A,IS* is) 649 { 650 PetscFunctionBegin; 651 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 652 if (!is) PetscValidPointer(is,2); 653 PetscTryMethod(A,"MatHtoolGetPermutationSource_C",(Mat,IS*),(A,is)); 654 PetscFunctionReturn(0); 655 } 656 657 static PetscErrorCode MatHtoolGetPermutationTarget_Htool(Mat A,IS* is) 658 { 659 Mat_Htool *a = (Mat_Htool*)A->data; 660 std::vector<PetscInt> target; 661 662 PetscFunctionBegin; 663 target = a->hmatrix->get_target_cluster()->get_local_perm(); 664 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A),target.size(),target.data(),PETSC_COPY_VALUES,is)); 665 PetscCall(ISSetPermutation(*is)); 666 PetscFunctionReturn(0); 667 } 668 669 /*@C 670 MatHtoolGetPermutationTarget - Gets the permutation associated to the target cluster. 671 672 Input Parameter: 673 . A - hierarchical matrix 674 675 Output Parameter: 676 . is - permutation 677 678 Level: advanced 679 680 .seealso: `MATHTOOL`, `MatHtoolGetPermutationSource()`, `MatHtoolUsePermutation()` 681 @*/ 682 PETSC_EXTERN PetscErrorCode MatHtoolGetPermutationTarget(Mat A,IS* is) 683 { 684 PetscFunctionBegin; 685 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 686 if (!is) PetscValidPointer(is,2); 687 PetscTryMethod(A,"MatHtoolGetPermutationTarget_C",(Mat,IS*),(A,is)); 688 PetscFunctionReturn(0); 689 } 690 691 static PetscErrorCode MatHtoolUsePermutation_Htool(Mat A,PetscBool use) 692 { 693 Mat_Htool *a = (Mat_Htool*)A->data; 694 695 PetscFunctionBegin; 696 a->hmatrix->set_use_permutation(use); 697 PetscFunctionReturn(0); 698 } 699 700 /*@C 701 MatHtoolUsePermutation - Sets whether MATHTOOL should permute input (resp. output) vectors following its internal source (resp. target) permutation. 702 703 Input Parameters: 704 + A - hierarchical matrix 705 - use - Boolean value 706 707 Level: advanced 708 709 .seealso: `MATHTOOL`, `MatHtoolGetPermutationSource()`, `MatHtoolGetPermutationTarget()` 710 @*/ 711 PETSC_EXTERN PetscErrorCode MatHtoolUsePermutation(Mat A,PetscBool use) 712 { 713 PetscFunctionBegin; 714 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 715 PetscValidLogicalCollectiveBool(A,use,2); 716 PetscTryMethod(A,"MatHtoolUsePermutation_C",(Mat,PetscBool),(A,use)); 717 PetscFunctionReturn(0); 718 } 719 720 static PetscErrorCode MatConvert_Htool_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B) 721 { 722 Mat C; 723 Mat_Htool *a = (Mat_Htool*)A->data; 724 PetscInt lda; 725 PetscScalar *array; 726 727 PetscFunctionBegin; 728 if (reuse == MAT_REUSE_MATRIX) { 729 C = *B; 730 PetscCheck(C->rmap->n == A->rmap->n && C->cmap->N == A->cmap->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Incompatible dimensions"); 731 PetscCall(MatDenseGetLDA(C,&lda)); 732 PetscCheck(lda == C->rmap->n,PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported leading dimension (%" PetscInt_FMT " != %" PetscInt_FMT ")",lda,C->rmap->n); 733 } else { 734 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C)); 735 PetscCall(MatSetSizes(C,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N)); 736 PetscCall(MatSetType(C,MATDENSE)); 737 PetscCall(MatSetUp(C)); 738 PetscCall(MatSetOption(C,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE)); 739 } 740 PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY)); 741 PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY)); 742 PetscCall(MatDenseGetArrayWrite(C,&array)); 743 a->hmatrix->copy_local_dense_perm(array); 744 PetscCall(MatDenseRestoreArrayWrite(C,&array)); 745 PetscCall(MatScale(C,a->s)); 746 if (reuse == MAT_INPLACE_MATRIX) { 747 PetscCall(MatHeaderReplace(A,&C)); 748 } else *B = C; 749 PetscFunctionReturn(0); 750 } 751 752 static PetscErrorCode GenEntriesTranspose(PetscInt sdim,PetscInt M,PetscInt N,const PetscInt *rows,const PetscInt *cols,PetscScalar *ptr,void *ctx) 753 { 754 MatHtoolKernelTranspose *generator = (MatHtoolKernelTranspose*)ctx; 755 PetscScalar *tmp; 756 757 PetscFunctionBegin; 758 generator->kernel(sdim,N,M,cols,rows,ptr,generator->kernelctx); 759 PetscCall(PetscMalloc1(M*N,&tmp)); 760 PetscCall(PetscArraycpy(tmp,ptr,M*N)); 761 for (PetscInt i=0; i<M; ++i) { 762 for (PetscInt j=0; j<N; ++j) ptr[i+j*M] = tmp[j+i*N]; 763 } 764 PetscCall(PetscFree(tmp)); 765 PetscFunctionReturn(0); 766 } 767 768 /* naive implementation which keeps a reference to the original Mat */ 769 static PetscErrorCode MatTranspose_Htool(Mat A,MatReuse reuse,Mat *B) 770 { 771 Mat C; 772 Mat_Htool *a = (Mat_Htool*)A->data,*c; 773 PetscInt M = A->rmap->N,N = A->cmap->N,m = A->rmap->n,n = A->cmap->n; 774 PetscContainer container; 775 MatHtoolKernelTranspose *kernelt; 776 777 PetscFunctionBegin; 778 PetscCheck(reuse != MAT_INPLACE_MATRIX,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatTranspose() with MAT_INPLACE_MATRIX not supported"); 779 if (reuse == MAT_INITIAL_MATRIX) { 780 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C)); 781 PetscCall(MatSetSizes(C,n,m,N,M)); 782 PetscCall(MatSetType(C,((PetscObject)A)->type_name)); 783 PetscCall(MatSetUp(C)); 784 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)C),&container)); 785 PetscCall(PetscNew(&kernelt)); 786 PetscCall(PetscContainerSetPointer(container,kernelt)); 787 PetscCall(PetscObjectCompose((PetscObject)C,"KernelTranspose",(PetscObject)container)); 788 } else { 789 C = *B; 790 PetscCall(PetscObjectQuery((PetscObject)C,"KernelTranspose",(PetscObject*)&container)); 791 PetscCheck(container,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call MatTranspose() with MAT_INITIAL_MATRIX first"); 792 PetscCall(PetscContainerGetPointer(container,(void**)&kernelt)); 793 } 794 c = (Mat_Htool*)C->data; 795 c->dim = a->dim; 796 c->s = a->s; 797 c->kernel = GenEntriesTranspose; 798 if (kernelt->A != A) { 799 PetscCall(MatDestroy(&kernelt->A)); 800 kernelt->A = A; 801 PetscCall(PetscObjectReference((PetscObject)A)); 802 } 803 kernelt->kernel = a->kernel; 804 kernelt->kernelctx = a->kernelctx; 805 c->kernelctx = kernelt; 806 if (reuse == MAT_INITIAL_MATRIX) { 807 PetscCall(PetscMalloc1(N*c->dim,&c->gcoords_target)); 808 PetscCall(PetscArraycpy(c->gcoords_target,a->gcoords_source,N*c->dim)); 809 if (a->gcoords_target != a->gcoords_source) { 810 PetscCall(PetscMalloc1(M*c->dim,&c->gcoords_source)); 811 PetscCall(PetscArraycpy(c->gcoords_source,a->gcoords_target,M*c->dim)); 812 } else c->gcoords_source = c->gcoords_target; 813 PetscCall(PetscCalloc2(M,&c->work_source,N,&c->work_target)); 814 } 815 PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY)); 816 PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY)); 817 if (reuse == MAT_INITIAL_MATRIX) *B = C; 818 PetscFunctionReturn(0); 819 } 820 821 /*@C 822 MatCreateHtoolFromKernel - Creates a MATHTOOL from a user-supplied kernel. 823 824 Input Parameters: 825 + comm - MPI communicator 826 . m - number of local rows (or PETSC_DECIDE to have calculated if M is given) 827 . n - number of local columns (or PETSC_DECIDE to have calculated if N is given) 828 . M - number of global rows (or PETSC_DETERMINE to have calculated if m is given) 829 . N - number of global columns (or PETSC_DETERMINE to have calculated if n is given) 830 . spacedim - dimension of the space coordinates 831 . coords_target - coordinates of the target 832 . coords_source - coordinates of the source 833 . kernel - computational kernel (or NULL) 834 - kernelctx - kernel context (if kernel is NULL, the pointer must be of type htool::VirtualGenerator<PetscScalar>*) 835 836 Output Parameter: 837 . B - matrix 838 839 Options Database Keys: 840 + -mat_htool_min_cluster_size <PetscInt> - minimal leaf size in cluster tree 841 . -mat_htool_max_block_size <PetscInt> - maximal number of coefficients in a dense block 842 . -mat_htool_epsilon <PetscReal> - relative error in Frobenius norm when approximating a block 843 . -mat_htool_eta <PetscReal> - admissibility condition tolerance 844 . -mat_htool_min_target_depth <PetscInt> - minimal cluster tree depth associated with the rows 845 . -mat_htool_min_source_depth <PetscInt> - minimal cluster tree depth associated with the columns 846 . -mat_htool_compressor <sympartialACA, fullACA, SVD> - type of compression 847 - -mat_htool_clustering <PCARegular, PCAGeometric, BounbingBox1Regular, BoundingBox1Geometric> - type of clustering 848 849 Level: intermediate 850 851 .seealso: `MatCreate()`, `MATHTOOL`, `PCSetCoordinates()`, `MatHtoolSetKernel()`, `MatHtoolCompressorType`, `MATH2OPUS`, `MatCreateH2OpusFromKernel()` 852 @*/ 853 PetscErrorCode MatCreateHtoolFromKernel(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscInt spacedim,const PetscReal coords_target[],const PetscReal coords_source[],MatHtoolKernel kernel,void *kernelctx,Mat *B) 854 { 855 Mat A; 856 Mat_Htool *a; 857 858 PetscFunctionBegin; 859 PetscCall(MatCreate(comm,&A)); 860 PetscValidLogicalCollectiveInt(A,spacedim,6); 861 PetscValidRealPointer(coords_target,7); 862 PetscValidRealPointer(coords_source,8); 863 if (!kernelctx) PetscValidFunction(kernel,9); 864 if (!kernel) PetscValidPointer(kernelctx,10); 865 PetscCall(MatSetSizes(A,m,n,M,N)); 866 PetscCall(MatSetType(A,MATHTOOL)); 867 PetscCall(MatSetUp(A)); 868 a = (Mat_Htool*)A->data; 869 a->dim = spacedim; 870 a->s = 1.0; 871 a->kernel = kernel; 872 a->kernelctx = kernelctx; 873 PetscCall(PetscCalloc1(A->rmap->N*spacedim,&a->gcoords_target)); 874 PetscCall(PetscArraycpy(a->gcoords_target+A->rmap->rstart*spacedim,coords_target,A->rmap->n*spacedim)); 875 PetscCall(MPIU_Allreduce(MPI_IN_PLACE,a->gcoords_target,A->rmap->N*spacedim,MPIU_REAL,MPI_SUM,PetscObjectComm((PetscObject)A))); /* global target coordinates */ 876 if (coords_target != coords_source) { 877 PetscCall(PetscCalloc1(A->cmap->N*spacedim,&a->gcoords_source)); 878 PetscCall(PetscArraycpy(a->gcoords_source+A->cmap->rstart*spacedim,coords_source,A->cmap->n*spacedim)); 879 PetscCall(MPIU_Allreduce(MPI_IN_PLACE,a->gcoords_source,A->cmap->N*spacedim,MPIU_REAL,MPI_SUM,PetscObjectComm((PetscObject)A))); /* global source coordinates */ 880 } else a->gcoords_source = a->gcoords_target; 881 PetscCall(PetscCalloc2(A->cmap->N,&a->work_source,A->rmap->N,&a->work_target)); 882 *B = A; 883 PetscFunctionReturn(0); 884 } 885 886 /*MC 887 MATHTOOL = "htool" - A matrix type for hierarchical matrices using the Htool package. 888 889 Use ./configure --download-htool to install PETSc to use Htool. 890 891 Options Database Keys: 892 . -mat_type htool - matrix type to "htool" during a call to MatSetFromOptions() 893 894 Level: beginner 895 896 .seealso: `MATH2OPUS`, `MATDENSE`, `MatCreateHtoolFromKernel()`, `MatHtoolSetKernel()` 897 M*/ 898 PETSC_EXTERN PetscErrorCode MatCreate_Htool(Mat A) 899 { 900 Mat_Htool *a; 901 902 PetscFunctionBegin; 903 PetscCall(PetscNewLog(A,&a)); 904 A->data = (void*)a; 905 PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATHTOOL)); 906 PetscCall(PetscMemzero(A->ops,sizeof(struct _MatOps))); 907 A->ops->getdiagonal = MatGetDiagonal_Htool; 908 A->ops->getdiagonalblock = MatGetDiagonalBlock_Htool; 909 A->ops->mult = MatMult_Htool; 910 A->ops->multadd = MatMultAdd_Htool; 911 A->ops->multtranspose = MatMultTranspose_Htool; 912 if (!PetscDefined(USE_COMPLEX)) A->ops->multhermitiantranspose = MatMultTranspose_Htool; 913 A->ops->increaseoverlap = MatIncreaseOverlap_Htool; 914 A->ops->createsubmatrices = MatCreateSubMatrices_Htool; 915 A->ops->transpose = MatTranspose_Htool; 916 A->ops->destroy = MatDestroy_Htool; 917 A->ops->view = MatView_Htool; 918 A->ops->setfromoptions = MatSetFromOptions_Htool; 919 A->ops->scale = MatScale_Htool; 920 A->ops->getrow = MatGetRow_Htool; 921 A->ops->restorerow = MatRestoreRow_Htool; 922 A->ops->assemblyend = MatAssemblyEnd_Htool; 923 a->dim = 0; 924 a->gcoords_target = NULL; 925 a->gcoords_source = NULL; 926 a->s = 1.0; 927 a->bs[0] = 10; 928 a->bs[1] = 1000000; 929 a->epsilon = PetscSqrtReal(PETSC_SMALL); 930 a->eta = 10.0; 931 a->depth[0] = 0; 932 a->depth[1] = 0; 933 a->compressor = MAT_HTOOL_COMPRESSOR_SYMPARTIAL_ACA; 934 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_seqdense_C",MatProductSetFromOptions_Htool)); 935 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_htool_mpidense_C",MatProductSetFromOptions_Htool)); 936 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_seqdense_C",MatConvert_Htool_Dense)); 937 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_htool_mpidense_C",MatConvert_Htool_Dense)); 938 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetHierarchicalMat_C",MatHtoolGetHierarchicalMat_Htool)); 939 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolSetKernel_C",MatHtoolSetKernel_Htool)); 940 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationSource_C",MatHtoolGetPermutationSource_Htool)); 941 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolGetPermutationTarget_C",MatHtoolGetPermutationTarget_Htool)); 942 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatHtoolUsePermutation_C",MatHtoolUsePermutation_Htool)); 943 PetscFunctionReturn(0); 944 } 945