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