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