static char help[] = "Tests affine subspaces.\n\n"; #include #include #include int main(int argc, char **argv) { DM dm; PetscFE fe; PetscSpace space; PetscDualSpace dualspace, dualsubspace; PetscInt dim = 2, Nc = 3, cStart, cEnd; PetscBool simplex = PETSC_TRUE; MPI_Comm comm; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); comm = PETSC_COMM_WORLD; PetscOptionsBegin(comm, "", "Options for subspace test", "none"); PetscCall(PetscOptionsRangeInt("-dim", "The spatial dimension", "ex5.c", dim, &dim, NULL, 1, 3)); PetscCall(PetscOptionsBool("-simplex", "Test simplex element", "ex5.c", simplex, &simplex, NULL)); PetscCall(PetscOptionsBoundedInt("-num_comp", "Number of components in space", "ex5.c", Nc, &Nc, NULL, 1)); PetscOptionsEnd(); PetscCall(DMShellCreate(comm, &dm)); PetscCall(PetscFECreateDefault(comm, dim, Nc, simplex, NULL, PETSC_DEFAULT, &fe)); PetscCall(DMDestroy(&dm)); PetscCall(PetscFESetName(fe, "solution")); PetscCall(PetscFEGetBasisSpace(fe, &space)); PetscCall(PetscSpaceGetNumComponents(space, &Nc)); PetscCall(PetscFEGetDualSpace(fe, &dualspace)); PetscCall(PetscDualSpaceGetHeightSubspace(dualspace, 1, &dualsubspace)); PetscCall(PetscDualSpaceGetDM(dualspace, &dm)); PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); if (cEnd > cStart) { PetscInt coneSize; PetscCall(DMPlexGetConeSize(dm, cStart, &coneSize)); if (coneSize) { PetscFE traceFE; const PetscInt *cone; PetscInt point, nSub, nFull; PetscReal xi0[3] = {-1., -1., -1.}; PetscScalar *outSub, *outFull; PetscReal *testSub, *testFull; PetscTabulation Tsub, Tfull; PetscReal J[9], detJ; PetscInt i, j; PetscSection sectionFull; Vec vecFull; PetscScalar *arrayFull, *arraySub; PetscReal err; PetscRandom rand; PetscCall(DMPlexGetCone(dm, cStart, &cone)); point = cone[0]; PetscCall(PetscFECreatePointTrace(fe, point, &traceFE)); PetscCall(PetscFESetUp(traceFE)); PetscCall(PetscFEViewFromOptions(traceFE, NULL, "-trace_fe_view")); PetscCall(PetscMalloc4(dim - 1, &testSub, dim, &testFull, Nc, &outSub, Nc, &outFull)); PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &rand)); PetscCall(PetscRandomSetFromOptions(rand)); PetscCall(PetscRandomSetInterval(rand, -1., 1.)); /* create a random point in the trace domain */ for (i = 0; i < dim - 1; i++) PetscCall(PetscRandomGetValueReal(rand, &testSub[i])); PetscCall(DMPlexComputeCellGeometryFEM(dm, point, NULL, testFull, J, NULL, &detJ)); /* project it into the full domain */ for (i = 0; i < dim; i++) { for (j = 0; j < dim - 1; j++) testFull[i] += J[i * dim + j] * (testSub[j] - xi0[j]); } /* create a random vector in the full domain */ PetscCall(PetscFEGetDimension(fe, &nFull)); PetscCall(VecCreateSeq(PETSC_COMM_SELF, nFull, &vecFull)); PetscCall(VecGetArray(vecFull, &arrayFull)); for (i = 0; i < nFull; i++) PetscCall(PetscRandomGetValue(rand, &arrayFull[i])); PetscCall(VecRestoreArray(vecFull, &arrayFull)); /* create a vector on the trace domain */ PetscCall(PetscFEGetDimension(traceFE, &nSub)); /* get the subset of the original finite element space that is supported on the trace space */ PetscCall(PetscDualSpaceGetSection(dualspace, §ionFull)); PetscCall(PetscSectionSetUp(sectionFull)); /* get the trace degrees of freedom */ PetscCall(PetscMalloc1(nSub, &arraySub)); PetscCall(DMPlexVecGetClosure(dm, sectionFull, vecFull, point, &nSub, &arraySub)); /* get the tabulations */ PetscCall(PetscFECreateTabulation(traceFE, 1, 1, testSub, 0, &Tsub)); PetscCall(PetscFECreateTabulation(fe, 1, 1, testFull, 0, &Tfull)); for (i = 0; i < Nc; i++) { outSub[i] = 0.0; for (j = 0; j < nSub; j++) outSub[i] += Tsub->T[0][j * Nc + i] * arraySub[j]; } PetscCall(VecGetArray(vecFull, &arrayFull)); err = 0.0; for (i = 0; i < Nc; i++) { PetscScalar diff; outFull[i] = 0.0; for (j = 0; j < nFull; j++) outFull[i] += Tfull->T[0][j * Nc + i] * arrayFull[j]; diff = outFull[i] - outSub[i]; err += PetscRealPart(PetscConj(diff) * diff); } err = PetscSqrtReal(err); PetscCheck(err <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Trace FE error %g", (double)err); PetscCall(VecRestoreArray(vecFull, &arrayFull)); PetscCall(PetscTabulationDestroy(&Tfull)); PetscCall(PetscTabulationDestroy(&Tsub)); /* clean up */ PetscCall(PetscFree(arraySub)); PetscCall(VecDestroy(&vecFull)); PetscCall(PetscRandomDestroy(&rand)); PetscCall(PetscFree4(testSub, testFull, outSub, outFull)); PetscCall(PetscFEDestroy(&traceFE)); } } PetscCall(PetscFEDestroy(&fe)); PetscCall(PetscFinalize()); return 0; } /*TEST test: suffix: 0 args: -petscspace_degree 1 -trace_fe_view TEST*/