1 /// @file 2 /// MatCEED implementation 3 4 #include <ceed.h> 5 #include <ceed/backend.h> 6 #include <mat-ceed-impl.h> 7 #include <mat-ceed.h> 8 #include <petsc-ceed-utils.h> 9 #include <petsc-ceed.h> 10 #include <petscdm.h> 11 #include <petscmat.h> 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 PetscClassId MATCEED_CLASSID; 18 PetscLogEvent MATCEED_MULT, MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE, MATCEED_MULT_TRANSPOSE_CEEDOP, MATCEED_ASSEMBLE_DIAGONAL, 19 MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, MATCEED_SETUP_PBDIAGONAL, MATCEED_SETUP_PBDIAGONAL_CEEDOP, MATCEED_ASSEMBLE_PBDIAGONAL, 20 MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, MATCEED_SETUP_FULL, MATCEED_SETUP_FULL_CEEDOP, MATCEED_ASSEMBLE_FULL, MATCEED_ASSEMBLE_FULL_CEEDOP; 21 22 /** 23 @brief Register MATCEED log events. 24 25 Not collective across MPI processes. 26 27 @return An error code: 0 - success, otherwise - failure 28 **/ 29 static PetscErrorCode MatCeedRegisterLogEvents() { 30 static PetscBool registered = PETSC_FALSE; 31 32 PetscFunctionBeginUser; 33 if (registered) PetscFunctionReturn(PETSC_SUCCESS); 34 PetscCall(PetscClassIdRegister("MatCEED", &MATCEED_CLASSID)); 35 PetscCall(PetscLogEventRegister("MatCEEDMul", MATCEED_CLASSID, &MATCEED_MULT)); 36 PetscCall(PetscLogEventRegister("MatCEEDMulCeed", MATCEED_CLASSID, &MATCEED_MULT_CEEDOP)); 37 PetscCall(PetscLogEventRegister("MatCEEDMulT", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE)); 38 PetscCall(PetscLogEventRegister("MatCEEDMulTCeed", MATCEED_CLASSID, &MATCEED_MULT_TRANSPOSE_CEEDOP)); 39 PetscCall(PetscLogEventRegister("MatCEEDAsmDiag", MATCEED_CLASSID, &MATCEED_ASSEMBLE_DIAGONAL)); 40 PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSU", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL)); 41 PetscCall(PetscLogEventRegister("MatCEEDAsmPBDSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_PBDIAGONAL_CEEDOP)); 42 PetscCall(PetscLogEventRegister("MatCEEDAsmPBD", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL)); 43 PetscCall(PetscLogEventRegister("MatCEEDAsmPBDCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP)); 44 PetscCall(PetscLogEventRegister("MatCEEDAsmSU", MATCEED_CLASSID, &MATCEED_SETUP_FULL)); 45 PetscCall(PetscLogEventRegister("MatCEEDAsmSUCeed", MATCEED_CLASSID, &MATCEED_SETUP_FULL_CEEDOP)); 46 PetscCall(PetscLogEventRegister("MatCEEDAsm", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL)); 47 PetscCall(PetscLogEventRegister("MatCEEDAsmCeed", MATCEED_CLASSID, &MATCEED_ASSEMBLE_FULL_CEEDOP)); 48 registered = PETSC_TRUE; 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 52 /** 53 @brief Assemble the point block diagonal of a `MATCEED` into a `MATAIJ` or similar. 54 The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`. 55 The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail. 56 57 Collective across MPI processes. 58 59 @param[in] mat_ceed `MATCEED` to assemble 60 @param[in,out] mat_coo `MATAIJ` or similar to assemble into 61 62 @return An error code: 0 - success, otherwise - failure 63 **/ 64 static PetscErrorCode MatCeedAssemblePointBlockDiagonalCOO(Mat mat_ceed, Mat mat_coo) { 65 MatCeedContext ctx; 66 67 PetscFunctionBeginUser; 68 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 69 70 // Check if COO pattern set 71 { 72 PetscInt index = -1; 73 74 for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) { 75 if (ctx->mats_assembled_pbd[i] == mat_coo) index = i; 76 } 77 if (index == -1) { 78 PetscInt *rows_petsc = NULL, *cols_petsc = NULL; 79 CeedInt *rows_ceed, *cols_ceed; 80 PetscCount num_entries; 81 PetscLogStage stage_amg_setup; 82 83 // -- Assemble sparsity pattern if mat hasn't been assembled before 84 PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup)); 85 if (stage_amg_setup == -1) { 86 PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup)); 87 } 88 PetscCall(PetscLogStagePush(stage_amg_setup)); 89 PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL)); 90 PetscCall(PetscLogEventBegin(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 91 PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonalSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed)); 92 PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 93 PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc)); 94 PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc)); 95 PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc)); 96 free(rows_petsc); 97 free(cols_petsc); 98 if (!ctx->coo_values_pbd) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_pbd)); 99 PetscCall(PetscRealloc(++ctx->num_mats_assembled_pbd * sizeof(Mat), &ctx->mats_assembled_pbd)); 100 ctx->mats_assembled_pbd[ctx->num_mats_assembled_pbd - 1] = mat_coo; 101 PetscCall(PetscLogEventEnd(MATCEED_SETUP_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL)); 102 PetscCall(PetscLogStagePop()); 103 } 104 } 105 106 // Assemble mat_ceed 107 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL)); 108 PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY)); 109 { 110 const CeedScalar *values; 111 MatType mat_type; 112 CeedMemType mem_type = CEED_MEM_HOST; 113 PetscBool is_spd, is_spd_known; 114 115 PetscCall(MatGetType(mat_coo, &mat_type)); 116 if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE; 117 else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE; 118 else mem_type = CEED_MEM_HOST; 119 120 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 121 PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemblePointBlockDiagonal(ctx->op_mult, ctx->coo_values_pbd, CEED_REQUEST_IMMEDIATE)); 122 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 123 PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_pbd, mem_type, &values)); 124 PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES)); 125 PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd)); 126 if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd)); 127 PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_pbd, &values)); 128 } 129 PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY)); 130 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_PBDIAGONAL, mat_ceed, mat_coo, NULL, NULL)); 131 PetscFunctionReturn(PETSC_SUCCESS); 132 } 133 134 /** 135 @brief Assemble inner `Mat` for diagonal `PC` operations 136 137 Collective across MPI processes. 138 139 @param[in] mat_ceed `MATCEED` to invert 140 @param[in] use_ceed_pbd Boolean flag to use libCEED PBD assembly 141 @param[out] mat_inner Inner `Mat` for diagonal operations 142 143 @return An error code: 0 - success, otherwise - failure 144 **/ 145 static PetscErrorCode MatCeedAssembleInnerBlockDiagonalMat(Mat mat_ceed, PetscBool use_ceed_pbd, Mat *mat_inner) { 146 MatCeedContext ctx; 147 148 PetscFunctionBeginUser; 149 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 150 if (use_ceed_pbd) { 151 // Check if COO pattern set 152 if (!ctx->mat_assembled_pbd_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_pbd_internal)); 153 154 // Assemble mat_assembled_full_internal 155 PetscCall(MatCeedAssemblePointBlockDiagonalCOO(mat_ceed, ctx->mat_assembled_pbd_internal)); 156 if (mat_inner) *mat_inner = ctx->mat_assembled_pbd_internal; 157 } else { 158 // Check if COO pattern set 159 if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal)); 160 161 // Assemble mat_assembled_full_internal 162 PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal)); 163 if (mat_inner) *mat_inner = ctx->mat_assembled_full_internal; 164 } 165 PetscFunctionReturn(PETSC_SUCCESS); 166 } 167 168 /** 169 @brief Get `MATCEED` variable block diagonal for Jacobi. 170 171 Collective across MPI processes. 172 173 @param[in] mat_ceed `MATCEED` to invert 174 @param[out] mat_vblock The variable diagonal block matrix 175 176 @return An error code: 0 - success, otherwise - failure 177 **/ 178 static PetscErrorCode MatGetVariableBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_vblock) { 179 MatCeedContext ctx; 180 181 PetscFunctionBeginUser; 182 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 183 184 // Assemble inner mat if needed 185 PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_vpbd_valid, mat_vblock)); 186 PetscCall(PetscObjectReference((PetscObject)*mat_vblock)); 187 PetscFunctionReturn(PETSC_SUCCESS); 188 } 189 190 /** 191 @brief Get `MATCEED` block diagonal for Jacobi. 192 193 Collective across MPI processes. 194 195 @param[in] mat_ceed `MATCEED` to invert 196 @param[out] mat_block The variable diagonal block matrix 197 198 @return An error code: 0 - success, otherwise - failure 199 **/ 200 static PetscErrorCode MatGetBlockDiagonal_Ceed(Mat mat_ceed, Mat *mat_block) { 201 MatCeedContext ctx; 202 203 PetscFunctionBeginUser; 204 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 205 206 // Assemble inner mat if needed 207 PetscCall(MatCeedAssembleInnerBlockDiagonalMat(mat_ceed, ctx->is_ceed_pbd_valid, mat_block)); 208 PetscCall(PetscObjectReference((PetscObject)*mat_block)); 209 PetscFunctionReturn(PETSC_SUCCESS); 210 } 211 212 /** 213 @brief Get on-process diagonal block of `MATCEED` 214 215 This is a block per-process of the diagonal of the global matrix. 216 This is NOT the diagonal blocks associated with the block size of the matrix (i.e. `MatSetBlockSize()` has no effect on this function). 217 218 Collective across MPI processes. 219 220 @param[in] mat_ceed `MATCEED` to invert 221 @param[out] mat_block The diagonal block matrix 222 223 @return An error code: 0 - success, otherwise - failure 224 **/ 225 static PetscErrorCode MatGetDiagonalBlock_Ceed(Mat mat_ceed, Mat *mat_block) { 226 MatCeedContext ctx; 227 228 PetscFunctionBeginUser; 229 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 230 231 // Check if COO pattern set 232 if (!ctx->mat_assembled_full_internal) PetscCall(MatCeedCreateMatCOO(mat_ceed, &ctx->mat_assembled_full_internal)); 233 234 // Assemble mat_assembled_full_internal 235 PetscCall(MatCeedAssembleCOO(mat_ceed, ctx->mat_assembled_full_internal)); 236 237 // Get diagonal block 238 PetscCall(MatGetDiagonalBlock(ctx->mat_assembled_full_internal, mat_block)); 239 PetscFunctionReturn(PETSC_SUCCESS); 240 } 241 242 /** 243 @brief View `MATCEED`. 244 245 Collective across MPI processes. 246 247 @param[in] mat_ceed `MATCEED` to view 248 @param[in] viewer The visualization context 249 250 @return An error code: 0 - success, otherwise - failure 251 **/ 252 static PetscErrorCode MatView_Ceed(Mat mat_ceed, PetscViewer viewer) { 253 PetscBool is_ascii; 254 PetscViewerFormat format; 255 PetscMPIInt size, rank; 256 MatCeedContext ctx; 257 258 PetscFunctionBeginUser; 259 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 260 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 261 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat_ceed), &viewer)); 262 263 PetscCall(PetscViewerGetFormat(viewer, &format)); 264 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat_ceed), &size)); 265 if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS); 266 267 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat_ceed), &rank)); 268 if (rank != 0) PetscFunctionReturn(PETSC_SUCCESS); 269 270 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &is_ascii)); 271 { 272 PetscBool is_detailed = format == PETSC_VIEWER_ASCII_INFO_DETAIL; 273 char rank_string[16] = {'\0'}; 274 FILE *file; 275 276 PetscCall(PetscViewerASCIIPrintf(viewer, "MatCEED:\n")); 277 PetscCall(PetscViewerASCIIPushTab(viewer)); // MatCEED 278 PetscCall(PetscViewerASCIIPrintf(viewer, "Default COO MatType: %s\n", ctx->coo_mat_type)); 279 PetscCall(PetscSNPrintf(rank_string, 16, "on Rank %d", rank)); 280 PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator Apply %s:\n", is_detailed ? rank_string : "Summary")); 281 PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED PB Diagonal Assembly: %s\n", ctx->is_ceed_pbd_valid ? "True" : "False")); 282 PetscCall(PetscViewerASCIIPrintf(viewer, "libCEED VPB Diagonal Assembly: %s\n", ctx->is_ceed_vpbd_valid ? "True" : "False")); 283 PetscCall(PetscViewerASCIIGetPointer(viewer, &file)); 284 PetscCall(PetscViewerASCIIPushTab(viewer)); // CeedOperator 285 if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult, file)); 286 else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult, file)); 287 PetscCall(PetscViewerASCIIPopTab(viewer)); // CeedOperator 288 if (ctx->op_mult_transpose) { 289 PetscCall(PetscViewerASCIIPrintf(viewer, "CeedOperator ApplyTranspose %s:\n", is_detailed ? rank_string : "Summary")); 290 PetscCall(PetscViewerASCIIPushTab(viewer)); // CeedOperator 291 if (is_detailed) PetscCallCeed(ctx->ceed, CeedOperatorView(ctx->op_mult_transpose, file)); 292 else PetscCallCeed(ctx->ceed, CeedOperatorViewTerse(ctx->op_mult_transpose, file)); 293 PetscCall(PetscViewerASCIIPopTab(viewer)); // CeedOperator 294 } 295 PetscCall(PetscViewerASCIIPopTab(viewer)); // MatCEED 296 } 297 PetscFunctionReturn(PETSC_SUCCESS); 298 } 299 300 // ----------------------------------------------------------------------------- 301 // MatCeed 302 // ----------------------------------------------------------------------------- 303 304 /** 305 @brief Create PETSc `Mat` from libCEED operators. 306 307 Collective across MPI processes. 308 309 @param[in] dm_x Input `DM` 310 @param[in] dm_y Output `DM` 311 @param[in] op_mult `CeedOperator` for forward evaluation 312 @param[in] op_mult_transpose `CeedOperator` for transpose evaluation 313 @param[out] mat New MatCeed 314 315 @return An error code: 0 - success, otherwise - failure 316 **/ 317 PetscErrorCode MatCreateCeed(DM dm_x, DM dm_y, CeedOperator op_mult, CeedOperator op_mult_transpose, Mat *mat) { 318 PetscInt X_l_size, X_g_size, Y_l_size, Y_g_size; 319 VecType vec_type; 320 MatCeedContext ctx; 321 322 PetscFunctionBeginUser; 323 PetscCall(MatCeedRegisterLogEvents()); 324 325 // Collect context data 326 PetscCall(DMGetVecType(dm_x, &vec_type)); 327 { 328 Vec X; 329 330 PetscCall(DMGetGlobalVector(dm_x, &X)); 331 PetscCall(VecGetSize(X, &X_g_size)); 332 PetscCall(VecGetLocalSize(X, &X_l_size)); 333 PetscCall(DMRestoreGlobalVector(dm_x, &X)); 334 } 335 if (dm_y) { 336 Vec Y; 337 338 PetscCall(DMGetGlobalVector(dm_y, &Y)); 339 PetscCall(VecGetSize(Y, &Y_g_size)); 340 PetscCall(VecGetLocalSize(Y, &Y_l_size)); 341 PetscCall(DMRestoreGlobalVector(dm_y, &Y)); 342 } else { 343 dm_y = dm_x; 344 Y_g_size = X_g_size; 345 Y_l_size = X_l_size; 346 } 347 348 // Create context 349 { 350 Vec X_loc, Y_loc_transpose = NULL; 351 352 PetscCall(DMCreateLocalVector(dm_x, &X_loc)); 353 PetscCall(VecZeroEntries(X_loc)); 354 if (op_mult_transpose) { 355 PetscCall(DMCreateLocalVector(dm_y, &Y_loc_transpose)); 356 PetscCall(VecZeroEntries(Y_loc_transpose)); 357 } 358 PetscCall(MatCeedContextCreate(dm_x, dm_y, X_loc, Y_loc_transpose, op_mult, op_mult_transpose, MATCEED_MULT, MATCEED_MULT_TRANSPOSE, 359 MATCEED_MULT_CEEDOP, MATCEED_MULT_TRANSPOSE_CEEDOP, &ctx)); 360 PetscCall(VecDestroy(&X_loc)); 361 PetscCall(VecDestroy(&Y_loc_transpose)); 362 } 363 364 // Create mat 365 PetscCall(MatCreateShell(PetscObjectComm((PetscObject)dm_x), Y_l_size, X_l_size, Y_g_size, X_g_size, ctx, mat)); 366 PetscCall(PetscObjectChangeTypeName((PetscObject)*mat, MATCEED)); 367 // -- Set block and variable block sizes 368 if (dm_x == dm_y) { 369 MatType dm_mat_type, dm_mat_type_copy; 370 Mat temp_mat; 371 372 PetscCall(DMGetMatType(dm_x, &dm_mat_type)); 373 PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy)); 374 PetscCall(DMSetMatType(dm_x, MATAIJ)); 375 PetscCall(DMCreateMatrix(dm_x, &temp_mat)); 376 PetscCall(DMSetMatType(dm_x, dm_mat_type_copy)); 377 PetscCall(PetscFree(dm_mat_type_copy)); 378 379 { 380 PetscInt block_size, num_blocks, max_vblock_size = PETSC_INT_MAX; 381 const PetscInt *vblock_sizes; 382 383 // -- Get block sizes 384 PetscCall(MatGetBlockSize(temp_mat, &block_size)); 385 PetscCall(MatGetVariableBlockSizes(temp_mat, &num_blocks, &vblock_sizes)); 386 { 387 PetscInt local_min_max[2] = {0}, global_min_max[2] = {0, PETSC_INT_MAX}; 388 389 for (PetscInt i = 0; i < num_blocks; i++) local_min_max[1] = PetscMax(local_min_max[1], vblock_sizes[i]); 390 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_min_max, global_min_max)); 391 max_vblock_size = global_min_max[1]; 392 } 393 394 // -- Copy block sizes 395 if (block_size > 1) PetscCall(MatSetBlockSize(*mat, block_size)); 396 if (num_blocks) PetscCall(MatSetVariableBlockSizes(*mat, num_blocks, (PetscInt *)vblock_sizes)); 397 398 // -- Check libCEED compatibility 399 { 400 bool is_composite; 401 402 ctx->is_ceed_pbd_valid = PETSC_TRUE; 403 ctx->is_ceed_vpbd_valid = PETSC_TRUE; 404 PetscCallCeed(ctx->ceed, CeedOperatorIsComposite(op_mult, &is_composite)); 405 if (is_composite) { 406 CeedInt num_sub_operators; 407 CeedOperator *sub_operators; 408 409 PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetNumSub(op_mult, &num_sub_operators)); 410 PetscCallCeed(ctx->ceed, CeedCompositeOperatorGetSubList(op_mult, &sub_operators)); 411 for (CeedInt i = 0; i < num_sub_operators; i++) { 412 CeedInt num_bases, num_comp; 413 CeedBasis *active_bases; 414 CeedOperatorAssemblyData assembly_data; 415 416 PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(sub_operators[i], &assembly_data)); 417 PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL)); 418 PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp)); 419 if (num_bases > 1) { 420 ctx->is_ceed_pbd_valid = PETSC_FALSE; 421 ctx->is_ceed_vpbd_valid = PETSC_FALSE; 422 } 423 if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE; 424 if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE; 425 } 426 } else { 427 // LCOV_EXCL_START 428 CeedInt num_bases, num_comp; 429 CeedBasis *active_bases; 430 CeedOperatorAssemblyData assembly_data; 431 432 PetscCallCeed(ctx->ceed, CeedOperatorGetOperatorAssemblyData(op_mult, &assembly_data)); 433 PetscCallCeed(ctx->ceed, CeedOperatorAssemblyDataGetBases(assembly_data, &num_bases, &active_bases, NULL, NULL, NULL, NULL)); 434 PetscCallCeed(ctx->ceed, CeedBasisGetNumComponents(active_bases[0], &num_comp)); 435 if (num_bases > 1) { 436 ctx->is_ceed_pbd_valid = PETSC_FALSE; 437 ctx->is_ceed_vpbd_valid = PETSC_FALSE; 438 } 439 if (num_comp != block_size) ctx->is_ceed_pbd_valid = PETSC_FALSE; 440 if (num_comp < max_vblock_size) ctx->is_ceed_vpbd_valid = PETSC_FALSE; 441 // LCOV_EXCL_STOP 442 } 443 { 444 PetscInt local_is_valid[2], global_is_valid[2]; 445 446 local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_pbd_valid; 447 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid)); 448 ctx->is_ceed_pbd_valid = global_is_valid[0]; 449 local_is_valid[0] = local_is_valid[1] = ctx->is_ceed_vpbd_valid; 450 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm_x), local_is_valid, global_is_valid)); 451 ctx->is_ceed_vpbd_valid = global_is_valid[0]; 452 } 453 } 454 } 455 PetscCall(MatDestroy(&temp_mat)); 456 } 457 // -- Set internal mat type 458 { 459 VecType vec_type; 460 MatType coo_mat_type; 461 462 PetscCall(VecGetType(ctx->X_loc, &vec_type)); 463 if (strstr(vec_type, VECCUDA)) coo_mat_type = MATAIJCUSPARSE; 464 else if (strstr(vec_type, VECKOKKOS)) coo_mat_type = MATAIJKOKKOS; 465 else coo_mat_type = MATAIJ; 466 PetscCall(PetscStrallocpy(coo_mat_type, &ctx->coo_mat_type)); 467 } 468 // -- Set mat operations 469 PetscCall(MatShellSetContextDestroy(*mat, (PetscCtxDestroyFn *)MatCeedContextDestroy)); 470 PetscCall(MatShellSetOperation(*mat, MATOP_VIEW, (void (*)(void))MatView_Ceed)); 471 PetscCall(MatShellSetOperation(*mat, MATOP_MULT, (void (*)(void))MatMult_Ceed)); 472 if (op_mult_transpose) PetscCall(MatShellSetOperation(*mat, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed)); 473 PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed)); 474 PetscCall(MatShellSetOperation(*mat, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed)); 475 PetscCall(MatShellSetOperation(*mat, MATOP_GET_BLOCK_DIAGONAL, (void (*)(void))MatGetBlockDiagonal_Ceed)); 476 PetscCall(MatShellSetOperation(*mat, MATOP_GET_VBLOCK_DIAGONAL, (void (*)(void))MatGetVariableBlockDiagonal_Ceed)); 477 PetscCall(MatShellSetVecType(*mat, vec_type)); 478 PetscFunctionReturn(PETSC_SUCCESS); 479 } 480 481 /** 482 @brief Copy `MATCEED` into a compatible `Mat` with type `MatShell` or `MATCEED`. 483 484 Collective across MPI processes. 485 486 @param[in] mat_ceed `MATCEED` to copy from 487 @param[out] mat_other `MatShell` or `MATCEED` to copy into 488 489 @return An error code: 0 - success, otherwise - failure 490 **/ 491 PetscErrorCode MatCeedCopy(Mat mat_ceed, Mat mat_other) { 492 PetscFunctionBeginUser; 493 PetscCall(MatCeedRegisterLogEvents()); 494 495 // Check type compatibility 496 { 497 PetscBool is_matceed = PETSC_FALSE, is_matshell = PETSC_FALSE; 498 MatType mat_type_ceed, mat_type_other; 499 500 PetscCall(MatGetType(mat_ceed, &mat_type_ceed)); 501 PetscCall(PetscStrcmp(mat_type_ceed, MATCEED, &is_matceed)); 502 PetscCheck(is_matceed, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_ceed must have type " MATCEED); 503 PetscCall(MatGetType(mat_other, &mat_type_other)); 504 PetscCall(PetscStrcmp(mat_type_other, MATCEED, &is_matceed)); 505 PetscCall(PetscStrcmp(mat_type_other, MATSHELL, &is_matceed)); 506 PetscCheck(is_matceed || is_matshell, PETSC_COMM_SELF, PETSC_ERR_LIB, "mat_other must have type " MATCEED " or " MATSHELL); 507 } 508 509 // Check dimension compatibility 510 { 511 PetscInt X_l_ceed_size, X_g_ceed_size, Y_l_ceed_size, Y_g_ceed_size, X_l_other_size, X_g_other_size, Y_l_other_size, Y_g_other_size; 512 513 PetscCall(MatGetSize(mat_ceed, &Y_g_ceed_size, &X_g_ceed_size)); 514 PetscCall(MatGetLocalSize(mat_ceed, &Y_l_ceed_size, &X_l_ceed_size)); 515 PetscCall(MatGetSize(mat_ceed, &Y_g_other_size, &X_g_other_size)); 516 PetscCall(MatGetLocalSize(mat_ceed, &Y_l_other_size, &X_l_other_size)); 517 PetscCheck((Y_g_ceed_size == Y_g_other_size) && (X_g_ceed_size == X_g_other_size) && (Y_l_ceed_size == Y_l_other_size) && 518 (X_l_ceed_size == X_l_other_size), 519 PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, 520 "mat_ceed and mat_other must have compatible sizes; found mat_ceed (Global: %" PetscInt_FMT ", %" PetscInt_FMT 521 "; Local: %" PetscInt_FMT ", %" PetscInt_FMT ") mat_other (Global: %" PetscInt_FMT ", %" PetscInt_FMT "; Local: %" PetscInt_FMT 522 ", %" PetscInt_FMT ")", 523 Y_g_ceed_size, X_g_ceed_size, Y_l_ceed_size, X_l_ceed_size, Y_g_other_size, X_g_other_size, Y_l_other_size, X_l_other_size); 524 } 525 526 // Convert 527 { 528 VecType vec_type; 529 MatCeedContext ctx; 530 531 PetscCall(PetscObjectChangeTypeName((PetscObject)mat_other, MATCEED)); 532 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 533 PetscCall(MatCeedContextReference(ctx)); 534 PetscCall(MatShellSetContext(mat_other, ctx)); 535 PetscCall(MatShellSetContextDestroy(mat_other, (PetscCtxDestroyFn *)MatCeedContextDestroy)); 536 PetscCall(MatShellSetOperation(mat_other, MATOP_VIEW, (void (*)(void))MatView_Ceed)); 537 PetscCall(MatShellSetOperation(mat_other, MATOP_MULT, (void (*)(void))MatMult_Ceed)); 538 if (ctx->op_mult_transpose) PetscCall(MatShellSetOperation(mat_other, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Ceed)); 539 PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Ceed)); 540 PetscCall(MatShellSetOperation(mat_other, MATOP_GET_DIAGONAL_BLOCK, (void (*)(void))MatGetDiagonalBlock_Ceed)); 541 PetscCall(MatShellSetOperation(mat_other, MATOP_GET_BLOCK_DIAGONAL, (void (*)(void))MatGetBlockDiagonal_Ceed)); 542 PetscCall(MatShellSetOperation(mat_other, MATOP_GET_VBLOCK_DIAGONAL, (void (*)(void))MatGetVariableBlockDiagonal_Ceed)); 543 { 544 PetscInt block_size; 545 546 PetscCall(MatGetBlockSize(mat_ceed, &block_size)); 547 if (block_size > 1) PetscCall(MatSetBlockSize(mat_other, block_size)); 548 } 549 { 550 PetscInt num_blocks; 551 const PetscInt *block_sizes; 552 553 PetscCall(MatGetVariableBlockSizes(mat_ceed, &num_blocks, &block_sizes)); 554 if (num_blocks) PetscCall(MatSetVariableBlockSizes(mat_other, num_blocks, (PetscInt *)block_sizes)); 555 } 556 PetscCall(DMGetVecType(ctx->dm_x, &vec_type)); 557 PetscCall(MatShellSetVecType(mat_other, vec_type)); 558 } 559 PetscFunctionReturn(PETSC_SUCCESS); 560 } 561 562 /** 563 @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly for a `MatCEED`. 564 565 Collective across MPI processes. 566 567 @param[in] mat_ceed `MATCEED` 568 @param[out] update_needed Boolean flag indicating `CeedQFunction` update needed 569 570 @return An error code: 0 - success, otherwise - failure 571 **/ 572 PetscErrorCode MatCeedSetAssemblyDataUpdateNeeded(Mat mat_ceed, PetscBool update_needed) { 573 MatCeedContext ctx; 574 575 PetscFunctionBeginUser; 576 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 577 PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult, update_needed)); 578 if (ctx->op_mult_transpose) { 579 PetscCallCeed(ctx->ceed, CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(ctx->op_mult_transpose, update_needed)); 580 } 581 if (update_needed) { 582 PetscCall(MatAssemblyBegin(mat_ceed, MAT_FINAL_ASSEMBLY)); 583 PetscCall(MatAssemblyEnd(mat_ceed, MAT_FINAL_ASSEMBLY)); 584 } 585 PetscFunctionReturn(PETSC_SUCCESS); 586 } 587 588 /** 589 @brief Setup a `Mat` with the same COO pattern as a `MatCEED`. 590 591 Collective across MPI processes. 592 593 @param[in] mat_ceed `MATCEED` 594 @param[out] mat_coo Sparse `Mat` with same COO pattern 595 596 @return An error code: 0 - success, otherwise - failure 597 **/ 598 PetscErrorCode MatCeedCreateMatCOO(Mat mat_ceed, Mat *mat_coo) { 599 MatCeedContext ctx; 600 601 PetscFunctionBeginUser; 602 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 603 604 PetscCheck(ctx->dm_x == ctx->dm_y, PetscObjectComm((PetscObject)mat_ceed), PETSC_ERR_SUP, "COO assembly only supported for MATCEED on a single DM"); 605 606 // Check cl mat type 607 { 608 PetscBool is_coo_mat_type_cl = PETSC_FALSE; 609 char coo_mat_type_cl[64]; 610 611 // Check for specific CL coo mat type for this Mat 612 { 613 const char *mat_ceed_prefix = NULL; 614 615 PetscCall(MatGetOptionsPrefix(mat_ceed, &mat_ceed_prefix)); 616 PetscOptionsBegin(PetscObjectComm((PetscObject)mat_ceed), mat_ceed_prefix, "", NULL); 617 PetscCall(PetscOptionsFList("-ceed_coo_mat_type", "Default MATCEED COO assembly MatType", NULL, MatList, coo_mat_type_cl, coo_mat_type_cl, 618 sizeof(coo_mat_type_cl), &is_coo_mat_type_cl)); 619 PetscOptionsEnd(); 620 if (is_coo_mat_type_cl) { 621 PetscCall(PetscFree(ctx->coo_mat_type)); 622 PetscCall(PetscStrallocpy(coo_mat_type_cl, &ctx->coo_mat_type)); 623 } 624 } 625 } 626 627 // Create sparse matrix 628 { 629 MatType dm_mat_type, dm_mat_type_copy; 630 631 PetscCall(DMGetMatType(ctx->dm_x, &dm_mat_type)); 632 PetscCall(PetscStrallocpy(dm_mat_type, (char **)&dm_mat_type_copy)); 633 PetscCall(DMSetMatType(ctx->dm_x, ctx->coo_mat_type)); 634 PetscCall(DMCreateMatrix(ctx->dm_x, mat_coo)); 635 PetscCall(DMSetMatType(ctx->dm_x, dm_mat_type_copy)); 636 PetscCall(PetscFree(dm_mat_type_copy)); 637 } 638 PetscFunctionReturn(PETSC_SUCCESS); 639 } 640 641 /** 642 @brief Setup the COO preallocation `MATCEED` into a `MATAIJ` or similar. 643 The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail. 644 645 Collective across MPI processes. 646 647 @param[in] mat_ceed `MATCEED` to assemble 648 @param[in,out] mat_coo `MATAIJ` or similar to assemble into 649 650 @return An error code: 0 - success, otherwise - failure 651 **/ 652 PetscErrorCode MatCeedSetPreallocationCOO(Mat mat_ceed, Mat mat_coo) { 653 MatCeedContext ctx; 654 655 PetscFunctionBeginUser; 656 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 657 658 { 659 PetscInt *rows_petsc = NULL, *cols_petsc = NULL; 660 CeedInt *rows_ceed, *cols_ceed; 661 PetscCount num_entries; 662 PetscLogStage stage_amg_setup; 663 664 // -- Assemble sparsity pattern if mat hasn't been assembled before 665 PetscCall(PetscLogStageGetId("MatCEED Asm Setup", &stage_amg_setup)); 666 if (stage_amg_setup == -1) { 667 PetscCall(PetscLogStageRegister("MatCEED Asm Setup", &stage_amg_setup)); 668 } 669 PetscCall(PetscLogStagePush(stage_amg_setup)); 670 PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL)); 671 PetscCall(PetscLogEventBegin(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 672 PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleSymbolic(ctx->op_mult, &num_entries, &rows_ceed, &cols_ceed)); 673 PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 674 PetscCall(IntArrayCeedToPetsc(num_entries, &rows_ceed, &rows_petsc)); 675 PetscCall(IntArrayCeedToPetsc(num_entries, &cols_ceed, &cols_petsc)); 676 PetscCall(MatSetPreallocationCOOLocal(mat_coo, num_entries, rows_petsc, cols_petsc)); 677 free(rows_petsc); 678 free(cols_petsc); 679 if (!ctx->coo_values_full) PetscCallCeed(ctx->ceed, CeedVectorCreate(ctx->ceed, num_entries, &ctx->coo_values_full)); 680 PetscCall(PetscRealloc(++ctx->num_mats_assembled_full * sizeof(Mat), &ctx->mats_assembled_full)); 681 ctx->mats_assembled_full[ctx->num_mats_assembled_full - 1] = mat_coo; 682 PetscCall(PetscLogEventEnd(MATCEED_SETUP_FULL, mat_ceed, mat_coo, NULL, NULL)); 683 PetscCall(PetscLogStagePop()); 684 } 685 PetscFunctionReturn(PETSC_SUCCESS); 686 } 687 688 /** 689 @brief Assemble a `MATCEED` into a `MATAIJ` or similar. 690 The `mat_coo` preallocation is set to match the sparsity pattern of `mat_ceed`. 691 The caller is responsible for assuring the global and local sizes are compatible, otherwise this function will fail. 692 693 Collective across MPI processes. 694 695 @param[in] mat_ceed `MATCEED` to assemble 696 @param[in,out] mat_coo `MATAIJ` or similar to assemble into 697 698 @return An error code: 0 - success, otherwise - failure 699 **/ 700 PetscErrorCode MatCeedAssembleCOO(Mat mat_ceed, Mat mat_coo) { 701 MatCeedContext ctx; 702 703 PetscFunctionBeginUser; 704 PetscCall(MatShellGetContext(mat_ceed, &ctx)); 705 706 // Set COO pattern if needed 707 { 708 CeedInt index = -1; 709 710 for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) { 711 if (ctx->mats_assembled_full[i] == mat_coo) index = i; 712 } 713 if (index == -1) PetscCall(MatCeedSetPreallocationCOO(mat_ceed, mat_coo)); 714 } 715 716 // Assemble mat_ceed 717 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL)); 718 PetscCall(MatAssemblyBegin(mat_coo, MAT_FINAL_ASSEMBLY)); 719 { 720 const CeedScalar *values; 721 MatType mat_type; 722 CeedMemType mem_type = CEED_MEM_HOST; 723 PetscBool is_spd, is_spd_known; 724 725 PetscCall(MatGetType(mat_coo, &mat_type)); 726 if (strstr(mat_type, "cusparse")) mem_type = CEED_MEM_DEVICE; 727 else if (strstr(mat_type, "kokkos")) mem_type = CEED_MEM_DEVICE; 728 else mem_type = CEED_MEM_HOST; 729 730 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 731 PetscCallCeed(ctx->ceed, CeedOperatorLinearAssemble(ctx->op_mult, ctx->coo_values_full)); 732 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL_CEEDOP, mat_ceed, mat_coo, NULL, NULL)); 733 PetscCallCeed(ctx->ceed, CeedVectorGetArrayRead(ctx->coo_values_full, mem_type, &values)); 734 PetscCall(MatSetValuesCOO(mat_coo, values, INSERT_VALUES)); 735 PetscCall(MatIsSPDKnown(mat_ceed, &is_spd_known, &is_spd)); 736 if (is_spd_known) PetscCall(MatSetOption(mat_coo, MAT_SPD, is_spd)); 737 PetscCallCeed(ctx->ceed, CeedVectorRestoreArrayRead(ctx->coo_values_full, &values)); 738 } 739 PetscCall(MatAssemblyEnd(mat_coo, MAT_FINAL_ASSEMBLY)); 740 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_FULL, mat_ceed, mat_coo, NULL, NULL)); 741 PetscFunctionReturn(PETSC_SUCCESS); 742 } 743 744 /** 745 @brief Set the current value of a context field for a `MatCEED`. 746 747 Not collective across MPI processes. 748 749 @param[in,out] mat `MatCEED` 750 @param[in] name Name of the context field 751 @param[in] value New context field value 752 753 @return An error code: 0 - success, otherwise - failure 754 **/ 755 PetscErrorCode MatCeedSetContextDouble(Mat mat, const char *name, double value) { 756 PetscBool was_updated = PETSC_FALSE; 757 MatCeedContext ctx; 758 759 PetscFunctionBeginUser; 760 PetscCall(MatShellGetContext(mat, &ctx)); 761 { 762 CeedContextFieldLabel label = NULL; 763 764 PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult, name, &label)); 765 if (label) { 766 double set_value = 2 * value + 1.0; 767 768 PetscCall(MatCeedGetContextDouble(mat, name, &set_value)); 769 if (set_value != value) { 770 PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult, label, &value)); 771 was_updated = PETSC_TRUE; 772 } 773 } 774 if (ctx->op_mult_transpose) { 775 label = NULL; 776 PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(ctx->op_mult_transpose, name, &label)); 777 if (label) { 778 double set_value = 2 * value + 1.0; 779 780 PetscCall(MatCeedGetContextDouble(mat, name, &set_value)); 781 if (set_value != value) { 782 PetscCallCeed(ctx->ceed, CeedOperatorSetContextDouble(ctx->op_mult_transpose, label, &value)); 783 was_updated = PETSC_TRUE; 784 } 785 } 786 } 787 } 788 if (was_updated) { 789 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 790 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 791 } 792 PetscFunctionReturn(PETSC_SUCCESS); 793 } 794 795 /** 796 @brief Get the current value of a context field for a `MatCEED`. 797 798 Not collective across MPI processes. 799 800 @param[in] mat `MatCEED` 801 @param[in] name Name of the context field 802 @param[out] value Current context field value 803 804 @return An error code: 0 - success, otherwise - failure 805 **/ 806 PetscErrorCode MatCeedGetContextDouble(Mat mat, const char *name, double *value) { 807 MatCeedContext ctx; 808 809 PetscFunctionBeginUser; 810 PetscCall(MatShellGetContext(mat, &ctx)); 811 { 812 CeedContextFieldLabel label = NULL; 813 CeedOperator op = ctx->op_mult; 814 815 PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label)); 816 if (!label && ctx->op_mult_transpose) { 817 op = ctx->op_mult_transpose; 818 PetscCallCeed(ctx->ceed, CeedOperatorGetContextFieldLabel(op, name, &label)); 819 } 820 if (label) { 821 PetscSizeT num_values; 822 const double *values_ceed; 823 824 PetscCallCeed(ctx->ceed, CeedOperatorGetContextDoubleRead(op, label, &num_values, &values_ceed)); 825 *value = values_ceed[0]; 826 PetscCallCeed(ctx->ceed, CeedOperatorRestoreContextDoubleRead(op, label, &values_ceed)); 827 } 828 } 829 PetscFunctionReturn(PETSC_SUCCESS); 830 } 831 832 /** 833 @brief Set the current `PetscReal` value of a context field for a `MatCEED`. 834 835 Not collective across MPI processes. 836 837 @param[in,out] mat `MatCEED` 838 @param[in] name Name of the context field 839 @param[in] value New context field value 840 841 @return An error code: 0 - success, otherwise - failure 842 **/ 843 PetscErrorCode MatCeedSetContextReal(Mat mat, const char *name, PetscReal value) { 844 double value_double = value; 845 846 PetscFunctionBeginUser; 847 PetscCall(MatCeedSetContextDouble(mat, name, value_double)); 848 PetscFunctionReturn(PETSC_SUCCESS); 849 } 850 851 /** 852 @brief Get the current `PetscReal` value of a context field for a `MatCEED`. 853 854 Not collective across MPI processes. 855 856 @param[in] mat `MatCEED` 857 @param[in] name Name of the context field 858 @param[out] value Current context field value 859 860 @return An error code: 0 - success, otherwise - failure 861 **/ 862 PetscErrorCode MatCeedGetContextReal(Mat mat, const char *name, PetscReal *value) { 863 double value_double = 0.0; 864 865 PetscFunctionBeginUser; 866 PetscCall(MatCeedGetContextDouble(mat, name, &value_double)); 867 *value = value_double; 868 PetscFunctionReturn(PETSC_SUCCESS); 869 } 870 871 /** 872 @brief Set the current time for a `MatCEED`. 873 874 Not collective across MPI processes. 875 876 @param[in,out] mat `MatCEED` 877 @param[in] time Current time 878 879 @return An error code: 0 - success, otherwise - failure 880 **/ 881 PetscErrorCode MatCeedSetTime(Mat mat, PetscReal time) { 882 PetscFunctionBeginUser; 883 { 884 double time_ceed = time; 885 886 PetscCall(MatCeedSetContextDouble(mat, "time", time_ceed)); 887 } 888 PetscFunctionReturn(PETSC_SUCCESS); 889 } 890 891 /** 892 @brief Get the current time for a `MatCEED`. 893 894 Not collective across MPI processes. 895 896 @param[in] mat `MatCEED` 897 @param[out] time Current time, or -1.0 if the boundary evaluator has no time field 898 899 @return An error code: 0 - success, otherwise - failure 900 **/ 901 PetscErrorCode MatCeedGetTime(Mat mat, PetscReal *time) { 902 PetscFunctionBeginUser; 903 *time = -1.0; 904 { 905 double time_ceed = -1.0; 906 907 PetscCall(MatCeedGetContextDouble(mat, "time", &time_ceed)); 908 *time = time_ceed; 909 } 910 PetscFunctionReturn(PETSC_SUCCESS); 911 } 912 913 /** 914 @brief Set the current time step for a `MatCEED`. 915 916 Not collective across MPI processes. 917 918 @param[in,out] mat `MatCEED` 919 @param[in] dt Current time step 920 921 @return An error code: 0 - success, otherwise - failure 922 **/ 923 PetscErrorCode MatCeedSetDt(Mat mat, PetscReal dt) { 924 PetscFunctionBeginUser; 925 { 926 double dt_ceed = dt; 927 928 PetscCall(MatCeedSetContextDouble(mat, "dt", dt_ceed)); 929 } 930 PetscFunctionReturn(PETSC_SUCCESS); 931 } 932 933 /** 934 @brief Set the Jacobian shifts for a `MatCEED`. 935 936 Not collective across MPI processes. 937 938 @param[in,out] mat `MatCEED` 939 @param[in] shift_v Velocity shift 940 @param[in] shift_a Acceleration shift 941 942 @return An error code: 0 - success, otherwise - failure 943 **/ 944 PetscErrorCode MatCeedSetShifts(Mat mat, PetscReal shift_v, PetscReal shift_a) { 945 PetscFunctionBeginUser; 946 { 947 double shift_v_ceed = shift_v; 948 949 PetscCall(MatCeedSetContextDouble(mat, "shift v", shift_v_ceed)); 950 } 951 if (shift_a) { 952 double shift_a_ceed = shift_a; 953 954 PetscCall(MatCeedSetContextDouble(mat, "shift a", shift_a_ceed)); 955 } 956 PetscFunctionReturn(PETSC_SUCCESS); 957 } 958 959 /** 960 @brief Set user context for a `MATCEED`. 961 962 Collective across MPI processes. 963 964 @param[in,out] mat `MATCEED` 965 @param[in] f The context destroy function, or NULL 966 @param[in] ctx User context, or NULL to unset 967 968 @return An error code: 0 - success, otherwise - failure 969 **/ 970 PetscErrorCode MatCeedSetContext(Mat mat, PetscCtxDestroyFn f, void *ctx) { 971 PetscContainer user_ctx = NULL; 972 973 PetscFunctionBeginUser; 974 if (ctx) { 975 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &user_ctx)); 976 PetscCall(PetscContainerSetPointer(user_ctx, ctx)); 977 PetscCall(PetscContainerSetCtxDestroy(user_ctx, f)); 978 } 979 PetscCall(PetscObjectCompose((PetscObject)mat, "MatCeed user context", (PetscObject)user_ctx)); 980 PetscCall(PetscContainerDestroy(&user_ctx)); 981 PetscFunctionReturn(PETSC_SUCCESS); 982 } 983 984 /** 985 @brief Retrieve the user context for a `MATCEED`. 986 987 Collective across MPI processes. 988 989 @param[in,out] mat `MATCEED` 990 @param[in] ctx User context 991 992 @return An error code: 0 - success, otherwise - failure 993 **/ 994 PetscErrorCode MatCeedGetContext(Mat mat, void *ctx) { 995 PetscContainer user_ctx; 996 997 PetscFunctionBeginUser; 998 PetscCall(PetscObjectQuery((PetscObject)mat, "MatCeed user context", (PetscObject *)&user_ctx)); 999 if (user_ctx) PetscCall(PetscContainerGetPointer(user_ctx, (void **)ctx)); 1000 else *(void **)ctx = NULL; 1001 PetscFunctionReturn(PETSC_SUCCESS); 1002 } 1003 /** 1004 @brief Set a user defined matrix operation for a `MATCEED` matrix. 1005 1006 Within each user-defined routine, the user should call `MatCeedGetContext()` to obtain the user-defined context that was set by 1007 `MatCeedSetContext()`. 1008 1009 Collective across MPI processes. 1010 1011 @param[in,out] mat `MATCEED` 1012 @param[in] op Name of the `MatOperation` 1013 @param[in] g Function that provides the operation 1014 1015 @return An error code: 0 - success, otherwise - failure 1016 **/ 1017 PetscErrorCode MatCeedSetOperation(Mat mat, MatOperation op, void (*g)(void)) { 1018 PetscFunctionBeginUser; 1019 PetscCall(MatShellSetOperation(mat, op, g)); 1020 PetscFunctionReturn(PETSC_SUCCESS); 1021 } 1022 1023 /** 1024 @brief Sets the default COO matrix type as a string from the `MATCEED`. 1025 1026 Collective across MPI processes. 1027 1028 @param[in,out] mat `MATCEED` 1029 @param[in] type COO `MatType` to set 1030 1031 @return An error code: 0 - success, otherwise - failure 1032 **/ 1033 PetscErrorCode MatCeedSetCOOMatType(Mat mat, MatType type) { 1034 MatCeedContext ctx; 1035 1036 PetscFunctionBeginUser; 1037 PetscCall(MatShellGetContext(mat, &ctx)); 1038 // Check if same 1039 { 1040 size_t len_old, len_new; 1041 PetscBool is_same = PETSC_FALSE; 1042 1043 PetscCall(PetscStrlen(ctx->coo_mat_type, &len_old)); 1044 PetscCall(PetscStrlen(type, &len_new)); 1045 if (len_old == len_new) PetscCall(PetscStrncmp(ctx->coo_mat_type, type, len_old, &is_same)); 1046 if (is_same) PetscFunctionReturn(PETSC_SUCCESS); 1047 } 1048 // Clean up old mats in different format 1049 // LCOV_EXCL_START 1050 if (ctx->mat_assembled_full_internal) { 1051 for (PetscInt i = 0; i < ctx->num_mats_assembled_full; i++) { 1052 if (ctx->mats_assembled_full[i] == ctx->mat_assembled_full_internal) { 1053 for (PetscInt j = i + 1; j < ctx->num_mats_assembled_full; j++) { 1054 ctx->mats_assembled_full[j - 1] = ctx->mats_assembled_full[j]; 1055 } 1056 ctx->num_mats_assembled_full--; 1057 // Note: we'll realloc this array again, so no need to shrink the allocation 1058 PetscCall(MatDestroy(&ctx->mat_assembled_full_internal)); 1059 } 1060 } 1061 } 1062 if (ctx->mat_assembled_pbd_internal) { 1063 for (PetscInt i = 0; i < ctx->num_mats_assembled_pbd; i++) { 1064 if (ctx->mats_assembled_pbd[i] == ctx->mat_assembled_pbd_internal) { 1065 for (PetscInt j = i + 1; j < ctx->num_mats_assembled_pbd; j++) { 1066 ctx->mats_assembled_pbd[j - 1] = ctx->mats_assembled_pbd[j]; 1067 } 1068 // Note: we'll realloc this array again, so no need to shrink the allocation 1069 ctx->num_mats_assembled_pbd--; 1070 PetscCall(MatDestroy(&ctx->mat_assembled_pbd_internal)); 1071 } 1072 } 1073 } 1074 PetscCall(PetscFree(ctx->coo_mat_type)); 1075 PetscCall(PetscStrallocpy(type, &ctx->coo_mat_type)); 1076 PetscFunctionReturn(PETSC_SUCCESS); 1077 // LCOV_EXCL_STOP 1078 } 1079 1080 /** 1081 @brief Gets the default COO matrix type as a string from the `MATCEED`. 1082 1083 Collective across MPI processes. 1084 1085 @param[in,out] mat `MATCEED` 1086 @param[in] type COO `MatType` 1087 1088 @return An error code: 0 - success, otherwise - failure 1089 **/ 1090 PetscErrorCode MatCeedGetCOOMatType(Mat mat, MatType *type) { 1091 MatCeedContext ctx; 1092 1093 PetscFunctionBeginUser; 1094 PetscCall(MatShellGetContext(mat, &ctx)); 1095 *type = ctx->coo_mat_type; 1096 PetscFunctionReturn(PETSC_SUCCESS); 1097 } 1098 1099 /** 1100 @brief Set input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations. 1101 1102 Not collective across MPI processes. 1103 1104 @param[in,out] mat `MATCEED` 1105 @param[in] X_loc Input PETSc local vector, or NULL 1106 @param[in] Y_loc_transpose Input PETSc local vector for transpose operation, or NULL 1107 1108 @return An error code: 0 - success, otherwise - failure 1109 **/ 1110 PetscErrorCode MatCeedSetLocalVectors(Mat mat, Vec X_loc, Vec Y_loc_transpose) { 1111 MatCeedContext ctx; 1112 1113 PetscFunctionBeginUser; 1114 PetscCall(MatShellGetContext(mat, &ctx)); 1115 if (X_loc) { 1116 PetscInt len_old, len_new; 1117 1118 PetscCall(VecGetSize(ctx->X_loc, &len_old)); 1119 PetscCall(VecGetSize(X_loc, &len_new)); 1120 PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB, "new X_loc length %" PetscInt_FMT " should match old X_loc length %" PetscInt_FMT, 1121 len_new, len_old); 1122 PetscCall(VecReferenceCopy(X_loc, &ctx->X_loc)); 1123 } 1124 if (Y_loc_transpose) { 1125 PetscInt len_old, len_new; 1126 1127 PetscCall(VecGetSize(ctx->Y_loc_transpose, &len_old)); 1128 PetscCall(VecGetSize(Y_loc_transpose, &len_new)); 1129 PetscCheck(len_old == len_new, PETSC_COMM_SELF, PETSC_ERR_LIB, 1130 "new Y_loc_transpose length %" PetscInt_FMT " should match old Y_loc_transpose length %" PetscInt_FMT, len_new, len_old); 1131 PetscCall(VecReferenceCopy(Y_loc_transpose, &ctx->Y_loc_transpose)); 1132 } 1133 PetscFunctionReturn(PETSC_SUCCESS); 1134 } 1135 1136 /** 1137 @brief Get input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations. 1138 1139 Not collective across MPI processes. 1140 1141 @param[in,out] mat `MATCEED` 1142 @param[out] X_loc Input PETSc local vector, or NULL 1143 @param[out] Y_loc_transpose Input PETSc local vector for transpose operation, or NULL 1144 1145 @return An error code: 0 - success, otherwise - failure 1146 **/ 1147 PetscErrorCode MatCeedGetLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) { 1148 MatCeedContext ctx; 1149 1150 PetscFunctionBeginUser; 1151 PetscCall(MatShellGetContext(mat, &ctx)); 1152 if (X_loc) { 1153 *X_loc = NULL; 1154 PetscCall(VecReferenceCopy(ctx->X_loc, X_loc)); 1155 } 1156 if (Y_loc_transpose) { 1157 *Y_loc_transpose = NULL; 1158 PetscCall(VecReferenceCopy(ctx->Y_loc_transpose, Y_loc_transpose)); 1159 } 1160 PetscFunctionReturn(PETSC_SUCCESS); 1161 } 1162 1163 /** 1164 @brief Restore input local vectors for `MATCEED` `MatMult()` and `MatMultTranspose()` operations. 1165 1166 Not collective across MPI processes. 1167 1168 @param[in,out] mat MatCeed 1169 @param[out] X_loc Input PETSc local vector, or NULL 1170 @param[out] Y_loc_transpose Input PETSc local vector for transpose operation, or NULL 1171 1172 @return An error code: 0 - success, otherwise - failure 1173 **/ 1174 PetscErrorCode MatCeedRestoreLocalVectors(Mat mat, Vec *X_loc, Vec *Y_loc_transpose) { 1175 PetscFunctionBeginUser; 1176 if (X_loc) PetscCall(VecDestroy(X_loc)); 1177 if (Y_loc_transpose) PetscCall(VecDestroy(Y_loc_transpose)); 1178 PetscFunctionReturn(PETSC_SUCCESS); 1179 } 1180 1181 /** 1182 @brief Get libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations. 1183 1184 Not collective across MPI processes. 1185 1186 @param[in,out] mat MatCeed 1187 @param[out] op_mult libCEED `CeedOperator` for `MatMult()`, or NULL 1188 @param[out] op_mult_transpose libCEED `CeedOperator` for `MatMultTranspose()`, or NULL 1189 1190 @return An error code: 0 - success, otherwise - failure 1191 **/ 1192 PetscErrorCode MatCeedGetCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) { 1193 MatCeedContext ctx; 1194 1195 PetscFunctionBeginUser; 1196 PetscCall(MatShellGetContext(mat, &ctx)); 1197 if (op_mult) { 1198 *op_mult = NULL; 1199 PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult, op_mult)); 1200 } 1201 if (op_mult_transpose) { 1202 *op_mult_transpose = NULL; 1203 PetscCallCeed(ctx->ceed, CeedOperatorReferenceCopy(ctx->op_mult_transpose, op_mult_transpose)); 1204 } 1205 PetscFunctionReturn(PETSC_SUCCESS); 1206 } 1207 1208 /** 1209 @brief Restore libCEED `CeedOperator` for `MATCEED` `MatMult()` and `MatMultTranspose()` operations. 1210 1211 Not collective across MPI processes. 1212 1213 @param[in,out] mat MatCeed 1214 @param[out] op_mult libCEED `CeedOperator` for `MatMult()`, or NULL 1215 @param[out] op_mult_transpose libCEED `CeedOperator` for `MatMultTranspose()`, or NULL 1216 1217 @return An error code: 0 - success, otherwise - failure 1218 **/ 1219 PetscErrorCode MatCeedRestoreCeedOperators(Mat mat, CeedOperator *op_mult, CeedOperator *op_mult_transpose) { 1220 MatCeedContext ctx; 1221 1222 PetscFunctionBeginUser; 1223 PetscCall(MatShellGetContext(mat, &ctx)); 1224 if (op_mult) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult)); 1225 if (op_mult_transpose) PetscCallCeed(ctx->ceed, CeedOperatorDestroy(op_mult_transpose)); 1226 PetscFunctionReturn(PETSC_SUCCESS); 1227 } 1228 1229 /** 1230 @brief Set `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators. 1231 1232 Not collective across MPI processes. 1233 1234 @param[in,out] mat MatCeed 1235 @param[out] log_event_mult `PetscLogEvent` for forward evaluation, or NULL 1236 @param[out] log_event_mult_transpose `PetscLogEvent` for transpose evaluation, or NULL 1237 1238 @return An error code: 0 - success, otherwise - failure 1239 **/ 1240 PetscErrorCode MatCeedSetLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) { 1241 MatCeedContext ctx; 1242 1243 PetscFunctionBeginUser; 1244 PetscCall(MatShellGetContext(mat, &ctx)); 1245 if (log_event_mult) ctx->log_event_mult = log_event_mult; 1246 if (log_event_mult_transpose) ctx->log_event_mult_transpose = log_event_mult_transpose; 1247 PetscFunctionReturn(PETSC_SUCCESS); 1248 } 1249 1250 /** 1251 @brief Get `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators. 1252 1253 Not collective across MPI processes. 1254 1255 @param[in,out] mat MatCeed 1256 @param[out] log_event_mult `PetscLogEvent` for forward evaluation, or NULL 1257 @param[out] log_event_mult_transpose `PetscLogEvent` for transpose evaluation, or NULL 1258 1259 @return An error code: 0 - success, otherwise - failure 1260 **/ 1261 PetscErrorCode MatCeedGetLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) { 1262 MatCeedContext ctx; 1263 1264 PetscFunctionBeginUser; 1265 PetscCall(MatShellGetContext(mat, &ctx)); 1266 if (log_event_mult) *log_event_mult = ctx->log_event_mult; 1267 if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_mult_transpose; 1268 PetscFunctionReturn(PETSC_SUCCESS); 1269 } 1270 1271 /** 1272 @brief Set `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators. 1273 1274 Not collective across MPI processes. 1275 1276 @param[in,out] mat MatCeed 1277 @param[out] log_event_mult `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL 1278 @param[out] log_event_mult_transpose `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL 1279 1280 @return An error code: 0 - success, otherwise - failure 1281 **/ 1282 PetscErrorCode MatCeedSetCeedOperatorLogEvents(Mat mat, PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose) { 1283 MatCeedContext ctx; 1284 1285 PetscFunctionBeginUser; 1286 PetscCall(MatShellGetContext(mat, &ctx)); 1287 if (log_event_mult) ctx->log_event_ceed_mult = log_event_mult; 1288 if (log_event_mult_transpose) ctx->log_event_ceed_mult_transpose = log_event_mult_transpose; 1289 PetscFunctionReturn(PETSC_SUCCESS); 1290 } 1291 1292 /** 1293 @brief Get `CeedOperator` `PetscLogEvent` for `MATCEED` `MatMult()` and `MatMultTranspose()` operators. 1294 1295 Not collective across MPI processes. 1296 1297 @param[in,out] mat MatCeed 1298 @param[out] log_event_mult `PetscLogEvent` for forward `CeedOperator` evaluation, or NULL 1299 @param[out] log_event_mult_transpose `PetscLogEvent` for transpose `CeedOperator` evaluation, or NULL 1300 1301 @return An error code: 0 - success, otherwise - failure 1302 **/ 1303 PetscErrorCode MatCeedGetCeedOperatorLogEvents(Mat mat, PetscLogEvent *log_event_mult, PetscLogEvent *log_event_mult_transpose) { 1304 MatCeedContext ctx; 1305 1306 PetscFunctionBeginUser; 1307 PetscCall(MatShellGetContext(mat, &ctx)); 1308 if (log_event_mult) *log_event_mult = ctx->log_event_ceed_mult; 1309 if (log_event_mult_transpose) *log_event_mult_transpose = ctx->log_event_ceed_mult_transpose; 1310 PetscFunctionReturn(PETSC_SUCCESS); 1311 } 1312 1313 // ----------------------------------------------------------------------------- 1314 // Operator context data 1315 // ----------------------------------------------------------------------------- 1316 1317 /** 1318 @brief Setup context data for operator application. 1319 1320 Collective across MPI processes. 1321 1322 @param[in] dm_x Input `DM` 1323 @param[in] dm_y Output `DM` 1324 @param[in] X_loc Input PETSc local vector, or NULL 1325 @param[in] Y_loc_transpose Input PETSc local vector for transpose operation, or NULL 1326 @param[in] op_mult `CeedOperator` for forward evaluation 1327 @param[in] op_mult_transpose `CeedOperator` for transpose evaluation 1328 @param[in] log_event_mult `PetscLogEvent` for forward evaluation 1329 @param[in] log_event_mult_transpose `PetscLogEvent` for transpose evaluation 1330 @param[in] log_event_ceed_mult `PetscLogEvent` for forward `CeedOperator` evaluation 1331 @param[in] log_event_ceed_mult_transpose `PetscLogEvent` for transpose `CeedOperator` evaluation 1332 @param[out] ctx Context data for operator evaluation 1333 1334 @return An error code: 0 - success, otherwise - failure 1335 **/ 1336 PetscErrorCode MatCeedContextCreate(DM dm_x, DM dm_y, Vec X_loc, Vec Y_loc_transpose, CeedOperator op_mult, CeedOperator op_mult_transpose, 1337 PetscLogEvent log_event_mult, PetscLogEvent log_event_mult_transpose, PetscLogEvent log_event_ceed_mult, 1338 PetscLogEvent log_event_ceed_mult_transpose, MatCeedContext *ctx) { 1339 CeedSize x_loc_len, y_loc_len; 1340 1341 PetscFunctionBeginUser; 1342 1343 // Allocate 1344 PetscCall(PetscNew(ctx)); 1345 (*ctx)->ref_count = 1; 1346 1347 // Logging 1348 (*ctx)->log_event_mult = log_event_mult; 1349 (*ctx)->log_event_mult_transpose = log_event_mult_transpose; 1350 (*ctx)->log_event_ceed_mult = log_event_ceed_mult; 1351 (*ctx)->log_event_ceed_mult_transpose = log_event_ceed_mult_transpose; 1352 1353 // PETSc objects 1354 PetscCall(DMReferenceCopy(dm_x, &(*ctx)->dm_x)); 1355 PetscCall(DMReferenceCopy(dm_y, &(*ctx)->dm_y)); 1356 if (X_loc) PetscCall(VecReferenceCopy(X_loc, &(*ctx)->X_loc)); 1357 if (Y_loc_transpose) PetscCall(VecReferenceCopy(Y_loc_transpose, &(*ctx)->Y_loc_transpose)); 1358 1359 // Memtype 1360 { 1361 const PetscScalar *x; 1362 Vec X; 1363 1364 PetscCall(DMGetLocalVector(dm_x, &X)); 1365 PetscCall(VecGetArrayReadAndMemType(X, &x, &(*ctx)->mem_type)); 1366 PetscCall(VecRestoreArrayReadAndMemType(X, &x)); 1367 PetscCall(DMRestoreLocalVector(dm_x, &X)); 1368 } 1369 1370 // libCEED objects 1371 PetscCheck(CeedOperatorGetCeed(op_mult, &(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, 1372 "retrieving Ceed context object failed"); 1373 PetscCallCeed((*ctx)->ceed, CeedReference((*ctx)->ceed)); 1374 PetscCallCeed((*ctx)->ceed, CeedOperatorGetActiveVectorLengths(op_mult, &x_loc_len, &y_loc_len)); 1375 PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult, &(*ctx)->op_mult)); 1376 if (op_mult_transpose) PetscCallCeed((*ctx)->ceed, CeedOperatorReferenceCopy(op_mult_transpose, &(*ctx)->op_mult_transpose)); 1377 PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, x_loc_len, &(*ctx)->x_loc)); 1378 PetscCallCeed((*ctx)->ceed, CeedVectorCreate((*ctx)->ceed, y_loc_len, &(*ctx)->y_loc)); 1379 1380 // Flop counting 1381 { 1382 CeedSize ceed_flops_estimate = 0; 1383 1384 PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult, &ceed_flops_estimate)); 1385 (*ctx)->flops_mult = ceed_flops_estimate; 1386 if (op_mult_transpose) { 1387 PetscCallCeed((*ctx)->ceed, CeedOperatorGetFlopsEstimate(op_mult_transpose, &ceed_flops_estimate)); 1388 (*ctx)->flops_mult_transpose = ceed_flops_estimate; 1389 } 1390 } 1391 1392 // Check sizes 1393 if (x_loc_len > 0 || y_loc_len > 0) { 1394 CeedSize ctx_x_loc_len, ctx_y_loc_len; 1395 PetscInt X_loc_len, dm_x_loc_len, Y_loc_len, dm_y_loc_len; 1396 Vec dm_X_loc, dm_Y_loc; 1397 1398 // -- Input 1399 PetscCall(DMGetLocalVector(dm_x, &dm_X_loc)); 1400 PetscCall(VecGetLocalSize(dm_X_loc, &dm_x_loc_len)); 1401 PetscCall(DMRestoreLocalVector(dm_x, &dm_X_loc)); 1402 PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->x_loc, &ctx_x_loc_len)); 1403 if (X_loc) { 1404 PetscCall(VecGetLocalSize(X_loc, &X_loc_len)); 1405 PetscCheck(X_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, 1406 "X_loc (%" PetscInt_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", X_loc_len, dm_x_loc_len); 1407 } 1408 PetscCheck(x_loc_len == dm_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "op (%" CeedSize_FMT ") must match dm_x (%" PetscInt_FMT ") dimensions", 1409 x_loc_len, dm_x_loc_len); 1410 PetscCheck(x_loc_len == ctx_x_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "x_loc (%" CeedSize_FMT ") must match op dimensions (%" CeedSize_FMT ")", 1411 x_loc_len, ctx_x_loc_len); 1412 1413 // -- Output 1414 PetscCall(DMGetLocalVector(dm_y, &dm_Y_loc)); 1415 PetscCall(VecGetLocalSize(dm_Y_loc, &dm_y_loc_len)); 1416 PetscCall(DMRestoreLocalVector(dm_y, &dm_Y_loc)); 1417 PetscCallCeed((*ctx)->ceed, CeedVectorGetLength((*ctx)->y_loc, &ctx_y_loc_len)); 1418 PetscCheck(ctx_y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, "op (%" CeedSize_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", 1419 ctx_y_loc_len, dm_y_loc_len); 1420 1421 // -- Transpose 1422 if (Y_loc_transpose) { 1423 PetscCall(VecGetLocalSize(Y_loc_transpose, &Y_loc_len)); 1424 PetscCheck(Y_loc_len == dm_y_loc_len, PETSC_COMM_SELF, PETSC_ERR_LIB, 1425 "Y_loc_transpose (%" PetscInt_FMT ") must match dm_y (%" PetscInt_FMT ") dimensions", Y_loc_len, dm_y_loc_len); 1426 } 1427 } 1428 PetscFunctionReturn(PETSC_SUCCESS); 1429 } 1430 1431 /** 1432 @brief Increment reference counter for `MATCEED` context. 1433 1434 Not collective across MPI processes. 1435 1436 @param[in,out] ctx Context data 1437 1438 @return An error code: 0 - success, otherwise - failure 1439 **/ 1440 PetscErrorCode MatCeedContextReference(MatCeedContext ctx) { 1441 PetscFunctionBeginUser; 1442 ctx->ref_count++; 1443 PetscFunctionReturn(PETSC_SUCCESS); 1444 } 1445 1446 /** 1447 @brief Copy reference for `MATCEED`. 1448 Note: If `ctx_copy` is non-null, it is assumed to be a valid pointer to a `MatCeedContext`. 1449 1450 Not collective across MPI processes. 1451 1452 @param[in] ctx Context data 1453 @param[out] ctx_copy Copy of pointer to context data 1454 1455 @return An error code: 0 - success, otherwise - failure 1456 **/ 1457 PetscErrorCode MatCeedContextReferenceCopy(MatCeedContext ctx, MatCeedContext *ctx_copy) { 1458 PetscFunctionBeginUser; 1459 PetscCall(MatCeedContextReference(ctx)); 1460 PetscCall(MatCeedContextDestroy(ctx_copy)); 1461 *ctx_copy = ctx; 1462 PetscFunctionReturn(PETSC_SUCCESS); 1463 } 1464 1465 /** 1466 @brief Destroy context data for operator application. 1467 1468 Collective across MPI processes. 1469 1470 @param[in,out] ctx Context data for operator evaluation 1471 1472 @return An error code: 0 - success, otherwise - failure 1473 **/ 1474 PetscErrorCode MatCeedContextDestroy(MatCeedContext *ctx) { 1475 PetscFunctionBeginUser; 1476 if (!ctx || --(*ctx)->ref_count > 0) PetscFunctionReturn(PETSC_SUCCESS); 1477 1478 // PETSc objects 1479 PetscCall(DMDestroy(&(*ctx)->dm_x)); 1480 PetscCall(DMDestroy(&(*ctx)->dm_y)); 1481 PetscCall(VecDestroy(&(*ctx)->X_loc)); 1482 PetscCall(VecDestroy(&(*ctx)->Y_loc_transpose)); 1483 PetscCall(MatDestroy(&(*ctx)->mat_assembled_full_internal)); 1484 PetscCall(MatDestroy(&(*ctx)->mat_assembled_pbd_internal)); 1485 PetscCall(PetscFree((*ctx)->coo_mat_type)); 1486 PetscCall(PetscFree((*ctx)->mats_assembled_full)); 1487 PetscCall(PetscFree((*ctx)->mats_assembled_pbd)); 1488 1489 // libCEED objects 1490 PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->x_loc)); 1491 PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->y_loc)); 1492 PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_full)); 1493 PetscCallCeed((*ctx)->ceed, CeedVectorDestroy(&(*ctx)->coo_values_pbd)); 1494 PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult)); 1495 PetscCallCeed((*ctx)->ceed, CeedOperatorDestroy(&(*ctx)->op_mult_transpose)); 1496 PetscCheck(CeedDestroy(&(*ctx)->ceed) == CEED_ERROR_SUCCESS, PETSC_COMM_SELF, PETSC_ERR_LIB, "destroying libCEED context object failed"); 1497 1498 // Deallocate 1499 (*ctx)->is_destroyed = PETSC_TRUE; // Flag as destroyed in case someone has stale ref 1500 PetscCall(PetscFree(*ctx)); 1501 PetscFunctionReturn(PETSC_SUCCESS); 1502 } 1503 1504 /** 1505 @brief Compute the diagonal of an operator via libCEED. 1506 1507 Collective across MPI processes. 1508 1509 @param[in] A `MATCEED` 1510 @param[out] D Vector holding operator diagonal 1511 1512 @return An error code: 0 - success, otherwise - failure 1513 **/ 1514 PetscErrorCode MatGetDiagonal_Ceed(Mat A, Vec D) { 1515 PetscMemType mem_type; 1516 Vec D_loc; 1517 MatCeedContext ctx; 1518 1519 PetscFunctionBeginUser; 1520 PetscCall(MatShellGetContext(A, &ctx)); 1521 1522 // Place PETSc vector in libCEED vector 1523 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL)); 1524 PetscCall(DMGetLocalVector(ctx->dm_x, &D_loc)); 1525 PetscCall(VecPetscToCeed(D_loc, &mem_type, ctx->x_loc)); 1526 1527 // Compute Diagonal 1528 PetscCall(PetscLogEventBegin(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL)); 1529 PetscCallCeed(ctx->ceed, CeedOperatorLinearAssembleDiagonal(ctx->op_mult, ctx->x_loc, CEED_REQUEST_IMMEDIATE)); 1530 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL_CEEDOP, A, D, NULL, NULL)); 1531 1532 // Restore PETSc vector 1533 PetscCall(VecCeedToPetsc(ctx->x_loc, mem_type, D_loc)); 1534 1535 // Local-to-Global 1536 PetscCall(VecZeroEntries(D)); 1537 PetscCall(DMLocalToGlobal(ctx->dm_x, D_loc, ADD_VALUES, D)); 1538 PetscCall(DMRestoreLocalVector(ctx->dm_x, &D_loc)); 1539 PetscCall(PetscLogEventEnd(MATCEED_ASSEMBLE_DIAGONAL, A, D, NULL, NULL)); 1540 PetscFunctionReturn(PETSC_SUCCESS); 1541 } 1542 1543 /** 1544 @brief Compute `A X = Y` for a `MATCEED`. 1545 1546 Collective across MPI processes. 1547 1548 @param[in] A `MATCEED` 1549 @param[in] X Input PETSc vector 1550 @param[out] Y Output PETSc vector 1551 1552 @return An error code: 0 - success, otherwise - failure 1553 **/ 1554 PetscErrorCode MatMult_Ceed(Mat A, Vec X, Vec Y) { 1555 MatCeedContext ctx; 1556 1557 PetscFunctionBeginUser; 1558 PetscCall(MatShellGetContext(A, &ctx)); 1559 PetscCall(PetscLogEventBegin(ctx->log_event_mult, A, X, Y, NULL)); 1560 1561 { 1562 PetscMemType x_mem_type, y_mem_type; 1563 Vec X_loc = ctx->X_loc, Y_loc; 1564 1565 // Get local vectors 1566 if (!ctx->X_loc) PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc)); 1567 PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc)); 1568 1569 // Global-to-local 1570 PetscCall(DMGlobalToLocal(ctx->dm_x, X, INSERT_VALUES, X_loc)); 1571 1572 // Setup libCEED vectors 1573 PetscCall(VecReadPetscToCeed(X_loc, &x_mem_type, ctx->x_loc)); 1574 PetscCall(VecZeroEntries(Y_loc)); 1575 PetscCall(VecPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc)); 1576 1577 // Apply libCEED operator 1578 PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult, A, X, Y, NULL)); 1579 PetscCall(PetscLogGpuTimeBegin()); 1580 PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult, ctx->x_loc, ctx->y_loc, CEED_REQUEST_IMMEDIATE)); 1581 PetscCall(PetscLogGpuTimeEnd()); 1582 PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult, A, X, Y, NULL)); 1583 1584 // Restore PETSc vectors 1585 PetscCall(VecReadCeedToPetsc(ctx->x_loc, x_mem_type, X_loc)); 1586 PetscCall(VecCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc)); 1587 1588 // Local-to-global 1589 PetscCall(VecZeroEntries(Y)); 1590 PetscCall(DMLocalToGlobal(ctx->dm_y, Y_loc, ADD_VALUES, Y)); 1591 1592 // Restore local vectors, as needed 1593 if (!ctx->X_loc) PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc)); 1594 PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc)); 1595 } 1596 1597 // Log flops 1598 if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult)); 1599 else PetscCall(PetscLogFlops(ctx->flops_mult)); 1600 PetscCall(PetscLogEventEnd(ctx->log_event_mult, A, X, Y, NULL)); 1601 PetscFunctionReturn(PETSC_SUCCESS); 1602 } 1603 1604 /** 1605 @brief Compute `A^T Y = X` for a `MATCEED`. 1606 1607 Collective across MPI processes. 1608 1609 @param[in] A `MATCEED` 1610 @param[in] Y Input PETSc vector 1611 @param[out] X Output PETSc vector 1612 1613 @return An error code: 0 - success, otherwise - failure 1614 **/ 1615 PetscErrorCode MatMultTranspose_Ceed(Mat A, Vec Y, Vec X) { 1616 MatCeedContext ctx; 1617 1618 PetscFunctionBeginUser; 1619 PetscCall(MatShellGetContext(A, &ctx)); 1620 PetscCall(PetscLogEventBegin(ctx->log_event_mult_transpose, A, Y, X, NULL)); 1621 1622 { 1623 PetscMemType x_mem_type, y_mem_type; 1624 Vec X_loc, Y_loc = ctx->Y_loc_transpose; 1625 1626 // Get local vectors 1627 if (!ctx->Y_loc_transpose) PetscCall(DMGetLocalVector(ctx->dm_y, &Y_loc)); 1628 PetscCall(DMGetLocalVector(ctx->dm_x, &X_loc)); 1629 1630 // Global-to-local 1631 PetscCall(DMGlobalToLocal(ctx->dm_y, Y, INSERT_VALUES, Y_loc)); 1632 1633 // Setup libCEED vectors 1634 PetscCall(VecReadPetscToCeed(Y_loc, &y_mem_type, ctx->y_loc)); 1635 PetscCall(VecZeroEntries(X_loc)); 1636 PetscCall(VecPetscToCeed(X_loc, &x_mem_type, ctx->x_loc)); 1637 1638 // Apply libCEED operator 1639 PetscCall(PetscLogEventBegin(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL)); 1640 PetscCall(PetscLogGpuTimeBegin()); 1641 PetscCallCeed(ctx->ceed, CeedOperatorApplyAdd(ctx->op_mult_transpose, ctx->y_loc, ctx->x_loc, CEED_REQUEST_IMMEDIATE)); 1642 PetscCall(PetscLogGpuTimeEnd()); 1643 PetscCall(PetscLogEventEnd(ctx->log_event_ceed_mult_transpose, A, Y, X, NULL)); 1644 1645 // Restore PETSc vectors 1646 PetscCall(VecReadCeedToPetsc(ctx->y_loc, y_mem_type, Y_loc)); 1647 PetscCall(VecCeedToPetsc(ctx->x_loc, x_mem_type, X_loc)); 1648 1649 // Local-to-global 1650 PetscCall(VecZeroEntries(X)); 1651 PetscCall(DMLocalToGlobal(ctx->dm_x, X_loc, ADD_VALUES, X)); 1652 1653 // Restore local vectors, as needed 1654 if (!ctx->Y_loc_transpose) PetscCall(DMRestoreLocalVector(ctx->dm_y, &Y_loc)); 1655 PetscCall(DMRestoreLocalVector(ctx->dm_x, &X_loc)); 1656 } 1657 1658 // Log flops 1659 if (PetscMemTypeDevice(ctx->mem_type)) PetscCall(PetscLogGpuFlops(ctx->flops_mult_transpose)); 1660 else PetscCall(PetscLogFlops(ctx->flops_mult_transpose)); 1661 PetscCall(PetscLogEventEnd(ctx->log_event_mult_transpose, A, Y, X, NULL)); 1662 PetscFunctionReturn(PETSC_SUCCESS); 1663 } 1664