1 // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors. 2 // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause 3 4 #include <navierstokes.h> 5 6 #include <petscsection.h> 7 #include "../qfunctions/setupgeo.h" 8 #include "../qfunctions/setupgeo2d.h" 9 10 static CeedVector *q_data_vecs; 11 static CeedElemRestriction *q_data_restrictions; 12 static PetscInt num_q_data_stored; 13 14 /** 15 @brief Get stored QData objects that match created objects, if present 16 17 If created objects are not present, they are added to the storage and returned in the output 18 19 Not Collective 20 21 @param[in] q_data_created Vector with created QData 22 @param[in] elem_restr_qd_created Restriction for created QData 23 @param[out] q_data_stored Vector from storage matching QData 24 @param[out] elem_restr_qd_stored Restriction from storage matching QData 25 **/ 26 static PetscErrorCode QDataGetStored(CeedVector q_data_created, CeedElemRestriction elem_restr_qd_created, CeedVector *q_data_stored, 27 CeedElemRestriction *elem_restr_qd_stored) { 28 Ceed ceed = CeedVectorReturnCeed(q_data_created); 29 CeedSize created_length, stored_length; 30 PetscInt q_data_stored_index = -1; 31 32 PetscFunctionBeginUser; 33 PetscCallCeed(ceed, CeedVectorGetLength(q_data_created, &created_length)); 34 for (PetscInt i = 0; i < num_q_data_stored; i++) { 35 CeedVector difference_cvec; 36 CeedScalar max_difference; 37 38 PetscCallCeed(ceed, CeedVectorGetLength(q_data_vecs[0], &stored_length)); 39 if (created_length != stored_length) continue; 40 PetscCallCeed(ceed, CeedVectorCreate(ceed, stored_length, &difference_cvec)); 41 PetscCallCeed(ceed, CeedVectorCopy(q_data_vecs[i], difference_cvec)); 42 PetscCallCeed(ceed, CeedVectorAXPY(difference_cvec, -1, q_data_created)); 43 PetscCallCeed(ceed, CeedVectorNorm(difference_cvec, CEED_NORM_MAX, &max_difference)); 44 PetscCallCeed(ceed, CeedVectorDestroy(&difference_cvec)); 45 if (max_difference < 100 * CEED_EPSILON) { 46 q_data_stored_index = i; 47 break; 48 } 49 } 50 51 if (q_data_stored_index == -1) { 52 q_data_stored_index = num_q_data_stored++; 53 54 PetscCall(PetscRealloc(num_q_data_stored * sizeof(CeedVector), &q_data_vecs)); 55 PetscCall(PetscRealloc(num_q_data_stored * sizeof(CeedElemRestriction), &q_data_restrictions)); 56 q_data_vecs[q_data_stored_index] = NULL; // Must set to NULL for ReferenceCopy 57 q_data_restrictions[q_data_stored_index] = NULL; // Must set to NULL for ReferenceCopy 58 PetscCallCeed(ceed, CeedVectorReferenceCopy(q_data_created, &q_data_vecs[q_data_stored_index])); 59 PetscCallCeed(ceed, CeedElemRestrictionReferenceCopy(elem_restr_qd_created, &q_data_restrictions[q_data_stored_index])); 60 } 61 *q_data_stored = NULL; // Must set to NULL for ReferenceCopy 62 *elem_restr_qd_stored = NULL; // Must set to NULL for ReferenceCopy 63 PetscCallCeed(ceed, CeedVectorReferenceCopy(q_data_vecs[q_data_stored_index], q_data_stored)); 64 PetscCallCeed(ceed, CeedElemRestrictionReferenceCopy(q_data_restrictions[q_data_stored_index], elem_restr_qd_stored)); 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /** 69 @brief Clear stored QData objects 70 **/ 71 PetscErrorCode QDataClearStoredData() { 72 PetscFunctionBeginUser; 73 for (PetscInt i = 0; i < num_q_data_stored; i++) { 74 Ceed ceed = CeedVectorReturnCeed(q_data_vecs[i]); 75 76 PetscCallCeed(ceed, CeedVectorDestroy(&q_data_vecs[i])); 77 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&q_data_restrictions[i])); 78 } 79 PetscCall(PetscFree(q_data_vecs)); 80 PetscCall(PetscFree(q_data_restrictions)); 81 q_data_vecs = NULL; 82 q_data_restrictions = NULL; 83 PetscFunctionReturn(PETSC_SUCCESS); 84 } 85 86 /** 87 * @brief Get number of components of quadrature data for domain 88 * 89 * @param[in] dm DM where quadrature data would be used 90 * @param[out] q_data_size Number of components of quadrature data 91 */ 92 PetscErrorCode QDataGetNumComponents(DM dm, CeedInt *q_data_size) { 93 PetscInt num_comp_x, dim; 94 95 PetscFunctionBeginUser; 96 PetscCall(DMGetDimension(dm, &dim)); 97 { // Get number of coordinate components 98 DM dm_coord; 99 PetscSection section_coord; 100 PetscInt field = 0; // Default field has the coordinates 101 102 PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 103 PetscCall(DMGetLocalSection(dm_coord, §ion_coord)); 104 PetscCall(PetscSectionGetFieldComponents(section_coord, field, &num_comp_x)); 105 } 106 *q_data_size = 0; 107 switch (dim) { 108 case 2: 109 switch (num_comp_x) { 110 case 2: 111 *q_data_size = 5; 112 break; 113 case 3: 114 *q_data_size = 7; 115 break; 116 } 117 break; 118 case 3: 119 *q_data_size = 10; 120 break; 121 } 122 PetscCheck(*q_data_size, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, 123 "QData not valid for DM of dimension %" PetscInt_FMT " and coordinates with dimension %" PetscInt_FMT, dim, num_comp_x); 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 /** 128 * @brief Create quadrature data for domain 129 * 130 * @param[in] ceed Ceed object quadrature data will be used with 131 * @param[in] dm DM where quadrature data would be used 132 * @param[in] domain_label DMLabel that quadrature data would be used one 133 * @param[in] label_value Value of label 134 * @param[in] elem_restr_x CeedElemRestriction of the coordinates (must match `domain_label` and `label_value` selections) 135 * @param[in] basis_x CeedBasis of the coordinates 136 * @param[in] x_coord CeedVector of the coordinates 137 * @param[out] elem_restr_qd CeedElemRestriction of the quadrature data 138 * @param[out] q_data CeedVector of the quadrature data 139 * @param[out] q_data_size Number of components of quadrature data 140 */ 141 PetscErrorCode QDataGet(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, CeedElemRestriction elem_restr_x, CeedBasis basis_x, 142 CeedVector x_coord, CeedElemRestriction *elem_restr_qd, CeedVector *q_data, CeedInt *q_data_size) { 143 CeedQFunction qf_setup = NULL; 144 CeedOperator op_setup; 145 CeedVector q_data_created; 146 CeedElemRestriction elem_restr_qd_created; 147 CeedInt num_comp_x; 148 PetscInt dim, height = 0; 149 150 PetscFunctionBeginUser; 151 PetscCall(QDataGetNumComponents(dm, q_data_size)); 152 PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(elem_restr_x, &num_comp_x)); 153 PetscCall(DMGetDimension(dm, &dim)); 154 switch (dim) { 155 case 2: 156 switch (num_comp_x) { 157 case 2: 158 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, Setup2d, Setup2d_loc, &qf_setup)); 159 break; 160 case 3: 161 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, Setup2D_3Dcoords, Setup2D_3Dcoords_loc, &qf_setup)); 162 break; 163 } 164 break; 165 case 3: 166 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, Setup, Setup_loc, &qf_setup)); 167 break; 168 } 169 PetscCheck(qf_setup, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "%s not valid for DM of dimension %" PetscInt_FMT, __func__, dim); 170 171 // -- Create QFunction for quadrature data 172 PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(qf_setup, 0)); 173 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup, "dx", num_comp_x * (dim - height), CEED_EVAL_GRAD)); 174 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup, "weight", 1, CEED_EVAL_WEIGHT)); 175 PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_setup, "surface qdata", *q_data_size, CEED_EVAL_NONE)); 176 177 PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, dm, domain_label, label_value, height, *q_data_size, &elem_restr_qd_created)); 178 PetscCallCeed(ceed, CeedElemRestrictionCreateVector(elem_restr_qd_created, &q_data_created, NULL)); 179 180 PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_setup, NULL, NULL, &op_setup)); 181 PetscCallCeed(ceed, CeedOperatorSetField(op_setup, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE)); 182 PetscCallCeed(ceed, CeedOperatorSetField(op_setup, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE)); 183 PetscCallCeed(ceed, CeedOperatorSetField(op_setup, "surface qdata", elem_restr_qd_created, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE)); 184 185 PetscCallCeed(ceed, CeedOperatorApply(op_setup, x_coord, q_data_created, CEED_REQUEST_IMMEDIATE)); 186 187 PetscCall(QDataGetStored(q_data_created, elem_restr_qd_created, q_data, elem_restr_qd)); 188 189 PetscCallCeed(ceed, CeedVectorDestroy(&q_data_created)); 190 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd_created)); 191 PetscCallCeed(ceed, CeedOperatorDestroy(&op_setup)); 192 PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_setup)); 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 /** 197 * @brief Get number of components of quadrature data for boundary of domain 198 * 199 * @param[in] dm DM where quadrature data would be used 200 * @param[out] q_data_size Number of components of quadrature data 201 */ 202 PetscErrorCode QDataBoundaryGetNumComponents(DM dm, CeedInt *q_data_size) { 203 PetscInt dim; 204 205 PetscFunctionBeginUser; 206 PetscCall(DMGetDimension(dm, &dim)); 207 *q_data_size = 0; 208 switch (dim) { 209 case 2: 210 *q_data_size = 3; 211 break; 212 case 3: 213 *q_data_size = 10; 214 break; 215 } 216 PetscCheck(*q_data_size, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "%s not valid for DM of dimension %" PetscInt_FMT, __func__, dim); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 /** 221 * @brief Create quadrature data for boundary of domain 222 * 223 * @param[in] ceed Ceed object quadrature data will be used with 224 * @param[in] dm DM where quadrature data would be used 225 * @param[in] domain_label DMLabel that quadrature data would be used one 226 * @param[in] label_value Value of label 227 * @param[in] elem_restr_x CeedElemRestriction of the coordinates (must match `domain_label` and `label_value` selections) 228 * @param[in] basis_x CeedBasis of the coordinates 229 * @param[in] x_coord CeedVector of the coordinates 230 * @param[out] elem_restr_qd CeedElemRestriction of the quadrature data 231 * @param[out] q_data CeedVector of the quadrature data 232 * @param[out] q_data_size Number of components of quadrature data 233 */ 234 PetscErrorCode QDataBoundaryGet(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, CeedElemRestriction elem_restr_x, CeedBasis basis_x, 235 CeedVector x_coord, CeedElemRestriction *elem_restr_qd, CeedVector *q_data, CeedInt *q_data_size) { 236 CeedQFunction qf_setup_sur = NULL; 237 CeedOperator op_setup_sur; 238 CeedVector q_data_created; 239 CeedElemRestriction elem_restr_qd_created; 240 CeedInt num_comp_x; 241 PetscInt dim, height = 1; 242 243 PetscFunctionBeginUser; 244 PetscCall(QDataBoundaryGetNumComponents(dm, q_data_size)); 245 PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(elem_restr_x, &num_comp_x)); 246 PetscCall(DMGetDimension(dm, &dim)); 247 switch (dim) { 248 case 2: 249 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, SetupBoundary2d, SetupBoundary2d_loc, &qf_setup_sur)); 250 break; 251 case 3: 252 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, SetupBoundary, SetupBoundary_loc, &qf_setup_sur)); 253 break; 254 } 255 PetscCheck(qf_setup_sur, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "%s not valid for DM of dimension %" PetscInt_FMT, __func__, dim); 256 257 // -- Create QFunction for quadrature data 258 PetscCallCeed(ceed, CeedQFunctionSetUserFlopsEstimate(qf_setup_sur, 0)); 259 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup_sur, "dx", num_comp_x * (dim - height), CEED_EVAL_GRAD)); 260 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup_sur, "weight", 1, CEED_EVAL_WEIGHT)); 261 PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_setup_sur, "surface qdata", *q_data_size, CEED_EVAL_NONE)); 262 263 PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, dm, domain_label, label_value, height, *q_data_size, &elem_restr_qd_created)); 264 PetscCallCeed(ceed, CeedElemRestrictionCreateVector(elem_restr_qd_created, &q_data_created, NULL)); 265 266 PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_setup_sur, NULL, NULL, &op_setup_sur)); 267 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "dx", elem_restr_x, basis_x, CEED_VECTOR_ACTIVE)); 268 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE)); 269 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "surface qdata", elem_restr_qd_created, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE)); 270 271 PetscCallCeed(ceed, CeedOperatorApply(op_setup_sur, x_coord, q_data_created, CEED_REQUEST_IMMEDIATE)); 272 273 PetscCall(QDataGetStored(q_data_created, elem_restr_qd_created, q_data, elem_restr_qd)); 274 275 PetscCallCeed(ceed, CeedVectorDestroy(&q_data_created)); 276 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd_created)); 277 PetscCallCeed(ceed, CeedOperatorDestroy(&op_setup_sur)); 278 PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_setup_sur)); 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 282 /** 283 * @brief Get number of components of quadrature data for boundary of domain 284 * 285 * @param[in] dm DM where quadrature data would be used 286 * @param[out] q_data_size Number of components of quadrature data 287 */ 288 PetscErrorCode QDataBoundaryGradientGetNumComponents(DM dm, CeedInt *q_data_size) { 289 PetscInt dim; 290 291 PetscFunctionBeginUser; 292 PetscCall(DMGetDimension(dm, &dim)); 293 *q_data_size = 0; 294 switch (dim) { 295 case 2: 296 *q_data_size = 7; 297 break; 298 case 3: 299 *q_data_size = 13; 300 break; 301 } 302 PetscCheck(*q_data_size, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "%s not valid for DM of dimension %" PetscInt_FMT, __func__, dim); 303 PetscFunctionReturn(PETSC_SUCCESS); 304 } 305 306 /** 307 @brief Compute `CeedOperator` surface gradient QData 308 309 Collective across MPI processes. 310 311 @param[in] ceed `Ceed` object 312 @param[in] dm `DMPlex` grid 313 @param[in] domain_label `DMLabel` for surface 314 @param[in] label_value `DMPlex` label value for surface 315 @param[in] x_coord `CeedVector` for coordinates 316 @param[out] elem_restr_qd `CeedElemRestriction` for QData 317 @param[out] q_data `CeedVector` holding QData 318 @param[out] q_data_size Number of QData components per quadrature point 319 **/ 320 PetscErrorCode QDataBoundaryGradientGet(Ceed ceed, DM dm, DMLabel domain_label, PetscInt label_value, CeedVector x_coord, 321 CeedElemRestriction *elem_restr_qd, CeedVector *q_data, CeedInt *q_data_size) { 322 PetscInt dim; 323 const PetscInt height_cell = 0, height_face = 1; 324 CeedInt num_comp_x; 325 CeedElemRestriction elem_restr_x_cell, elem_restr_x_face, elem_restr_qd_created; 326 CeedVector q_data_created; 327 CeedBasis basis_x_cell_to_face, basis_x_face; 328 CeedQFunction qf_setup_sur = NULL; 329 CeedOperator op_setup_sur; 330 331 PetscFunctionBeginUser; 332 PetscCall(CreateCoordinateBasisFromPlex(ceed, dm, domain_label, label_value, height_face, &basis_x_face)); 333 PetscCall(DMPlexCeedBasisCellToFaceCoordinateCreate(ceed, dm, domain_label, label_value, label_value, &basis_x_cell_to_face)); 334 PetscCall(DMPlexCeedElemRestrictionCoordinateCreate(ceed, dm, domain_label, label_value, height_cell, &elem_restr_x_cell)); 335 PetscCall(DMPlexCeedElemRestrictionCoordinateCreate(ceed, dm, domain_label, label_value, height_face, &elem_restr_x_face)); 336 337 PetscCall(QDataBoundaryGradientGetNumComponents(dm, q_data_size)); 338 PetscCall(DMPlexCeedElemRestrictionQDataCreate(ceed, dm, domain_label, label_value, height_face, *q_data_size, &elem_restr_qd_created)); 339 PetscCallCeed(ceed, CeedElemRestrictionCreateVector(elem_restr_qd_created, &q_data_created, NULL)); 340 PetscCallCeed(ceed, CeedElemRestrictionGetNumComponents(elem_restr_x_face, &num_comp_x)); 341 342 PetscCall(DMGetDimension(dm, &dim)); 343 switch (dim) { 344 case 2: 345 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, Setup2DBoundaryGradient, Setup2DBoundaryGradient_loc, &qf_setup_sur)); 346 break; 347 case 3: 348 PetscCallCeed(ceed, CeedQFunctionCreateInterior(ceed, 1, SetupBoundaryGradient, SetupBoundaryGradient_loc, &qf_setup_sur)); 349 break; 350 } 351 PetscCheck(qf_setup_sur, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "%s not valid for DM of dimension %" PetscInt_FMT, __func__, dim); 352 353 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup_sur, "dx/dX cell", num_comp_x * (dim - height_cell), CEED_EVAL_GRAD)); 354 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup_sur, "dx/dX face", num_comp_x * (dim - height_face), CEED_EVAL_GRAD)); 355 PetscCallCeed(ceed, CeedQFunctionAddInput(qf_setup_sur, "weight", 1, CEED_EVAL_WEIGHT)); 356 PetscCallCeed(ceed, CeedQFunctionAddOutput(qf_setup_sur, "q data", *q_data_size, CEED_EVAL_NONE)); 357 358 PetscCallCeed(ceed, CeedOperatorCreate(ceed, qf_setup_sur, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_setup_sur)); 359 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "dx/dX cell", elem_restr_x_cell, basis_x_cell_to_face, CEED_VECTOR_ACTIVE)); 360 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "dx/dX face", elem_restr_x_face, basis_x_face, CEED_VECTOR_ACTIVE)); 361 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "weight", CEED_ELEMRESTRICTION_NONE, basis_x_face, CEED_VECTOR_NONE)); 362 PetscCallCeed(ceed, CeedOperatorSetField(op_setup_sur, "q data", elem_restr_qd_created, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE)); 363 364 PetscCallCeed(ceed, CeedOperatorApply(op_setup_sur, x_coord, q_data_created, CEED_REQUEST_IMMEDIATE)); 365 366 PetscCall(QDataGetStored(q_data_created, elem_restr_qd_created, q_data, elem_restr_qd)); 367 368 PetscCallCeed(ceed, CeedOperatorDestroy(&op_setup_sur)); 369 PetscCallCeed(ceed, CeedQFunctionDestroy(&qf_setup_sur)); 370 PetscCallCeed(ceed, CeedVectorDestroy(&q_data_created)); 371 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_qd_created)); 372 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x_face)); 373 PetscCallCeed(ceed, CeedElemRestrictionDestroy(&elem_restr_x_cell)); 374 PetscCallCeed(ceed, CeedBasisDestroy(&basis_x_face)); 375 PetscCallCeed(ceed, CeedBasisDestroy(&basis_x_cell_to_face)); 376 PetscFunctionReturn(PETSC_SUCCESS); 377 } 378