1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 2 #include <petsc/private/petscimpl.h> 3 4 typedef struct _n_PetscFE_Vec { 5 PetscFE scalar_fe; 6 PetscInt num_copies; 7 PetscBool interleave_basis; 8 PetscBool interleave_components; 9 } PetscFE_Vec; 10 11 static PetscErrorCode PetscFEDestroy_Vector(PetscFE fe) 12 { 13 PetscFE_Vec *v; 14 15 PetscFunctionBegin; 16 v = (PetscFE_Vec *)fe->data; 17 PetscCall(PetscFEDestroy(&v->scalar_fe)); 18 PetscCall(PetscFree(v)); 19 PetscFunctionReturn(PETSC_SUCCESS); 20 } 21 22 static PetscErrorCode PetscFEView_Vector_Ascii(PetscFE fe, PetscViewer v) 23 { 24 PetscInt dim, Nc, scalar_Nc; 25 PetscSpace basis = NULL; 26 PetscDualSpace dual = NULL; 27 PetscQuadrature quad = NULL; 28 PetscFE_Vec *vec; 29 PetscViewerFormat fmt; 30 31 PetscFunctionBegin; 32 vec = (PetscFE_Vec *)fe->data; 33 PetscCall(PetscFEGetSpatialDimension(fe, &dim)); 34 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 35 PetscCall(PetscFEGetNumComponents(vec->scalar_fe, &scalar_Nc)); 36 PetscCall(PetscFEGetBasisSpace(fe, &basis)); 37 PetscCall(PetscFEGetDualSpace(fe, &dual)); 38 PetscCall(PetscFEGetQuadrature(fe, &quad)); 39 PetscCall(PetscViewerGetFormat(v, &fmt)); 40 PetscCall(PetscViewerASCIIPushTab(v)); 41 if (scalar_Nc == 1) { 42 PetscCall(PetscViewerASCIIPrintf(v, "Vector Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components\n", dim, Nc)); 43 } else { 44 PetscCall(PetscViewerASCIIPrintf(v, "Vector Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components (%" PetscInt_FMT " copies of finite element with %" PetscInt_FMT " components)\n", dim, Nc, vec->num_copies, scalar_Nc)); 45 } 46 if (fmt == PETSC_VIEWER_ASCII_INFO_DETAIL) { 47 PetscCall(PetscViewerASCIIPrintf(v, "Original finite element:\n")); 48 PetscCall(PetscViewerASCIIPushTab(v)); 49 PetscCall(PetscFEView(vec->scalar_fe, v)); 50 PetscCall(PetscViewerASCIIPopTab(v)); 51 } 52 if (basis) PetscCall(PetscSpaceView(basis, v)); 53 if (dual) PetscCall(PetscDualSpaceView(dual, v)); 54 if (quad) PetscCall(PetscQuadratureView(quad, v)); 55 PetscCall(PetscViewerASCIIPopTab(v)); 56 PetscFunctionReturn(PETSC_SUCCESS); 57 } 58 59 static PetscErrorCode PetscFEView_Vector(PetscFE fe, PetscViewer v) 60 { 61 PetscBool iascii; 62 63 PetscFunctionBegin; 64 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii)); 65 if (iascii) PetscCall(PetscFEView_Vector_Ascii(fe, v)); 66 PetscFunctionReturn(PETSC_SUCCESS); 67 } 68 69 static PetscErrorCode PetscFESetUp_Vector(PetscFE fe) 70 { 71 PetscFE_Vec *v = (PetscFE_Vec *)fe->data; 72 PetscDualSpace dsp; 73 PetscInt n, Ncopies = v->num_copies; 74 PetscInt scalar_n; 75 PetscInt *d, *d_mapped; 76 PetscDualSpace_Sum *sum; 77 PetscBool is_sum; 78 79 PetscFunctionBegin; 80 PetscCall(PetscFESetUp(v->scalar_fe)); 81 PetscCall(PetscFEGetDimension(v->scalar_fe, &scalar_n)); 82 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 83 PetscCall(PetscObjectTypeCompare((PetscObject)dsp, PETSCDUALSPACESUM, &is_sum)); 84 PetscCheck(is_sum, PetscObjectComm((PetscObject)fe), PETSC_ERR_ARG_INCOMP, "Expected PETSCDUALSPACESUM dual space"); 85 sum = (PetscDualSpace_Sum *)dsp->data; 86 n = Ncopies * scalar_n; 87 PetscCall(PetscCalloc1(n * n, &fe->invV)); 88 PetscCall(PetscMalloc2(scalar_n, &d, scalar_n, &d_mapped)); 89 for (PetscInt i = 0; i < scalar_n; i++) d[i] = i; 90 for (PetscInt c = 0; c < Ncopies; c++) { 91 PetscCall(ISLocalToGlobalMappingApply(sum->all_rows[c], scalar_n, d, d_mapped)); 92 for (PetscInt i = 0; i < scalar_n; i++) { 93 PetscInt iw = d_mapped[i]; 94 PetscReal *row_w = &fe->invV[iw * n]; 95 const PetscReal *row_r = &v->scalar_fe->invV[i * scalar_n]; 96 PetscInt j0 = v->interleave_basis ? c : c * scalar_n; 97 PetscInt jstride = v->interleave_basis ? Ncopies : 1; 98 99 for (PetscInt j = 0; j < scalar_n; j++) row_w[j0 + j * jstride] = row_r[j]; 100 } 101 } 102 PetscCall(PetscFree2(d, d_mapped)); 103 104 PetscFunctionReturn(PETSC_SUCCESS); 105 } 106 107 static PetscErrorCode PetscFEGetDimension_Vector(PetscFE fe, PetscInt *dim) 108 { 109 PetscFE_Vec *v = (PetscFE_Vec *)fe->data; 110 111 PetscFunctionBegin; 112 PetscCall(PetscFEGetDimension(v->scalar_fe, dim)); 113 *dim *= v->num_copies; 114 PetscFunctionReturn(PETSC_SUCCESS); 115 } 116 117 static PetscErrorCode PetscFEVectorInsertTabulation(PetscFE fe, PetscInt npoints, const PetscReal points[], PetscInt k, PetscInt scalar_Nb, PetscInt scalar_point_stride, const PetscReal scalar_Tk[], PetscReal Tk[]) 118 { 119 PetscFE_Vec *v = (PetscFE_Vec *)fe->data; 120 PetscInt scalar_Nc; 121 PetscInt Nc; 122 PetscInt cdim; 123 PetscInt dblock; 124 PetscInt block; 125 PetscInt scalar_block; 126 127 PetscFunctionBegin; 128 PetscCall(PetscFEGetNumComponents(v->scalar_fe, &scalar_Nc)); 129 Nc = scalar_Nc * v->num_copies; 130 PetscCall(PetscFEGetSpatialDimension(v->scalar_fe, &cdim)); 131 dblock = PetscPowInt(cdim, k); 132 block = Nc * dblock; 133 scalar_block = scalar_Nc * dblock; 134 for (PetscInt p = 0; p < npoints; p++) { 135 const PetscReal *scalar_Tp = &scalar_Tk[p * scalar_point_stride]; 136 PetscReal *Tp = &Tk[p * scalar_point_stride * v->num_copies * v->num_copies]; 137 138 for (PetscInt j = 0; j < v->num_copies; j++) { 139 for (PetscInt scalar_i = 0; scalar_i < scalar_Nb; scalar_i++) { 140 PetscInt i = v->interleave_basis ? (scalar_i * v->num_copies + j) : (j * scalar_Nb + scalar_i); 141 const PetscReal *scalar_Ti = &scalar_Tp[scalar_i * scalar_block]; 142 PetscReal *Ti = &Tp[i * block]; 143 144 for (PetscInt scalar_c = 0; scalar_c < scalar_Nc; scalar_c++) { 145 PetscInt c = v->interleave_components ? (scalar_c * v->num_copies + j) : (j * scalar_Nc + scalar_c); 146 const PetscReal *scalar_Tc = &scalar_Ti[scalar_c * dblock]; 147 PetscReal *Tc = &Ti[c * dblock]; 148 149 PetscCall(PetscArraycpy(Tc, scalar_Tc, dblock)); 150 } 151 } 152 } 153 } 154 PetscFunctionReturn(PETSC_SUCCESS); 155 } 156 157 static PetscErrorCode PetscFECreateTabulation_Vector(PetscFE fe, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T) 158 { 159 PetscFE_Vec *v = (PetscFE_Vec *)fe->data; 160 PetscInt scalar_Nc; 161 PetscInt scalar_Nb; 162 PetscInt cdim; 163 PetscTabulation scalar_T; 164 165 PetscFunctionBegin; 166 PetscAssert(npoints == T->Nr * T->Np, PetscObjectComm((PetscObject)fe), PETSC_ERR_PLIB, "Expected to be able decode PetscFECreateTabulation() from PetscTabulation fields"); 167 PetscCall(PetscFECreateTabulation(v->scalar_fe, T->Nr, T->Np, points, K, &scalar_T)); 168 PetscCall(PetscFEGetNumComponents(v->scalar_fe, &scalar_Nc)); 169 PetscCall(PetscFEGetDimension(v->scalar_fe, &scalar_Nb)); 170 PetscCall(PetscFEGetSpatialDimension(v->scalar_fe, &cdim)); 171 for (PetscInt k = 0; k <= T->K; k++) { 172 PetscReal *Tk = T->T[k]; 173 const PetscReal *scalar_Tk = scalar_T->T[k]; 174 PetscInt dblock = PetscPowInt(cdim, k); 175 PetscInt scalar_block = scalar_Nc * dblock; 176 PetscInt scalar_point_stride = scalar_Nb * scalar_block; 177 178 if (v->interleave_basis) { 179 PetscCall(PetscFEVectorInsertTabulation(fe, npoints, points, k, scalar_Nb, scalar_point_stride, scalar_Tk, Tk)); 180 } else { 181 PetscDualSpace scalar_dsp; 182 PetscSection ref_section; 183 PetscInt pStart, pEnd; 184 185 PetscCall(PetscFEGetDualSpace(v->scalar_fe, &scalar_dsp)); 186 PetscCall(PetscDualSpaceGetSection(scalar_dsp, &ref_section)); 187 PetscCall(PetscSectionGetChart(ref_section, &pStart, &pEnd)); 188 for (PetscInt p = pStart; p < pEnd; p++) { 189 PetscInt dof, off; 190 PetscReal *Tp; 191 const PetscReal *scalar_Tp; 192 193 PetscCall(PetscSectionGetDof(ref_section, p, &dof)); 194 PetscCall(PetscSectionGetOffset(ref_section, p, &off)); 195 scalar_Tp = &scalar_Tk[off * scalar_block]; 196 Tp = &Tk[off * scalar_block * v->num_copies * v->num_copies]; 197 PetscCall(PetscFEVectorInsertTabulation(fe, npoints, points, k, dof, scalar_point_stride, scalar_Tp, Tp)); 198 } 199 } 200 } 201 PetscCall(PetscTabulationDestroy(&scalar_T)); 202 PetscFunctionReturn(PETSC_SUCCESS); 203 } 204 205 static PetscErrorCode PetscFECreatePointTrace_Vector(PetscFE fe, PetscInt refPoint, PetscFE *trFE) 206 { 207 PetscFE_Vec *v = (PetscFE_Vec *)fe->data; 208 PetscFE scalar_trFE; 209 const char *name; 210 211 PetscFunctionBegin; 212 PetscCall(PetscFECreatePointTrace(v->scalar_fe, refPoint, &scalar_trFE)); 213 PetscCall(PetscFECreateVector(scalar_trFE, v->num_copies, v->interleave_basis, v->interleave_components, trFE)); 214 PetscCall(PetscFEDestroy(&scalar_trFE)); 215 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 216 if (name) PetscCall(PetscFESetName(*trFE, name)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PETSC_INTERN PetscErrorCode PetscFEIntegrate_Basic(PetscDS, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]); 221 PETSC_INTERN PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS, PetscInt, PetscBdPointFunc, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]); 222 PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridResidual_Basic(PetscDS, PetscDS, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]); 223 PETSC_INTERN PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS, PetscWeakForm, PetscFEJacobianType, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]); 224 PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridJacobian_Basic(PetscDS, PetscDS, PetscFEJacobianType, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]); 225 226 static PetscErrorCode PetscFEInitialize_Vector(PetscFE fe) 227 { 228 PetscFunctionBegin; 229 fe->ops->setfromoptions = NULL; 230 fe->ops->setup = PetscFESetUp_Vector; 231 fe->ops->view = PetscFEView_Vector; 232 fe->ops->destroy = PetscFEDestroy_Vector; 233 fe->ops->getdimension = PetscFEGetDimension_Vector; 234 fe->ops->createpointtrace = PetscFECreatePointTrace_Vector; 235 fe->ops->createtabulation = PetscFECreateTabulation_Vector; 236 fe->ops->integrate = PetscFEIntegrate_Basic; 237 fe->ops->integratebd = PetscFEIntegrateBd_Basic; 238 fe->ops->integrateresidual = PetscFEIntegrateResidual_Basic; 239 fe->ops->integratebdresidual = PetscFEIntegrateBdResidual_Basic; 240 fe->ops->integratehybridresidual = PetscFEIntegrateHybridResidual_Basic; 241 fe->ops->integratejacobianaction = NULL; 242 fe->ops->integratejacobian = PetscFEIntegrateJacobian_Basic; 243 fe->ops->integratebdjacobian = PetscFEIntegrateBdJacobian_Basic; 244 fe->ops->integratehybridjacobian = PetscFEIntegrateHybridJacobian_Basic; 245 PetscFunctionReturn(PETSC_SUCCESS); 246 } 247 248 /*MC 249 PETSCFEVECTOR = "vector" - A vector-valued `PetscFE` object that is repeated copies 250 of the same underlying finite element. 251 252 Level: intermediate 253 254 .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`, `PETSCFEBASIC`, `PetscFECreateVector()` 255 M*/ 256 PETSC_EXTERN PetscErrorCode PetscFECreate_Vector(PetscFE fe) 257 { 258 PetscFE_Vec *v; 259 260 PetscFunctionBegin; 261 PetscValidHeaderSpecific(fe, PETSCFE_CLASSID, 1); 262 PetscCall(PetscNew(&v)); 263 fe->data = v; 264 265 PetscCall(PetscFEInitialize_Vector(fe)); 266 PetscFunctionReturn(PETSC_SUCCESS); 267 } 268 269 /*@ 270 PetscFECreateVector - Create a vector-valued `PetscFE` from multiple copies of an underlying 271 `PetscFE`. 272 273 Collective 274 275 Input Parameters: 276 + scalar_fe - a `PetscFE` finite element 277 . num_copies - a positive integer 278 . interleave_basis - if `PETSC_TRUE`, the first `num_copies` basis vectors 279 of the output finite element will be copies of the 280 first basis vector of `scalar_fe`, and so on for the 281 other basis vectors; otherwise all of the first-copy 282 basis vectors will come first, followed by all of the 283 second-copy, and so on. 284 - interleave_components - if `PETSC_TRUE`, the first `num_copies` components 285 of the output finite element will be copies of the 286 first component of `scalar_fe`, and so on for the 287 other components; otherwise all of the first-copy 288 components will come first, followed by all of the 289 second-copy, and so on. 290 291 Output Parameter: 292 . vector_fe - a `PetscFE` of type `PETSCFEVECTOR` that represent a discretization space with `num_copies` copies of `scalar_fe` 293 294 Level: intermediate 295 296 .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`, `PETSCFEBASIC`, `PETSCFEVECTOR` 297 @*/ 298 PetscErrorCode PetscFECreateVector(PetscFE scalar_fe, PetscInt num_copies, PetscBool interleave_basis, PetscBool interleave_components, PetscFE *vector_fe) 299 { 300 MPI_Comm comm; 301 PetscFE fe_vec; 302 PetscFE_Vec *v; 303 PetscInt scalar_Nc; 304 PetscQuadrature quad; 305 306 PetscFunctionBegin; 307 PetscValidHeaderSpecific(scalar_fe, PETSCFE_CLASSID, 1); 308 PetscCall(PetscObjectGetComm((PetscObject)scalar_fe, &comm)); 309 PetscCheck(num_copies >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Expected positive number of copies, got %" PetscInt_FMT, num_copies); 310 PetscCall(PetscFECreate(comm, vector_fe)); 311 fe_vec = *vector_fe; 312 PetscCall(PetscFESetType(fe_vec, PETSCFEVECTOR)); 313 v = (PetscFE_Vec *)fe_vec->data; 314 PetscCall(PetscObjectReference((PetscObject)scalar_fe)); 315 v->scalar_fe = scalar_fe; 316 v->num_copies = num_copies; 317 v->interleave_basis = interleave_basis; 318 v->interleave_components = interleave_components; 319 PetscCall(PetscFEGetNumComponents(scalar_fe, &scalar_Nc)); 320 PetscCall(PetscFESetNumComponents(fe_vec, scalar_Nc * num_copies)); 321 PetscCall(PetscFEGetQuadrature(scalar_fe, &quad)); 322 PetscCall(PetscFESetQuadrature(fe_vec, quad)); 323 PetscCall(PetscFEGetFaceQuadrature(scalar_fe, &quad)); 324 PetscCall(PetscFESetFaceQuadrature(fe_vec, quad)); 325 { 326 PetscSpace scalar_sp; 327 PetscSpace *copies; 328 PetscSpace sp; 329 330 PetscCall(PetscFEGetBasisSpace(scalar_fe, &scalar_sp)); 331 PetscCall(PetscMalloc1(num_copies, &copies)); 332 for (PetscInt i = 0; i < num_copies; i++) { 333 PetscCall(PetscObjectReference((PetscObject)scalar_sp)); 334 copies[i] = scalar_sp; 335 } 336 PetscCall(PetscSpaceCreateSum(num_copies, copies, PETSC_TRUE, &sp)); 337 PetscCall(PetscSpaceSumSetInterleave(sp, interleave_basis, interleave_components)); 338 PetscCall(PetscSpaceSetUp(sp)); 339 PetscCall(PetscFESetBasisSpace(fe_vec, sp)); 340 PetscCall(PetscSpaceDestroy(&sp)); 341 for (PetscInt i = 0; i < num_copies; i++) PetscCall(PetscSpaceDestroy(&copies[i])); 342 PetscCall(PetscFree(copies)); 343 } 344 { 345 PetscDualSpace scalar_sp; 346 PetscDualSpace *copies; 347 PetscDualSpace sp; 348 349 PetscCall(PetscFEGetDualSpace(scalar_fe, &scalar_sp)); 350 PetscCall(PetscMalloc1(num_copies, &copies)); 351 for (PetscInt i = 0; i < num_copies; i++) { 352 PetscCall(PetscObjectReference((PetscObject)scalar_sp)); 353 copies[i] = scalar_sp; 354 } 355 PetscCall(PetscDualSpaceCreateSum(num_copies, copies, PETSC_TRUE, &sp)); 356 PetscCall(PetscDualSpaceSumSetInterleave(sp, interleave_basis, interleave_components)); 357 PetscCall(PetscDualSpaceSetUp(sp)); 358 PetscCall(PetscFESetDualSpace(fe_vec, sp)); 359 PetscCall(PetscDualSpaceDestroy(&sp)); 360 for (PetscInt i = 0; i < num_copies; i++) PetscCall(PetscDualSpaceDestroy(&copies[i])); 361 PetscCall(PetscFree(copies)); 362 } 363 PetscFunctionReturn(PETSC_SUCCESS); 364 } 365