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