14 #include "../interface/ceed.hpp"
15 #include "../interface/util.hpp"
18 #include <ceed/backend.h>
35 int coarse_i = (i < coarse_P1d - 1) ? i : -1;
38 coarse_i = coarse_P1d - 1;
46 if (i > P1d - coarse_P1d)
48 coarse_i = i - (P1d - coarse_P1d);
63 if (a <= b && a <= c && a <= d)
67 else if (b <= a && b <= c && b <= d)
71 else if (c <= a && c <= b && c <= d)
83 CeedElemRestriction er_in,
84 CeedElemRestriction* er_out,
89 ierr = CeedElemRestrictionGetCeed(er_in, &ceed); CeedChk(ierr);
91 CeedInt numelem, numcomp, elemsize;
93 ierr = CeedElemRestrictionGetNumElements(er_in, &numelem); CeedChk(ierr);
94 ierr = CeedElemRestrictionGetLVectorSize(er_in, &numnodes); CeedChk(ierr);
95 ierr = CeedElemRestrictionGetElementSize(er_in, &elemsize); CeedChk(ierr);
96 ierr = CeedElemRestrictionGetNumComponents(er_in, &numcomp); CeedChk(ierr);
100 return CeedError(ceed, 1,
"Algebraic element restriction not "
101 "implemented for multiple components.");
105 int coarse_P1d = P1d - order_reduction;
106 int dim = (log((
double) elemsize) / log((
double) P1d)) + 1.e-3;
108 CeedVector in_lvec, in_evec;
109 ierr = CeedElemRestrictionCreateVector(er_in, &in_lvec, &in_evec);
114 CeedScalar * lvec_data;
115 ierr = CeedVectorGetArrayWrite(in_lvec, CEED_MEM_HOST, &lvec_data);
117 for (CeedSize i = 0; i < numnodes; ++i)
119 lvec_data[i] = (CeedScalar) i;
121 ierr = CeedVectorRestoreArray(in_lvec, &lvec_data); CeedChk(ierr);
122 CeedInt in_layout[3];
123 ierr = CeedElemRestrictionGetELayout(er_in, &in_layout); CeedChk(ierr);
124 if (in_layout[0] == 0 && in_layout[1] == 0 && in_layout[2] == 0)
126 return CeedError(ceed, 1,
"Cannot interpret e-vector ordering of given"
127 "CeedElemRestriction!");
129 ierr = CeedElemRestrictionApply(er_in, CEED_NOTRANSPOSE, in_lvec, in_evec,
130 CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
131 ierr = CeedVectorDestroy(&in_lvec); CeedChk(ierr);
132 const CeedScalar * in_elem_dof;
133 ierr = CeedVectorGetArrayRead(in_evec, CEED_MEM_HOST, &in_elem_dof);
139 dof_map =
new CeedInt[numnodes];
140 for (CeedSize i = 0; i < numnodes; ++i)
144 CeedInt coarse_elemsize = pow(coarse_P1d, dim);
145 CeedInt * out_elem_dof =
new CeedInt[coarse_elemsize * numelem];
146 const double rounding_guard = 1.e-10;
147 int running_out_ldof_count = 0;
150 for (
int e = 0; e < numelem; ++e)
153 for (
int i = 0; i < P1d; ++i)
155 for (
int j = 0; j < P1d; ++j)
159 int in_edof = i*P1d + j;
160 const int edof_index = in_edof*in_layout[0] + e*in_layout[2];
161 int in_ldof = in_elem_dof[edof_index] + rounding_guard;
162 bool i_edge = (i == 0 || i == P1d - 1);
163 bool j_edge = (j == 0 || j == P1d - 1);
169 int coarse_i, coarse_j;
170 if (i_edge == j_edge)
180 int left_in_edof, left_in_ldof, right_in_edof, right_in_ldof;
183 left_in_edof = i*P1d + 0;
184 right_in_edof = i*P1d + (P1d - 1);
185 left_in_ldof = in_elem_dof[left_in_edof*in_layout[0]+e*in_layout[2]]
187 right_in_ldof = in_elem_dof[right_in_edof*in_layout[0]+e*in_layout[2]]
190 coarse_j = (left_in_ldof < right_in_ldof) ?
195 left_in_edof = 0*P1d + j;
196 right_in_edof = (P1d - 1)*P1d + j;
197 left_in_ldof = in_elem_dof[left_in_edof*in_layout[0]+e*in_layout[2]]
199 right_in_ldof = in_elem_dof[right_in_edof*in_layout[0]+e*in_layout[2]]
201 coarse_i = (left_in_ldof < right_in_ldof) ?
208 if (coarse_i >= 0 && coarse_j >= 0)
210 int out_edof = coarse_i*coarse_P1d + coarse_j;
211 if (dof_map[in_ldof] >= 0)
213 out_elem_dof[e*coarse_elemsize + out_edof] = dof_map[in_ldof];
217 out_elem_dof[e*coarse_elemsize + out_edof] = running_out_ldof_count;
218 dof_map[in_ldof] = running_out_ldof_count;
219 running_out_ldof_count++;
229 for (
int e = 0; e < numelem; ++e)
232 for (
int i = 0; i < P1d; ++i)
234 for (
int j = 0; j < P1d; ++j)
236 for (
int k = 0; k < P1d; ++k)
240 int in_edof = i*P1d*P1d + j*P1d + k;
241 int in_ldof = in_elem_dof[in_edof*in_layout[0]+e*in_layout[2]]
243 bool i_edge = (i == 0 || i == P1d - 1);
244 bool j_edge = (j == 0 || j == P1d - 1);
245 bool k_edge = (k == 0 || k == P1d - 1);
247 if (i_edge) { topo++; }
248 if (j_edge) { topo++; }
249 if (k_edge) { topo++; }
255 int coarse_i, coarse_j, coarse_k;
256 if (topo == 0 || topo == 3)
267 int left_in_edof, left_in_ldof, right_in_edof, right_in_ldof;
270 left_in_edof = 0*P1d*P1d + j*P1d + k;
271 right_in_edof = (P1d - 1)*P1d*P1d + j*P1d + k;
272 left_in_ldof = in_elem_dof[left_in_edof*in_layout[0]+e*in_layout[2]]
274 right_in_ldof = in_elem_dof[right_in_edof*in_layout[0]+e*in_layout[2]]
276 coarse_i = (left_in_ldof < right_in_ldof) ?
283 left_in_edof = i*P1d*P1d + 0*P1d + k;
284 right_in_edof = i*P1d*P1d + (P1d - 1)*P1d + k;
285 left_in_ldof = in_elem_dof[left_in_edof*in_layout[0]+e*in_layout[2]]
287 right_in_ldof = in_elem_dof[right_in_edof*in_layout[0]+e*in_layout[2]]
290 coarse_j = (left_in_ldof < right_in_ldof) ?
298 return CeedError(ceed, 1,
299 "Element connectivity does not make sense!");
301 left_in_edof = i*P1d*P1d + j*P1d + 0;
302 right_in_edof = i*P1d*P1d + j*P1d + (P1d - 1);
303 left_in_ldof = in_elem_dof[left_in_edof*in_layout[0]+e*in_layout[2]]
305 right_in_ldof = in_elem_dof[right_in_edof*in_layout[0]+e*in_layout[2]]
309 coarse_k = (left_in_ldof < right_in_ldof) ?
319 return CeedError(ceed, 1,
320 "Element connectivity does not match topology!");
322 int bottom_left_edof, bottom_right_edof, top_left_edof, top_right_edof;
323 int bottom_left_ldof, bottom_right_ldof, top_left_ldof, top_right_ldof;
326 bottom_left_edof = i*P1d*P1d + 0*P1d + 0;
327 bottom_right_edof = i*P1d*P1d + 0*P1d + (P1d - 1);
328 top_right_edof = i*P1d*P1d + (P1d - 1)*P1d + (P1d - 1);
329 top_left_edof = i*P1d*P1d + (P1d - 1)*P1d + 0;
330 bottom_left_ldof = in_elem_dof[bottom_left_edof*in_layout[0]+e*in_layout[2]]
332 bottom_right_ldof = in_elem_dof[bottom_right_edof*in_layout[0]+e*in_layout[2]]
334 top_right_ldof = in_elem_dof[top_right_edof*in_layout[0]+e*in_layout[2]]
336 top_left_ldof = in_elem_dof[top_left_edof*in_layout[0]+e*in_layout[2]]
338 int m =
min4(bottom_left_ldof, bottom_right_ldof, top_right_ldof,
341 if (m == bottom_left_ldof)
346 else if (m == bottom_right_ldof)
351 else if (m == top_right_ldof)
364 bottom_left_edof = 0*P1d*P1d + j*P1d + 0;
365 bottom_right_edof = 0*P1d*P1d + j*P1d + (P1d - 1);
366 top_right_edof = (P1d - 1)*P1d*P1d + j*P1d + (P1d - 1);
367 top_left_edof = (P1d - 1)*P1d*P1d + j*P1d + 0;
368 bottom_left_ldof = in_elem_dof[bottom_left_edof*in_layout[0]+e*in_layout[2]]
370 bottom_right_ldof = in_elem_dof[bottom_right_edof*in_layout[0]+e*in_layout[2]]
372 top_right_ldof = in_elem_dof[top_right_edof*in_layout[0]+e*in_layout[2]]
374 top_left_ldof = in_elem_dof[top_left_edof*in_layout[0]+e*in_layout[2]]
376 int m =
min4(bottom_left_ldof, bottom_right_ldof, top_right_ldof,
379 if (m == bottom_left_ldof)
384 else if (m == bottom_right_ldof)
389 else if (m == top_right_ldof)
404 return CeedError(ceed, 1,
405 "Element connectivity does not make sense!");
407 bottom_left_edof = 0*P1d*P1d + 0*P1d + k;
408 bottom_right_edof = 0*P1d*P1d + (P1d - 1)*P1d + k;
409 top_right_edof = (P1d - 1)*P1d*P1d + (P1d - 1)*P1d + k;
410 top_left_edof = (P1d - 1)*P1d*P1d + 0*P1d + k;
411 bottom_left_ldof = in_elem_dof[bottom_left_edof*in_layout[0]+e*in_layout[2]]
413 bottom_right_ldof = in_elem_dof[bottom_right_edof*in_layout[0]+e*in_layout[2]]
415 top_right_ldof = in_elem_dof[top_right_edof*in_layout[0]+e*in_layout[2]]
417 top_left_ldof = in_elem_dof[top_left_edof*in_layout[0]+e*in_layout[2]]
419 int m =
min4(bottom_left_ldof, bottom_right_ldof,
420 top_right_ldof, top_left_ldof);
422 if (m == bottom_left_ldof)
427 else if (m == bottom_right_ldof)
432 else if (m == top_right_ldof)
446 if (coarse_i >= 0 && coarse_j >= 0 && coarse_k >= 0)
448 int out_edof = coarse_i*coarse_P1d*coarse_P1d + coarse_j*coarse_P1d + coarse_k;
449 if (dof_map[in_ldof] >= 0)
451 out_elem_dof[e*coarse_elemsize + out_edof] = dof_map[in_ldof];
455 out_elem_dof[e*coarse_elemsize + out_edof] = running_out_ldof_count;
456 dof_map[in_ldof] = running_out_ldof_count;
457 running_out_ldof_count++;
468 return CeedError(ceed, 1,
469 "CeedATPMGElemRestriction does not yet support this dimension.");
472 ierr = CeedVectorRestoreArrayRead(in_evec, &in_elem_dof); CeedChk(ierr);
473 ierr = CeedVectorDestroy(&in_evec); CeedChk(ierr);
475 ierr = CeedElemRestrictionCreate(ceed, numelem, coarse_elemsize, numcomp,
476 0, running_out_ldof_count,
477 CEED_MEM_HOST, CEED_COPY_VALUES, out_elem_dof,
478 er_out); CeedChk(ierr);
480 delete [] out_elem_dof;
493 ierr = CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, P1d - order_reduction, P1d,
494 CEED_GAUSS_LOBATTO, basisc2f); CeedChk(ierr);
504 ierr = CeedBasisGetCeed(basisin, &ceed); CeedChk(ierr);
507 ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
508 ierr = CeedBasisGetNumNodes1D(basisin, &P1d); CeedChk(ierr);
510 basisc2f); CeedChk(ierr);
521 ierr = CeedBasisGetCeed(basisin, &ceed); CeedChk(ierr);
523 CeedInt
dim, ncomp, P1d, Q1d;
524 ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
525 ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
526 ierr = CeedBasisGetNumNodes1D(basisin, &P1d); CeedChk(ierr);
527 ierr = CeedBasisGetNumQuadraturePoints1D(basisin, &Q1d); CeedChk(ierr);
529 CeedInt coarse_P1d = P1d - order_reduction;
531 const CeedScalar *interp1d;
532 ierr = CeedBasisGetInterp1D(basisin, &interp1d); CeedChk(ierr);
533 const CeedScalar * grad1d;
534 ierr = CeedBasisGetGrad1D(basisin, &grad1d); CeedChk(ierr);
536 CeedScalar * coarse_interp1d =
new CeedScalar[coarse_P1d * Q1d];
537 CeedScalar * coarse_grad1d =
new CeedScalar[coarse_P1d * Q1d];
538 CeedScalar * fine_nodal_points =
new CeedScalar[P1d];
545 ierr = CeedLobattoQuadrature(P1d, fine_nodal_points, NULL); CeedChk(ierr);
546 for (
int i = 0; i < P1d; ++i)
548 fine_nodal_points[i] = 0.5 * fine_nodal_points[i] + 0.5;
551 const CeedScalar *interp_ctof;
552 ierr = CeedBasisGetInterp1D(basisc2f, &interp_ctof); CeedChk(ierr);
554 for (
int i = 0; i < Q1d; ++i)
556 for (
int j = 0; j < coarse_P1d; ++j)
558 coarse_interp1d[i * coarse_P1d + j] = 0.0;
559 coarse_grad1d[i * coarse_P1d + j] = 0.0;
560 for (
int k = 0; k < P1d; ++k)
562 coarse_interp1d[i * coarse_P1d + j] += interp_ctof[k * coarse_P1d + j] *
563 interp1d[i * P1d + k];
564 coarse_grad1d[i * coarse_P1d + j] += interp_ctof[k * coarse_P1d + j] *
570 const CeedScalar * qref1d;
571 ierr = CeedBasisGetQRef(basisin, &qref1d); CeedChk(ierr);
572 const CeedScalar * qweight1d;
573 ierr = CeedBasisGetQWeights(basisin, &qweight1d); CeedChk(ierr);
574 ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp,
575 coarse_P1d, Q1d, coarse_interp1d, coarse_grad1d,
576 qref1d, qweight1d, basisout); CeedChk(ierr);
578 delete [] fine_nodal_points;
579 delete [] coarse_interp1d;
580 delete [] coarse_grad1d;
586 CeedElemRestriction coarse_er,
587 CeedBasis coarse_basis_in,
588 CeedBasis basis_ctof_in,
591 (void)order_reduction;
596 ierr = CeedOperatorGetCeed(oper, &ceed); CeedChk(ierr);
599 ierr = CeedOperatorGetQFunction(oper, &qf); CeedChk(ierr);
600 CeedInt numinputfields, numoutputfields;
601 CeedQFunctionField *inputqfields, *outputqfields;
602 ierr = CeedQFunctionGetFields(qf, &numinputfields, &inputqfields,
603 &numoutputfields, &outputqfields);
605 CeedOperatorField *inputfields, *outputfields;
606 ierr = CeedOperatorGetFields(oper, &numinputfields, &inputfields,
607 &numoutputfields, &outputfields);
610 CeedElemRestriction * er_input =
new CeedElemRestriction[numinputfields];
611 CeedElemRestriction * er_output =
new CeedElemRestriction[numoutputfields];
612 CeedVector * if_vector =
new CeedVector[numinputfields];
613 CeedVector * of_vector =
new CeedVector[numoutputfields];
614 CeedBasis * basis_input =
new CeedBasis[numinputfields];
615 CeedBasis * basis_output =
new CeedBasis[numoutputfields];
616 CeedBasis cbasis = coarse_basis_in;
618 int active_input_basis = -1;
619 for (
int i = 0; i < numinputfields; ++i)
621 ierr = CeedOperatorFieldGetElemRestriction(inputfields[i],
622 &er_input[i]); CeedChk(ierr);
623 ierr = CeedOperatorFieldGetVector(inputfields[i], &if_vector[i]); CeedChk(ierr);
624 ierr = CeedOperatorFieldGetBasis(inputfields[i], &basis_input[i]);
626 if (if_vector[i] == CEED_VECTOR_ACTIVE)
628 if (active_input_basis < 0)
630 active_input_basis = i;
632 else if (basis_input[i] != basis_input[active_input_basis])
634 return CeedError(ceed, 1,
"Two different active input basis!");
638 for (
int i = 0; i < numoutputfields; ++i)
640 ierr = CeedOperatorFieldGetElemRestriction(outputfields[i],
641 &er_output[i]); CeedChk(ierr);
642 ierr = CeedOperatorFieldGetVector(outputfields[i], &of_vector[i]);
644 ierr = CeedOperatorFieldGetBasis(outputfields[i], &basis_output[i]);
646 if (of_vector[i] == CEED_VECTOR_ACTIVE)
649 if (basis_output[i] != basis_input[active_input_basis])
651 return CeedError(ceed, 1,
"Input and output basis do not match!");
653 if (er_output[i] != er_input[active_input_basis])
655 return CeedError(ceed, 1,
"Input and output elem-restriction do not match!");
661 ierr = CeedOperatorCreate(ceed, qf, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE,
662 &coper); CeedChk(ierr);
664 for (
int i = 0; i < numinputfields; ++i)
667 ierr = CeedQFunctionFieldGetName(inputqfields[i], &fieldname); CeedChk(ierr);
668 if (if_vector[i] == CEED_VECTOR_ACTIVE)
670 ierr = CeedOperatorSetField(coper, fieldname, coarse_er, cbasis,
671 if_vector[i]); CeedChk(ierr);
675 ierr = CeedOperatorSetField(coper, fieldname, er_input[i], basis_input[i],
676 if_vector[i]); CeedChk(ierr);
679 for (
int i = 0; i < numoutputfields; ++i)
682 ierr = CeedQFunctionFieldGetName(outputqfields[i], &fieldname); CeedChk(ierr);
683 if (of_vector[i] == CEED_VECTOR_ACTIVE)
685 ierr = CeedOperatorSetField(coper, fieldname, coarse_er, cbasis,
686 of_vector[i]); CeedChk(ierr);
690 ierr = CeedOperatorSetField(coper, fieldname, er_output[i], basis_output[i],
691 of_vector[i]); CeedChk(ierr);
698 delete [] basis_input;
699 delete [] basis_output;
706 CeedElemRestriction coarse_er,
707 CeedBasis *coarse_basis_out,
708 CeedBasis *basis_ctof_out,
714 ierr = CeedOperatorGetQFunction(oper, &qf); CeedChk(ierr);
715 CeedInt numinputfields, numoutputfields;
716 CeedOperatorField *inputfields;
717 ierr = CeedOperatorGetFields(oper, &numinputfields, &inputfields,
718 &numoutputfields, NULL);
722 ierr = CeedOperatorGetActiveBasis(oper, &basis); CeedChk(ierr);
726 order_reduction); CeedChk(ierr);
728 *basis_ctof_out, out); CeedChk(ierr);
736 CeedOperatorField active_field;
739 ierr = CeedOperatorFieldGetBasis(active_field, &basis); CeedChk(ierr);
741 ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
748 CeedBasis* coarse_basis_out,
749 CeedBasis* basis_ctof_out,
750 CeedElemRestriction* er_out,
751 CeedOperator* coarse_oper,
757 CeedElemRestriction ho_er;
758 ierr = CeedOperatorGetActiveElemRestriction(oper, &ho_er); CeedChk(ierr);
762 basis_ctof_out, coarse_oper); CeedChk(ierr);
770 #endif // MFEM_USE_CEED
int CeedATPMGOperator(CeedOperator oper, int order_reduction, CeedElemRestriction coarse_er, CeedBasis coarse_basis_in, CeedBasis basis_ctof_in, CeedOperator *out)
int min4(int a, int b, int c, int d)
int reverse_coarse_1d_edof(int i, int P1d, int coarse_P1d)
int CeedBasisATPMGCoarsen(CeedBasis basisin, CeedBasis basisc2f, CeedBasis *basisout, int order_reduction)
int CeedATPMGBundle(CeedOperator oper, int order_reduction, CeedBasis *coarse_basis_out, CeedBasis *basis_ctof_out, CeedElemRestriction *er_out, CeedOperator *coarse_oper, CeedInt *&dof_map)
Given (fine) CeedOperator, produces everything you need for a coarse level (operator and interpolatio...
int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
int CeedOperatorGetOrder(CeedOperator oper, CeedInt *order)
int CeedATPMGElemRestriction(int order, int order_reduction, CeedElemRestriction er_in, CeedElemRestriction *er_out, CeedInt *&dof_map)
Take given (high-order) CeedElemRestriction and make a new CeedElemRestriction, which corresponds to ...
int CeedBasisATPMGCoarseToFine(Ceed ceed, int P1d, int dim, int order_reduction, CeedBasis *basisc2f)
Create coarse-to-fine basis, given number of input nodes and order reduction.
int coarse_1d_edof(int i, int P1d, int coarse_P1d)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...