xref: /petsc/src/dm/dt/space/impls/tensor/spacetensor.c (revision bcda9346efad4e5ba2d553af84eb238771ba1e25)
136e5648fSToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
236e5648fSToby Isaac 
PetscSpaceTensorCreateSubspace(PetscSpace space,PetscInt Nvs,PetscInt Ncs,PetscSpace * subspace)3d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorCreateSubspace(PetscSpace space, PetscInt Nvs, PetscInt Ncs, PetscSpace *subspace)
4d71ae5a4SJacob Faibussowitsch {
536e5648fSToby Isaac   PetscInt    degree;
636e5648fSToby Isaac   const char *prefix;
7417c287bSToby Isaac   const char *name;
8417c287bSToby Isaac   char        subname[PETSC_MAX_PATH_LEN];
936e5648fSToby Isaac 
1036e5648fSToby Isaac   PetscFunctionBegin;
119566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetDegree(space, &degree, NULL));
129566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)space, &prefix));
139566063dSJacob Faibussowitsch   PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)space), subspace));
149566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetType(*subspace, PETSCSPACEPOLYNOMIAL));
159566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumVariables(*subspace, Nvs));
169566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumComponents(*subspace, Ncs));
179566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetDegree(*subspace, degree, PETSC_DETERMINE));
189566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*subspace, prefix));
199566063dSJacob Faibussowitsch   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*subspace, "tensorcomp_"));
20417c287bSToby Isaac   if (((PetscObject)space)->name) {
219566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)space, &name));
229566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(subname, PETSC_MAX_PATH_LEN - 1, "%s tensor component", name));
239566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)*subspace, subname));
241baa6e33SBarry Smith   } else PetscCall(PetscObjectSetName((PetscObject)*subspace, "tensor component"));
253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2636e5648fSToby Isaac }
2736e5648fSToby Isaac 
PetscSpaceSetFromOptions_Tensor(PetscSpace sp,PetscOptionItems PetscOptionsObject)28ce78bad3SBarry Smith static PetscErrorCode PetscSpaceSetFromOptions_Tensor(PetscSpace sp, PetscOptionItems PetscOptionsObject)
29d71ae5a4SJacob Faibussowitsch {
3036e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
3136e5648fSToby Isaac   PetscInt           Ns, Nc, i, Nv, deg;
3236e5648fSToby Isaac   PetscBool          uniform = PETSC_TRUE;
3336e5648fSToby Isaac 
3436e5648fSToby Isaac   PetscFunctionBegin;
359566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumVariables(sp, &Nv));
363ba16761SJacob Faibussowitsch   if (!Nv) PetscFunctionReturn(PETSC_SUCCESS);
379566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumComponents(sp, &Nc));
389566063dSJacob Faibussowitsch   PetscCall(PetscSpaceTensorGetNumSubspaces(sp, &Ns));
399566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetDegree(sp, &deg, NULL));
4036e5648fSToby Isaac   if (Ns > 1) {
4136e5648fSToby Isaac     PetscSpace s0;
4236e5648fSToby Isaac 
439566063dSJacob Faibussowitsch     PetscCall(PetscSpaceTensorGetSubspace(sp, 0, &s0));
4436e5648fSToby Isaac     for (i = 1; i < Ns; i++) {
4536e5648fSToby Isaac       PetscSpace si;
4636e5648fSToby Isaac 
479566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorGetSubspace(sp, i, &si));
489371c9d4SSatish Balay       if (si != s0) {
499371c9d4SSatish Balay         uniform = PETSC_FALSE;
509371c9d4SSatish Balay         break;
519371c9d4SSatish Balay       }
5236e5648fSToby Isaac     }
5336e5648fSToby Isaac   }
5436e5648fSToby Isaac   Ns = (Ns == PETSC_DEFAULT) ? PetscMax(Nv, 1) : Ns;
55d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "PetscSpace tensor options");
569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscspace_tensor_spaces", "The number of subspaces", "PetscSpaceTensorSetNumSubspaces", Ns, &Ns, NULL, 0));
579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-petscspace_tensor_uniform", "Subspaces are identical", "PetscSpaceTensorSetFromOptions", uniform, &uniform, NULL));
58d0609cedSBarry Smith   PetscOptionsHeadEnd();
591dca8a05SBarry Smith   PetscCheck(Ns >= 0 && (Nv <= 0 || Ns != 0), PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a tensor space made up of %" PetscInt_FMT " spaces", Ns);
601dca8a05SBarry Smith   PetscCheck(Nv <= 0 || Ns <= Nv, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a tensor space with %" PetscInt_FMT " subspaces over %" PetscInt_FMT " variables", Ns, Nv);
619566063dSJacob Faibussowitsch   if (Ns != tens->numTensSpaces) PetscCall(PetscSpaceTensorSetNumSubspaces(sp, Ns));
6236e5648fSToby Isaac   if (uniform) {
6336e5648fSToby Isaac     PetscInt   Nvs = Nv / Ns;
64b3a91243SToby Isaac     PetscInt   Ncs;
6536e5648fSToby Isaac     PetscSpace subspace;
6636e5648fSToby Isaac 
6763a3b9bcSJacob Faibussowitsch     PetscCheck(Nv % Ns == 0, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Cannot use %" PetscInt_FMT " uniform subspaces for %" PetscInt_FMT " variable space", Ns, Nv);
68b3a91243SToby Isaac     Ncs = (PetscInt)PetscPowReal((PetscReal)Nc, 1. / Ns);
6963a3b9bcSJacob Faibussowitsch     PetscCheck(Nc % PetscPowInt(Ncs, Ns) == 0, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Cannot use %" PetscInt_FMT " uniform subspaces for %" PetscInt_FMT " component space", Ns, Nc);
709566063dSJacob Faibussowitsch     PetscCall(PetscSpaceTensorGetSubspace(sp, 0, &subspace));
719566063dSJacob Faibussowitsch     if (!subspace) PetscCall(PetscSpaceTensorCreateSubspace(sp, Nvs, Ncs, &subspace));
729566063dSJacob Faibussowitsch     else PetscCall(PetscObjectReference((PetscObject)subspace));
739566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetFromOptions(subspace));
749566063dSJacob Faibussowitsch     for (i = 0; i < Ns; i++) PetscCall(PetscSpaceTensorSetSubspace(sp, i, subspace));
759566063dSJacob Faibussowitsch     PetscCall(PetscSpaceDestroy(&subspace));
7636e5648fSToby Isaac   } else {
7736e5648fSToby Isaac     for (i = 0; i < Ns; i++) {
7836e5648fSToby Isaac       PetscSpace subspace;
7936e5648fSToby Isaac 
809566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorGetSubspace(sp, i, &subspace));
8136e5648fSToby Isaac       if (!subspace) {
8236e5648fSToby Isaac         char tprefix[128];
8336e5648fSToby Isaac 
849566063dSJacob Faibussowitsch         PetscCall(PetscSpaceTensorCreateSubspace(sp, 1, 1, &subspace));
85835f2295SStefano Zampini         PetscCall(PetscSNPrintf(tprefix, 128, "%" PetscInt_FMT "_", i));
869566063dSJacob Faibussowitsch         PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)subspace, tprefix));
871baa6e33SBarry Smith       } else PetscCall(PetscObjectReference((PetscObject)subspace));
889566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetFromOptions(subspace));
899566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorSetSubspace(sp, i, subspace));
909566063dSJacob Faibussowitsch       PetscCall(PetscSpaceDestroy(&subspace));
9136e5648fSToby Isaac     }
9236e5648fSToby Isaac   }
933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9436e5648fSToby Isaac }
9536e5648fSToby Isaac 
PetscSpaceTensorView_Ascii(PetscSpace sp,PetscViewer v)96d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorView_Ascii(PetscSpace sp, PetscViewer v)
97d71ae5a4SJacob Faibussowitsch {
9836e5648fSToby Isaac   PetscSpace_Tensor *tens    = (PetscSpace_Tensor *)sp->data;
9936e5648fSToby Isaac   PetscBool          uniform = PETSC_TRUE;
100c88cc932SToby Isaac   PetscInt           Ns      = tens->numTensSpaces, i, n;
10136e5648fSToby Isaac 
10236e5648fSToby Isaac   PetscFunctionBegin;
10336e5648fSToby Isaac   for (i = 1; i < Ns; i++) {
1049371c9d4SSatish Balay     if (tens->tensspaces[i] != tens->tensspaces[0]) {
1059371c9d4SSatish Balay       uniform = PETSC_FALSE;
1069371c9d4SSatish Balay       break;
1079371c9d4SSatish Balay     }
10836e5648fSToby Isaac   }
10963a3b9bcSJacob Faibussowitsch   if (uniform) PetscCall(PetscViewerASCIIPrintf(v, "Tensor space of %" PetscInt_FMT " subspaces (all identical)\n", Ns));
11063a3b9bcSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(v, "Tensor space of %" PetscInt_FMT " subspaces\n", Ns));
11136e5648fSToby Isaac   n = uniform ? 1 : Ns;
11236e5648fSToby Isaac   for (i = 0; i < n; i++) {
1139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
1149566063dSJacob Faibussowitsch     PetscCall(PetscSpaceView(tens->tensspaces[i], v));
1159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
11636e5648fSToby Isaac   }
1173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11836e5648fSToby Isaac }
11936e5648fSToby Isaac 
PetscSpaceView_Tensor(PetscSpace sp,PetscViewer viewer)120d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceView_Tensor(PetscSpace sp, PetscViewer viewer)
121d71ae5a4SJacob Faibussowitsch {
122*9f196a02SMartin Diehl   PetscBool isascii;
12336e5648fSToby Isaac 
12436e5648fSToby Isaac   PetscFunctionBegin;
125*9f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
126*9f196a02SMartin Diehl   if (isascii) PetscCall(PetscSpaceTensorView_Ascii(sp, viewer));
1273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12836e5648fSToby Isaac }
12936e5648fSToby Isaac 
PetscSpaceSetUp_Tensor(PetscSpace sp)130d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceSetUp_Tensor(PetscSpace sp)
131d71ae5a4SJacob Faibussowitsch {
13236e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
133b3a91243SToby Isaac   PetscInt           Nc, Nv, Ns;
13436e5648fSToby Isaac   PetscBool          uniform = PETSC_TRUE;
13536e5648fSToby Isaac   PetscInt           deg, maxDeg;
1362144e486SToby Isaac   PetscInt           Ncprod;
13736e5648fSToby Isaac 
13836e5648fSToby Isaac   PetscFunctionBegin;
139371d2eb7SMartin Diehl   if (tens->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
1409566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumVariables(sp, &Nv));
1419566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumComponents(sp, &Nc));
1429566063dSJacob Faibussowitsch   PetscCall(PetscSpaceTensorGetNumSubspaces(sp, &Ns));
14336e5648fSToby Isaac   if (Ns == PETSC_DEFAULT) {
14436e5648fSToby Isaac     Ns = Nv;
1459566063dSJacob Faibussowitsch     PetscCall(PetscSpaceTensorSetNumSubspaces(sp, Ns));
14636e5648fSToby Isaac   }
14736e5648fSToby Isaac   if (!Ns) {
148b3a91243SToby Isaac     SETERRQ(PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have zero subspaces");
14936e5648fSToby Isaac   } else {
150eae3dc7dSJacob Faibussowitsch     PetscSpace s0 = NULL;
15136e5648fSToby Isaac 
1521dca8a05SBarry Smith     PetscCheck(Nv <= 0 || Ns <= Nv, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a tensor space with %" PetscInt_FMT " subspaces over %" PetscInt_FMT " variables", Ns, Nv);
1539566063dSJacob Faibussowitsch     PetscCall(PetscSpaceTensorGetSubspace(sp, 0, &s0));
154b3a91243SToby Isaac     for (PetscInt i = 1; i < Ns; i++) {
15536e5648fSToby Isaac       PetscSpace si;
15636e5648fSToby Isaac 
1579566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorGetSubspace(sp, i, &si));
1589371c9d4SSatish Balay       if (si != s0) {
1599371c9d4SSatish Balay         uniform = PETSC_FALSE;
1609371c9d4SSatish Balay         break;
1619371c9d4SSatish Balay       }
16236e5648fSToby Isaac     }
16336e5648fSToby Isaac     if (uniform) {
16436e5648fSToby Isaac       PetscInt Nvs = Nv / Ns;
165b3a91243SToby Isaac       PetscInt Ncs;
16636e5648fSToby Isaac 
16763a3b9bcSJacob Faibussowitsch       PetscCheck(Nv % Ns == 0, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Cannot use %" PetscInt_FMT " uniform subspaces for %" PetscInt_FMT " variable space", Ns, Nv);
168b3a91243SToby Isaac       Ncs = (PetscInt)(PetscPowReal((PetscReal)Nc, 1. / Ns));
16963a3b9bcSJacob Faibussowitsch       PetscCheck(Nc % PetscPowInt(Ncs, Ns) == 0, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Cannot use %" PetscInt_FMT " uniform subspaces for %" PetscInt_FMT " component space", Ns, Nc);
1709566063dSJacob Faibussowitsch       if (!s0) PetscCall(PetscSpaceTensorCreateSubspace(sp, Nvs, Ncs, &s0));
1719566063dSJacob Faibussowitsch       else PetscCall(PetscObjectReference((PetscObject)s0));
1729566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(s0));
1739566063dSJacob Faibussowitsch       for (PetscInt i = 0; i < Ns; i++) PetscCall(PetscSpaceTensorSetSubspace(sp, i, s0));
1749566063dSJacob Faibussowitsch       PetscCall(PetscSpaceDestroy(&s0));
1752144e486SToby Isaac       Ncprod = PetscPowInt(Ncs, Ns);
17636e5648fSToby Isaac     } else {
177b3a91243SToby Isaac       PetscInt Nvsum = 0;
1782144e486SToby Isaac 
1792144e486SToby Isaac       Ncprod = 1;
180b3a91243SToby Isaac       for (PetscInt i = 0; i < Ns; i++) {
181b3a91243SToby Isaac         PetscInt   Nvs, Ncs;
182eae3dc7dSJacob Faibussowitsch         PetscSpace si = NULL;
18336e5648fSToby Isaac 
1849566063dSJacob Faibussowitsch         PetscCall(PetscSpaceTensorGetSubspace(sp, i, &si));
1859566063dSJacob Faibussowitsch         if (!si) PetscCall(PetscSpaceTensorCreateSubspace(sp, 1, 1, &si));
1869566063dSJacob Faibussowitsch         else PetscCall(PetscObjectReference((PetscObject)si));
1879566063dSJacob Faibussowitsch         PetscCall(PetscSpaceSetUp(si));
1889566063dSJacob Faibussowitsch         PetscCall(PetscSpaceTensorSetSubspace(sp, i, si));
1899566063dSJacob Faibussowitsch         PetscCall(PetscSpaceGetNumVariables(si, &Nvs));
1909566063dSJacob Faibussowitsch         PetscCall(PetscSpaceGetNumComponents(si, &Ncs));
1919566063dSJacob Faibussowitsch         PetscCall(PetscSpaceDestroy(&si));
192b3a91243SToby Isaac 
193b3a91243SToby Isaac         Nvsum += Nvs;
194b3a91243SToby Isaac         Ncprod *= Ncs;
19536e5648fSToby Isaac       }
196b3a91243SToby Isaac 
19763a3b9bcSJacob Faibussowitsch       PetscCheck(Nvsum == Nv, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Sum of subspace variables %" PetscInt_FMT " does not equal the number of variables %" PetscInt_FMT, Nvsum, Nv);
19863a3b9bcSJacob Faibussowitsch       PetscCheck(Nc % Ncprod == 0, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONG, "Product of subspace components %" PetscInt_FMT " does not divide the number of components %" PetscInt_FMT, Ncprod, Nc);
1992144e486SToby Isaac     }
2002144e486SToby Isaac     if (Ncprod != Nc) {
2012144e486SToby Isaac       PetscInt    Ncopies = Nc / Ncprod;
2022144e486SToby Isaac       PetscInt    Nv      = sp->Nv;
2032144e486SToby Isaac       const char *prefix;
2042144e486SToby Isaac       const char *name;
2052144e486SToby Isaac       char        subname[PETSC_MAX_PATH_LEN];
2062144e486SToby Isaac       PetscSpace  subsp;
2072144e486SToby Isaac 
2089566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)sp), &subsp));
2099566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)sp, &prefix));
2109566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)subsp, prefix));
2119566063dSJacob Faibussowitsch       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)subsp, "sumcomp_"));
2122144e486SToby Isaac       if (((PetscObject)sp)->name) {
2139566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetName((PetscObject)sp, &name));
2149566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(subname, PETSC_MAX_PATH_LEN - 1, "%s sum component", name));
2159566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)subsp, subname));
2161baa6e33SBarry Smith       } else PetscCall(PetscObjectSetName((PetscObject)subsp, "sum component"));
2179566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(subsp, PETSCSPACETENSOR));
2189566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(subsp, Nv));
2199566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(subsp, Ncprod));
2209566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorSetNumSubspaces(subsp, Ns));
2212144e486SToby Isaac       for (PetscInt i = 0; i < Ns; i++) {
2222144e486SToby Isaac         PetscSpace ssp;
2232144e486SToby Isaac 
2249566063dSJacob Faibussowitsch         PetscCall(PetscSpaceTensorGetSubspace(sp, i, &ssp));
2259566063dSJacob Faibussowitsch         PetscCall(PetscSpaceTensorSetSubspace(subsp, i, ssp));
2262144e486SToby Isaac       }
2279566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(subsp));
2289566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(sp, PETSCSPACESUM));
2299566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSumSetNumSubspaces(sp, Ncopies));
23048a46eb9SPierre Jolivet       for (PetscInt i = 0; i < Ncopies; i++) PetscCall(PetscSpaceSumSetSubspace(sp, i, subsp));
2319566063dSJacob Faibussowitsch       PetscCall(PetscSpaceDestroy(&subsp));
2329566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(sp));
2333ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
23436e5648fSToby Isaac     }
23536e5648fSToby Isaac   }
2361690c2aeSBarry Smith   deg    = PETSC_INT_MAX;
23736e5648fSToby Isaac   maxDeg = 0;
238b3a91243SToby Isaac   for (PetscInt i = 0; i < Ns; i++) {
23936e5648fSToby Isaac     PetscSpace si;
24036e5648fSToby Isaac     PetscInt   iDeg, iMaxDeg;
24136e5648fSToby Isaac 
2429566063dSJacob Faibussowitsch     PetscCall(PetscSpaceTensorGetSubspace(sp, i, &si));
2439566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDegree(si, &iDeg, &iMaxDeg));
24436e5648fSToby Isaac     deg = PetscMin(deg, iDeg);
24536e5648fSToby Isaac     maxDeg += iMaxDeg;
24636e5648fSToby Isaac   }
24736e5648fSToby Isaac   sp->degree        = deg;
24836e5648fSToby Isaac   sp->maxDegree     = maxDeg;
24936e5648fSToby Isaac   tens->uniform     = uniform;
250371d2eb7SMartin Diehl   tens->setupcalled = PETSC_TRUE;
2513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25236e5648fSToby Isaac }
25336e5648fSToby Isaac 
PetscSpaceDestroy_Tensor(PetscSpace sp)254d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceDestroy_Tensor(PetscSpace sp)
255d71ae5a4SJacob Faibussowitsch {
25636e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
25736e5648fSToby Isaac   PetscInt           Ns, i;
25836e5648fSToby Isaac 
25936e5648fSToby Isaac   PetscFunctionBegin;
260c88cc932SToby Isaac   Ns = tens->numTensSpaces;
261c88cc932SToby Isaac   if (tens->heightsubspaces) {
262d551817dSToby Isaac     PetscInt d;
263d551817dSToby Isaac 
264c88cc932SToby Isaac     /* sp->Nv is the spatial dimension, so it is equal to the number
265c88cc932SToby Isaac      * of subspaces on higher co-dimension points */
26648a46eb9SPierre Jolivet     for (d = 0; d < sp->Nv; ++d) PetscCall(PetscSpaceDestroy(&tens->heightsubspaces[d]));
267d551817dSToby Isaac   }
2689566063dSJacob Faibussowitsch   PetscCall(PetscFree(tens->heightsubspaces));
2699566063dSJacob Faibussowitsch   for (i = 0; i < Ns; i++) PetscCall(PetscSpaceDestroy(&tens->tensspaces[i]));
2709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorSetSubspace_C", NULL));
2719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorGetSubspace_C", NULL));
2729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorSetNumSubspaces_C", NULL));
2739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorGetNumSubspaces_C", NULL));
2749566063dSJacob Faibussowitsch   PetscCall(PetscFree(tens->tensspaces));
2759566063dSJacob Faibussowitsch   PetscCall(PetscFree(tens));
2763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27736e5648fSToby Isaac }
27836e5648fSToby Isaac 
PetscSpaceGetDimension_Tensor(PetscSpace sp,PetscInt * dim)279d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceGetDimension_Tensor(PetscSpace sp, PetscInt *dim)
280d71ae5a4SJacob Faibussowitsch {
28136e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
282b3a91243SToby Isaac   PetscInt           i, Ns, d;
28336e5648fSToby Isaac 
28436e5648fSToby Isaac   PetscFunctionBegin;
2859566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetUp(sp));
286c88cc932SToby Isaac   Ns = tens->numTensSpaces;
28736e5648fSToby Isaac   d  = 1;
28836e5648fSToby Isaac   for (i = 0; i < Ns; i++) {
28936e5648fSToby Isaac     PetscInt id;
29036e5648fSToby Isaac 
2919566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDimension(tens->tensspaces[i], &id));
29236e5648fSToby Isaac     d *= id;
29336e5648fSToby Isaac   }
29443bfef1cSToby Isaac   *dim = d;
2953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29636e5648fSToby Isaac }
29736e5648fSToby Isaac 
PetscSpaceEvaluate_Tensor(PetscSpace sp,PetscInt npoints,const PetscReal points[],PetscReal B[],PetscReal D[],PetscReal H[])298d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceEvaluate_Tensor(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[])
299d71ae5a4SJacob Faibussowitsch {
30036e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
30136e5648fSToby Isaac   DM                 dm   = sp->dm;
30236e5648fSToby Isaac   PetscInt           Nc   = sp->Nc;
30336e5648fSToby Isaac   PetscInt           Nv   = sp->Nv;
30436e5648fSToby Isaac   PetscInt           Ns;
30536e5648fSToby Isaac   PetscReal         *lpoints, *sB = NULL, *sD = NULL, *sH = NULL;
306b3a91243SToby Isaac   PetscInt           pdim;
30736e5648fSToby Isaac 
30836e5648fSToby Isaac   PetscFunctionBegin;
309371d2eb7SMartin Diehl   if (!tens->setupcalled) {
3109566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetUp(sp));
3119566063dSJacob Faibussowitsch     PetscCall(PetscSpaceEvaluate(sp, npoints, points, B, D, H));
3123ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
313b3a91243SToby Isaac   }
314c88cc932SToby Isaac   Ns = tens->numTensSpaces;
3159566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetDimension(sp, &pdim));
3169566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, npoints * Nv, MPIU_REAL, &lpoints));
3179566063dSJacob Faibussowitsch   if (B || D || H) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &sB));
3189566063dSJacob Faibussowitsch   if (D || H) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * Nv, MPIU_REAL, &sD));
3199566063dSJacob Faibussowitsch   if (H) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * Nv * Nv, MPIU_REAL, &sH));
32036e5648fSToby Isaac   if (B) {
321b3a91243SToby Isaac     for (PetscInt i = 0; i < npoints * pdim * Nc; i++) B[i] = 1.;
32236e5648fSToby Isaac   }
32336e5648fSToby Isaac   if (D) {
324b3a91243SToby Isaac     for (PetscInt i = 0; i < npoints * pdim * Nc * Nv; i++) D[i] = 1.;
32536e5648fSToby Isaac   }
32636e5648fSToby Isaac   if (H) {
327b3a91243SToby Isaac     for (PetscInt i = 0; i < npoints * pdim * Nc * Nv * Nv; i++) H[i] = 1.;
32836e5648fSToby Isaac   }
329b3a91243SToby Isaac   for (PetscInt s = 0, d = 0, vstep = 1, cstep = 1; s < Ns; s++) {
330b3a91243SToby Isaac     PetscInt sNv, sNc, spdim;
331b3a91243SToby Isaac     PetscInt vskip, cskip;
33236e5648fSToby Isaac 
3339566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetNumVariables(tens->tensspaces[s], &sNv));
3349566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetNumComponents(tens->tensspaces[s], &sNc));
3359566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDimension(tens->tensspaces[s], &spdim));
33663a3b9bcSJacob Faibussowitsch     PetscCheck(!(pdim % vstep) && !(pdim % spdim), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad tensor loop: Nv %" PetscInt_FMT ", Ns %" PetscInt_FMT ", pdim %" PetscInt_FMT ", s %" PetscInt_FMT ", vstep %" PetscInt_FMT ", spdim %" PetscInt_FMT, Nv, Ns, pdim, s, vstep, spdim);
33763a3b9bcSJacob Faibussowitsch     PetscCheck(!(Nc % cstep) && !(Nc % sNc), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad tensor loop: Nv %" PetscInt_FMT ", Ns %" PetscInt_FMT ", Nc %" PetscInt_FMT ", s %" PetscInt_FMT ", cstep %" PetscInt_FMT ", sNc %" PetscInt_FMT, Nv, Ns, Nc, s, cstep, spdim);
338b3a91243SToby Isaac     vskip = pdim / (vstep * spdim);
339b3a91243SToby Isaac     cskip = Nc / (cstep * sNc);
340b3a91243SToby Isaac     for (PetscInt p = 0; p < npoints; ++p) {
341ad540459SPierre Jolivet       for (PetscInt i = 0; i < sNv; i++) lpoints[p * sNv + i] = points[p * Nv + d + i];
34236e5648fSToby Isaac     }
3439566063dSJacob Faibussowitsch     PetscCall(PetscSpaceEvaluate(tens->tensspaces[s], npoints, lpoints, sB, sD, sH));
34436e5648fSToby Isaac     if (B) {
345b3a91243SToby Isaac       for (PetscInt k = 0; k < vskip; k++) {
346b3a91243SToby Isaac         for (PetscInt si = 0; si < spdim; si++) {
347b3a91243SToby Isaac           for (PetscInt j = 0; j < vstep; j++) {
348b3a91243SToby Isaac             PetscInt i = (k * spdim + si) * vstep + j;
349b3a91243SToby Isaac 
350b3a91243SToby Isaac             for (PetscInt l = 0; l < cskip; l++) {
351b3a91243SToby Isaac               for (PetscInt sc = 0; sc < sNc; sc++) {
352b3a91243SToby Isaac                 for (PetscInt m = 0; m < cstep; m++) {
353b3a91243SToby Isaac                   PetscInt c = (l * sNc + sc) * cstep + m;
354b3a91243SToby Isaac 
355ad540459SPierre Jolivet                   for (PetscInt p = 0; p < npoints; p++) B[(pdim * p + i) * Nc + c] *= sB[(spdim * p + si) * sNc + sc];
356b3a91243SToby Isaac                 }
357b3a91243SToby Isaac               }
35836e5648fSToby Isaac             }
35936e5648fSToby Isaac           }
36036e5648fSToby Isaac         }
36136e5648fSToby Isaac       }
36236e5648fSToby Isaac     }
36336e5648fSToby Isaac     if (D) {
364b3a91243SToby Isaac       for (PetscInt k = 0; k < vskip; k++) {
365b3a91243SToby Isaac         for (PetscInt si = 0; si < spdim; si++) {
366b3a91243SToby Isaac           for (PetscInt j = 0; j < vstep; j++) {
367b3a91243SToby Isaac             PetscInt i = (k * spdim + si) * vstep + j;
368b3a91243SToby Isaac 
369b3a91243SToby Isaac             for (PetscInt l = 0; l < cskip; l++) {
370b3a91243SToby Isaac               for (PetscInt sc = 0; sc < sNc; sc++) {
371b3a91243SToby Isaac                 for (PetscInt m = 0; m < cstep; m++) {
372b3a91243SToby Isaac                   PetscInt c = (l * sNc + sc) * cstep + m;
373b3a91243SToby Isaac 
374b3a91243SToby Isaac                   for (PetscInt der = 0; der < Nv; der++) {
37536e5648fSToby Isaac                     if (der >= d && der < d + sNv) {
376ad540459SPierre Jolivet                       for (PetscInt p = 0; p < npoints; p++) D[((pdim * p + i) * Nc + c) * Nv + der] *= sD[((spdim * p + si) * sNc + sc) * sNv + der - d];
37736e5648fSToby Isaac                     } else {
378ad540459SPierre Jolivet                       for (PetscInt p = 0; p < npoints; p++) D[((pdim * p + i) * Nc + c) * Nv + der] *= sB[(spdim * p + si) * sNc + sc];
379b3a91243SToby Isaac                     }
380b3a91243SToby Isaac                   }
38136e5648fSToby Isaac                 }
38236e5648fSToby Isaac               }
38336e5648fSToby Isaac             }
38436e5648fSToby Isaac           }
38536e5648fSToby Isaac         }
38636e5648fSToby Isaac       }
38736e5648fSToby Isaac     }
38836e5648fSToby Isaac     if (H) {
389b3a91243SToby Isaac       for (PetscInt k = 0; k < vskip; k++) {
390b3a91243SToby Isaac         for (PetscInt si = 0; si < spdim; si++) {
391b3a91243SToby Isaac           for (PetscInt j = 0; j < vstep; j++) {
392b3a91243SToby Isaac             PetscInt i = (k * spdim + si) * vstep + j;
393b3a91243SToby Isaac 
394b3a91243SToby Isaac             for (PetscInt l = 0; l < cskip; l++) {
395b3a91243SToby Isaac               for (PetscInt sc = 0; sc < sNc; sc++) {
396b3a91243SToby Isaac                 for (PetscInt m = 0; m < cstep; m++) {
397b3a91243SToby Isaac                   PetscInt c = (l * sNc + sc) * cstep + m;
398b3a91243SToby Isaac 
399b3a91243SToby Isaac                   for (PetscInt der = 0; der < Nv; der++) {
400b3a91243SToby Isaac                     for (PetscInt der2 = 0; der2 < Nv; der2++) {
40136e5648fSToby Isaac                       if (der >= d && der < d + sNv && der2 >= d && der2 < d + sNv) {
402ad540459SPierre Jolivet                         for (PetscInt p = 0; p < npoints; p++) H[(((pdim * p + i) * Nc + c) * Nv + der) * Nv + der2] *= sH[(((spdim * p + si) * sNc + sc) * sNv + der - d) * sNv + der2 - d];
40336e5648fSToby Isaac                       } else if (der >= d && der < d + sNv) {
404ad540459SPierre Jolivet                         for (PetscInt p = 0; p < npoints; p++) H[(((pdim * p + i) * Nc + c) * Nv + der) * Nv + der2] *= sD[((spdim * p + si) * sNc + sc) * sNv + der - d];
40536e5648fSToby Isaac                       } else if (der2 >= d && der2 < d + sNv) {
406ad540459SPierre Jolivet                         for (PetscInt p = 0; p < npoints; p++) H[(((pdim * p + i) * Nc + c) * Nv + der) * Nv + der2] *= sD[((spdim * p + si) * sNc + sc) * sNv + der2 - d];
40736e5648fSToby Isaac                       } else {
408ad540459SPierre Jolivet                         for (PetscInt p = 0; p < npoints; p++) H[(((pdim * p + i) * Nc + c) * Nv + der) * Nv + der2] *= sB[(spdim * p + si) * sNc + sc];
409b3a91243SToby Isaac                       }
410b3a91243SToby Isaac                     }
41136e5648fSToby Isaac                   }
41236e5648fSToby Isaac                 }
41336e5648fSToby Isaac               }
41436e5648fSToby Isaac             }
41536e5648fSToby Isaac           }
41636e5648fSToby Isaac         }
41736e5648fSToby Isaac       }
41836e5648fSToby Isaac     }
41936e5648fSToby Isaac     d += sNv;
420b3a91243SToby Isaac     vstep *= spdim;
421b3a91243SToby Isaac     cstep *= sNc;
42236e5648fSToby Isaac   }
4239566063dSJacob Faibussowitsch   if (H) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * Nv * Nv, MPIU_REAL, &sH));
4249566063dSJacob Faibussowitsch   if (D || H) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * Nv, MPIU_REAL, &sD));
4259566063dSJacob Faibussowitsch   if (B || D || H) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &sB));
4269566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, npoints * Nv, MPIU_REAL, &lpoints));
4273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42836e5648fSToby Isaac }
42936e5648fSToby Isaac 
43029b5c115SMatthew G. Knepley /*@
431b24fb147SBarry Smith   PetscSpaceTensorSetNumSubspaces - Set the number of spaces in the tensor product space
43229b5c115SMatthew G. Knepley 
43329b5c115SMatthew G. Knepley   Input Parameters:
43429b5c115SMatthew G. Knepley + sp            - the function space object
43529b5c115SMatthew G. Knepley - numTensSpaces - the number of spaces
43629b5c115SMatthew G. Knepley 
43729b5c115SMatthew G. Knepley   Level: intermediate
43829b5c115SMatthew G. Knepley 
439b24fb147SBarry Smith   Note:
440b24fb147SBarry Smith   The name NumSubspaces is misleading because it is actually setting the number of defining spaces of the tensor product space, not a number of Subspaces of it
441b24fb147SBarry Smith 
442dce8aebaSBarry Smith .seealso: `PETSCSPACETENSOR`, `PetscSpace`, `PetscSpaceTensorGetNumSubspaces()`, `PetscSpaceSetDegree()`, `PetscSpaceSetNumVariables()`
44329b5c115SMatthew G. Knepley @*/
PetscSpaceTensorSetNumSubspaces(PetscSpace sp,PetscInt numTensSpaces)444d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSpaceTensorSetNumSubspaces(PetscSpace sp, PetscInt numTensSpaces)
445d71ae5a4SJacob Faibussowitsch {
44636e5648fSToby Isaac   PetscFunctionBegin;
44736e5648fSToby Isaac   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
448cac4c232SBarry Smith   PetscTryMethod(sp, "PetscSpaceTensorSetNumSubspaces_C", (PetscSpace, PetscInt), (sp, numTensSpaces));
4493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45036e5648fSToby Isaac }
45136e5648fSToby Isaac 
45229b5c115SMatthew G. Knepley /*@
453b24fb147SBarry Smith   PetscSpaceTensorGetNumSubspaces - Get the number of spaces in the tensor product space
45429b5c115SMatthew G. Knepley 
45529b5c115SMatthew G. Knepley   Input Parameter:
45629b5c115SMatthew G. Knepley . sp - the function space object
45729b5c115SMatthew G. Knepley 
45829b5c115SMatthew G. Knepley   Output Parameter:
45929b5c115SMatthew G. Knepley . numTensSpaces - the number of spaces
46029b5c115SMatthew G. Knepley 
46129b5c115SMatthew G. Knepley   Level: intermediate
46229b5c115SMatthew G. Knepley 
463b24fb147SBarry Smith   Note:
464b24fb147SBarry Smith   The name NumSubspaces is misleading because it is actually getting the number of defining spaces of the tensor product space, not a number of Subspaces of it
465b24fb147SBarry Smith 
466dce8aebaSBarry Smith .seealso: `PETSCSPACETENSOR`, `PetscSpace`, `PetscSpaceTensorSetNumSubspaces()`, `PetscSpaceSetDegree()`, `PetscSpaceSetNumVariables()`
46729b5c115SMatthew G. Knepley @*/
PetscSpaceTensorGetNumSubspaces(PetscSpace sp,PetscInt * numTensSpaces)468d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSpaceTensorGetNumSubspaces(PetscSpace sp, PetscInt *numTensSpaces)
469d71ae5a4SJacob Faibussowitsch {
47036e5648fSToby Isaac   PetscFunctionBegin;
47136e5648fSToby Isaac   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
4724f572ea9SToby Isaac   PetscAssertPointer(numTensSpaces, 2);
473cac4c232SBarry Smith   PetscTryMethod(sp, "PetscSpaceTensorGetNumSubspaces_C", (PetscSpace, PetscInt *), (sp, numTensSpaces));
4743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47536e5648fSToby Isaac }
47636e5648fSToby Isaac 
47729b5c115SMatthew G. Knepley /*@
478b24fb147SBarry Smith   PetscSpaceTensorSetSubspace - Set a space in the tensor product space
47929b5c115SMatthew G. Knepley 
48029b5c115SMatthew G. Knepley   Input Parameters:
48129b5c115SMatthew G. Knepley + sp    - the function space object
48229b5c115SMatthew G. Knepley . s     - The space number
48329b5c115SMatthew G. Knepley - subsp - the number of spaces
48429b5c115SMatthew G. Knepley 
48529b5c115SMatthew G. Knepley   Level: intermediate
48629b5c115SMatthew G. Knepley 
487b24fb147SBarry Smith   Note:
488b24fb147SBarry Smith   The name SetSubspace is misleading because it is actually setting one of the defining spaces of the tensor product space, not a Subspace of it
489b24fb147SBarry Smith 
490dce8aebaSBarry Smith .seealso: `PETSCSPACETENSOR`, `PetscSpace`, `PetscSpaceTensorGetSubspace()`, `PetscSpaceSetDegree()`, `PetscSpaceSetNumVariables()`
49129b5c115SMatthew G. Knepley @*/
PetscSpaceTensorSetSubspace(PetscSpace sp,PetscInt s,PetscSpace subsp)492d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSpaceTensorSetSubspace(PetscSpace sp, PetscInt s, PetscSpace subsp)
493d71ae5a4SJacob Faibussowitsch {
49436e5648fSToby Isaac   PetscFunctionBegin;
49536e5648fSToby Isaac   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
49636e5648fSToby Isaac   if (subsp) PetscValidHeaderSpecific(subsp, PETSCSPACE_CLASSID, 3);
497cac4c232SBarry Smith   PetscTryMethod(sp, "PetscSpaceTensorSetSubspace_C", (PetscSpace, PetscInt, PetscSpace), (sp, s, subsp));
4983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49936e5648fSToby Isaac }
50036e5648fSToby Isaac 
50129b5c115SMatthew G. Knepley /*@
502b24fb147SBarry Smith   PetscSpaceTensorGetSubspace - Get a space in the tensor product space
50329b5c115SMatthew G. Knepley 
50429b5c115SMatthew G. Knepley   Input Parameters:
50529b5c115SMatthew G. Knepley + sp - the function space object
50629b5c115SMatthew G. Knepley - s  - The space number
50729b5c115SMatthew G. Knepley 
50829b5c115SMatthew G. Knepley   Output Parameter:
509b24fb147SBarry Smith . subsp - the `PetscSpace`
51029b5c115SMatthew G. Knepley 
51129b5c115SMatthew G. Knepley   Level: intermediate
51229b5c115SMatthew G. Knepley 
513b24fb147SBarry Smith   Note:
514b24fb147SBarry Smith   The name GetSubspace is misleading because it is actually getting one of the defining spaces of the tensor product space, not a Subspace of it
515b24fb147SBarry Smith 
516dce8aebaSBarry Smith .seealso: `PETSCSPACETENSOR`, `PetscSpace`, `PetscSpaceTensorSetSubspace()`, `PetscSpaceSetDegree()`, `PetscSpaceSetNumVariables()`
51729b5c115SMatthew G. Knepley @*/
PetscSpaceTensorGetSubspace(PetscSpace sp,PetscInt s,PetscSpace * subsp)518d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSpaceTensorGetSubspace(PetscSpace sp, PetscInt s, PetscSpace *subsp)
519d71ae5a4SJacob Faibussowitsch {
52036e5648fSToby Isaac   PetscFunctionBegin;
52136e5648fSToby Isaac   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
5224f572ea9SToby Isaac   PetscAssertPointer(subsp, 3);
523cac4c232SBarry Smith   PetscTryMethod(sp, "PetscSpaceTensorGetSubspace_C", (PetscSpace, PetscInt, PetscSpace *), (sp, s, subsp));
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52536e5648fSToby Isaac }
52636e5648fSToby Isaac 
PetscSpaceTensorSetNumSubspaces_Tensor(PetscSpace space,PetscInt numTensSpaces)527d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorSetNumSubspaces_Tensor(PetscSpace space, PetscInt numTensSpaces)
528d71ae5a4SJacob Faibussowitsch {
52936e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)space->data;
53036e5648fSToby Isaac   PetscInt           Ns;
53136e5648fSToby Isaac 
53236e5648fSToby Isaac   PetscFunctionBegin;
533371d2eb7SMartin Diehl   PetscCheck(!tens->setupcalled, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of subspaces after setup called");
534c88cc932SToby Isaac   Ns = tens->numTensSpaces;
5353ba16761SJacob Faibussowitsch   if (numTensSpaces == Ns) PetscFunctionReturn(PETSC_SUCCESS);
53636e5648fSToby Isaac   if (Ns >= 0) {
53736e5648fSToby Isaac     PetscInt s;
53836e5648fSToby Isaac 
5399566063dSJacob Faibussowitsch     for (s = 0; s < Ns; s++) PetscCall(PetscSpaceDestroy(&tens->tensspaces[s]));
5409566063dSJacob Faibussowitsch     PetscCall(PetscFree(tens->tensspaces));
54136e5648fSToby Isaac   }
542c88cc932SToby Isaac   Ns = tens->numTensSpaces = numTensSpaces;
5439566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Ns, &tens->tensspaces));
5443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54536e5648fSToby Isaac }
54636e5648fSToby Isaac 
PetscSpaceTensorGetNumSubspaces_Tensor(PetscSpace space,PetscInt * numTensSpaces)547d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorGetNumSubspaces_Tensor(PetscSpace space, PetscInt *numTensSpaces)
548d71ae5a4SJacob Faibussowitsch {
54936e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)space->data;
55036e5648fSToby Isaac 
55136e5648fSToby Isaac   PetscFunctionBegin;
552c88cc932SToby Isaac   *numTensSpaces = tens->numTensSpaces;
5533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55436e5648fSToby Isaac }
55536e5648fSToby Isaac 
PetscSpaceTensorSetSubspace_Tensor(PetscSpace space,PetscInt s,PetscSpace subspace)556d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorSetSubspace_Tensor(PetscSpace space, PetscInt s, PetscSpace subspace)
557d71ae5a4SJacob Faibussowitsch {
55836e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)space->data;
55936e5648fSToby Isaac   PetscInt           Ns;
56036e5648fSToby Isaac 
56136e5648fSToby Isaac   PetscFunctionBegin;
562371d2eb7SMartin Diehl   PetscCheck(!tens->setupcalled, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_WRONGSTATE, "Cannot change subspace after setup called");
563c88cc932SToby Isaac   Ns = tens->numTensSpaces;
56408401ef6SPierre Jolivet   PetscCheck(Ns >= 0, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSpaceTensorSetNumSubspaces() first");
5651dca8a05SBarry Smith   PetscCheck(s >= 0 && s < Ns, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_OUTOFRANGE, "Invalid subspace number %" PetscInt_FMT, s);
5669566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)subspace));
5679566063dSJacob Faibussowitsch   PetscCall(PetscSpaceDestroy(&tens->tensspaces[s]));
568c88cc932SToby Isaac   tens->tensspaces[s] = subspace;
5693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57036e5648fSToby Isaac }
57136e5648fSToby Isaac 
PetscSpaceGetHeightSubspace_Tensor(PetscSpace sp,PetscInt height,PetscSpace * subsp)572d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceGetHeightSubspace_Tensor(PetscSpace sp, PetscInt height, PetscSpace *subsp)
573d71ae5a4SJacob Faibussowitsch {
574d551817dSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)sp->data;
575d551817dSToby Isaac   PetscInt           Nc, dim, order, i;
576d551817dSToby Isaac   PetscSpace         bsp;
577d551817dSToby Isaac 
578d551817dSToby Isaac   PetscFunctionBegin;
5799566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumVariables(sp, &dim));
5801dca8a05SBarry Smith   PetscCheck(tens->uniform && tens->numTensSpaces == dim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can only get a generic height subspace of a uniform tensor space of 1d spaces.");
5819566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetNumComponents(sp, &Nc));
5829566063dSJacob Faibussowitsch   PetscCall(PetscSpaceGetDegree(sp, &order, NULL));
5831dca8a05SBarry Smith   PetscCheck(height <= dim && height >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Asked for space at height %" PetscInt_FMT " for dimension %" PetscInt_FMT " space", height, dim);
5849566063dSJacob Faibussowitsch   if (!tens->heightsubspaces) PetscCall(PetscCalloc1(dim, &tens->heightsubspaces));
585d551817dSToby Isaac   if (height <= dim) {
586c88cc932SToby Isaac     if (!tens->heightsubspaces[height - 1]) {
587d551817dSToby Isaac       PetscSpace  sub;
5883f6b16c7SMatthew G. Knepley       const char *name;
589d551817dSToby Isaac 
5909566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorGetSubspace(sp, 0, &bsp));
5919566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)sp), &sub));
5929566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)sp, &name));
5939566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)sub, name));
5949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(sub, PETSCSPACETENSOR));
5959566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(sub, Nc));
5969566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(sub, order, PETSC_DETERMINE));
5979566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(sub, dim - height));
5989566063dSJacob Faibussowitsch       PetscCall(PetscSpaceTensorSetNumSubspaces(sub, dim - height));
59948a46eb9SPierre Jolivet       for (i = 0; i < dim - height; i++) PetscCall(PetscSpaceTensorSetSubspace(sub, i, bsp));
6009566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(sub));
601c88cc932SToby Isaac       tens->heightsubspaces[height - 1] = sub;
602d551817dSToby Isaac     }
603c88cc932SToby Isaac     *subsp = tens->heightsubspaces[height - 1];
604d551817dSToby Isaac   } else {
605d551817dSToby Isaac     *subsp = NULL;
606d551817dSToby Isaac   }
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
608d551817dSToby Isaac }
609d551817dSToby Isaac 
PetscSpaceTensorGetSubspace_Tensor(PetscSpace space,PetscInt s,PetscSpace * subspace)610d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceTensorGetSubspace_Tensor(PetscSpace space, PetscInt s, PetscSpace *subspace)
611d71ae5a4SJacob Faibussowitsch {
61236e5648fSToby Isaac   PetscSpace_Tensor *tens = (PetscSpace_Tensor *)space->data;
61336e5648fSToby Isaac   PetscInt           Ns;
61436e5648fSToby Isaac 
61536e5648fSToby Isaac   PetscFunctionBegin;
616c88cc932SToby Isaac   Ns = tens->numTensSpaces;
61708401ef6SPierre Jolivet   PetscCheck(Ns >= 0, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSpaceTensorSetNumSubspaces() first");
6181dca8a05SBarry Smith   PetscCheck(s >= 0 && s < Ns, PetscObjectComm((PetscObject)space), PETSC_ERR_ARG_OUTOFRANGE, "Invalid subspace number %" PetscInt_FMT, s);
619c88cc932SToby Isaac   *subspace = tens->tensspaces[s];
6203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62136e5648fSToby Isaac }
62236e5648fSToby Isaac 
PetscSpaceInitialize_Tensor(PetscSpace sp)623d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSpaceInitialize_Tensor(PetscSpace sp)
624d71ae5a4SJacob Faibussowitsch {
62536e5648fSToby Isaac   PetscFunctionBegin;
62636e5648fSToby Isaac   sp->ops->setfromoptions    = PetscSpaceSetFromOptions_Tensor;
62736e5648fSToby Isaac   sp->ops->setup             = PetscSpaceSetUp_Tensor;
62836e5648fSToby Isaac   sp->ops->view              = PetscSpaceView_Tensor;
62936e5648fSToby Isaac   sp->ops->destroy           = PetscSpaceDestroy_Tensor;
63036e5648fSToby Isaac   sp->ops->getdimension      = PetscSpaceGetDimension_Tensor;
63136e5648fSToby Isaac   sp->ops->evaluate          = PetscSpaceEvaluate_Tensor;
632d551817dSToby Isaac   sp->ops->getheightsubspace = PetscSpaceGetHeightSubspace_Tensor;
6339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorGetNumSubspaces_C", PetscSpaceTensorGetNumSubspaces_Tensor));
6349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorSetNumSubspaces_C", PetscSpaceTensorSetNumSubspaces_Tensor));
6359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorGetSubspace_C", PetscSpaceTensorGetSubspace_Tensor));
6369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sp, "PetscSpaceTensorSetSubspace_C", PetscSpaceTensorSetSubspace_Tensor));
6373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63836e5648fSToby Isaac }
63936e5648fSToby Isaac 
64036e5648fSToby Isaac /*MC
641dce8aebaSBarry Smith   PETSCSPACETENSOR = "tensor" - A `PetscSpace` object that encapsulates a tensor product space.
642b3a91243SToby Isaac                      A tensor product is created of the components of the subspaces as well.
64336e5648fSToby Isaac 
64436e5648fSToby Isaac   Level: intermediate
64536e5648fSToby Isaac 
646b24fb147SBarry Smith .seealso: `PetscSpace`, `PetscSpaceType`, `PetscSpaceCreate()`, `PetscSpaceSetType()`, `PetscSpaceTensorGetSubspace()`, `PetscSpaceTensorSetSubspace()`,
647b24fb147SBarry Smith           `PetscSpaceTensorGetNumSubspaces()`, `PetscSpaceTensorSetNumSubspaces()`
64836e5648fSToby Isaac M*/
64936e5648fSToby Isaac 
PetscSpaceCreate_Tensor(PetscSpace sp)650d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscSpaceCreate_Tensor(PetscSpace sp)
651d71ae5a4SJacob Faibussowitsch {
65236e5648fSToby Isaac   PetscSpace_Tensor *tens;
65336e5648fSToby Isaac 
65436e5648fSToby Isaac   PetscFunctionBegin;
65536e5648fSToby Isaac   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
6564dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&tens));
65736e5648fSToby Isaac   sp->data = tens;
65836e5648fSToby Isaac 
659c88cc932SToby Isaac   tens->numTensSpaces = PETSC_DEFAULT;
66036e5648fSToby Isaac 
6619566063dSJacob Faibussowitsch   PetscCall(PetscSpaceInitialize_Tensor(sp));
6623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66336e5648fSToby Isaac }
664