115ed3f7dSjeremylt /// @file 215ed3f7dSjeremylt /// Test creation and use of FDM element inverse 315ed3f7dSjeremylt /// \test Test creation and use of FDM element inverse 415ed3f7dSjeremylt #include <ceed.h> 515ed3f7dSjeremylt #include <stdlib.h> 615ed3f7dSjeremylt #include <string.h> 715ed3f7dSjeremylt #include <math.h> 815ed3f7dSjeremylt #include "t541-operator.h" 915ed3f7dSjeremylt 1015ed3f7dSjeremylt int main(int argc, char **argv) { 1115ed3f7dSjeremylt Ceed ceed; 1215ed3f7dSjeremylt CeedElemRestriction elem_restr_x_i, elem_restr_u_i, elem_restr_qd_i; 1315ed3f7dSjeremylt CeedBasis basis_x, basis_u; 1415ed3f7dSjeremylt CeedQFunction qf_setup_diff, qf_apply; 1515ed3f7dSjeremylt CeedOperator op_setup_diff, op_apply, op_inv; 1615ed3f7dSjeremylt CeedVector q_data_diff, X, U, V, W; 1715ed3f7dSjeremylt CeedInt num_elem = 1, P = 4, Q = 5, dim = 2; 1815ed3f7dSjeremylt CeedInt num_dofs = P*P, num_qpts = num_elem*Q*Q, q_data_size = dim*(dim+1)/2; 1915ed3f7dSjeremylt CeedScalar x[dim*num_elem*(2*2)]; 2015ed3f7dSjeremylt 2115ed3f7dSjeremylt CeedInit(argv[1], &ceed); 2215ed3f7dSjeremylt 2315ed3f7dSjeremylt // DoF Coordinates 2415ed3f7dSjeremylt for (CeedInt i=0; i<2; i++) 2515ed3f7dSjeremylt for (CeedInt j=0; j<2; j++) { 2615ed3f7dSjeremylt x[i+j*2+0*4] = i; 2715ed3f7dSjeremylt x[i+j*2+1*4] = j; 2815ed3f7dSjeremylt } 2915ed3f7dSjeremylt CeedVectorCreate(ceed, dim*num_elem*(2*2), &X); 3015ed3f7dSjeremylt CeedVectorSetArray(X, CEED_MEM_HOST, CEED_USE_POINTER, x); 3115ed3f7dSjeremylt 3215ed3f7dSjeremylt // Qdata Vector 3315ed3f7dSjeremylt CeedVectorCreate(ceed, q_data_size*num_qpts, &q_data_diff); 3415ed3f7dSjeremylt 3515ed3f7dSjeremylt // Element Setup 3615ed3f7dSjeremylt 3715ed3f7dSjeremylt // Restrictions 3815ed3f7dSjeremylt CeedInt strides_x[3] = {1, 2*2, 2*2*dim}; 3915ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, 2*2, dim, dim*num_elem*2*2, 4015ed3f7dSjeremylt strides_x, &elem_restr_x_i); 4115ed3f7dSjeremylt 4215ed3f7dSjeremylt CeedInt strides_u[3] = {1, P*P, P*P}; 4315ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, P*P, 1, num_dofs, strides_u, 4415ed3f7dSjeremylt &elem_restr_u_i); 4515ed3f7dSjeremylt 4615ed3f7dSjeremylt CeedInt strides_qd[3] = {1, Q*Q, q_data_size *Q*Q}; 4715ed3f7dSjeremylt CeedElemRestrictionCreateStrided(ceed, num_elem, Q*Q, q_data_size, 4815ed3f7dSjeremylt num_qpts*q_data_size, strides_qd, &elem_restr_qd_i); 4915ed3f7dSjeremylt 5015ed3f7dSjeremylt // Bases 5115ed3f7dSjeremylt CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, Q, CEED_GAUSS, &basis_x); 5215ed3f7dSjeremylt CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, P, Q, CEED_GAUSS, &basis_u); 5315ed3f7dSjeremylt 5415ed3f7dSjeremylt // QFunction - setup diff 5515ed3f7dSjeremylt CeedQFunctionCreateInterior(ceed, 1, setup_diff, setup_diff_loc, 5615ed3f7dSjeremylt &qf_setup_diff); 5715ed3f7dSjeremylt CeedQFunctionAddInput(qf_setup_diff, "dx", dim*dim, CEED_EVAL_GRAD); 5815ed3f7dSjeremylt CeedQFunctionAddInput(qf_setup_diff, "weight", 1, CEED_EVAL_WEIGHT); 5915ed3f7dSjeremylt CeedQFunctionAddOutput(qf_setup_diff, "qdata", q_data_size, CEED_EVAL_NONE); 6015ed3f7dSjeremylt 6115ed3f7dSjeremylt // Operator - setup diff 6215ed3f7dSjeremylt CeedOperatorCreate(ceed, qf_setup_diff, CEED_QFUNCTION_NONE, 6315ed3f7dSjeremylt CEED_QFUNCTION_NONE, &op_setup_diff); 6415ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "dx", elem_restr_x_i, basis_x, 6515ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 6615ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "weight", CEED_ELEMRESTRICTION_NONE, 6715ed3f7dSjeremylt basis_x, CEED_VECTOR_NONE); 6815ed3f7dSjeremylt CeedOperatorSetField(op_setup_diff, "qdata", elem_restr_qd_i, 6915ed3f7dSjeremylt CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 7015ed3f7dSjeremylt 7115ed3f7dSjeremylt // Apply Setup Operator 7215ed3f7dSjeremylt CeedOperatorApply(op_setup_diff, X, q_data_diff, CEED_REQUEST_IMMEDIATE); 7315ed3f7dSjeremylt 7415ed3f7dSjeremylt // QFunction - apply 7515ed3f7dSjeremylt CeedQFunctionCreateInterior(ceed, 1, apply, apply_loc, &qf_apply); 7615ed3f7dSjeremylt CeedQFunctionAddInput(qf_apply, "u", dim, CEED_EVAL_GRAD); 7715ed3f7dSjeremylt CeedQFunctionAddInput(qf_apply, "qdata_diff", q_data_size, CEED_EVAL_NONE); 7815ed3f7dSjeremylt CeedQFunctionAddOutput(qf_apply, "v", dim, CEED_EVAL_GRAD); 7915ed3f7dSjeremylt 8015ed3f7dSjeremylt // Operator - apply 8115ed3f7dSjeremylt CeedOperatorCreate(ceed, qf_apply, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, 8215ed3f7dSjeremylt &op_apply); 8315ed3f7dSjeremylt CeedOperatorSetField(op_apply, "u", elem_restr_u_i, basis_u, 8415ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 8515ed3f7dSjeremylt CeedOperatorSetField(op_apply, "qdata_diff", elem_restr_qd_i, 8615ed3f7dSjeremylt CEED_BASIS_COLLOCATED, q_data_diff); 8715ed3f7dSjeremylt CeedOperatorSetField(op_apply, "v", elem_restr_u_i, basis_u, 8815ed3f7dSjeremylt CEED_VECTOR_ACTIVE); 8915ed3f7dSjeremylt 9015ed3f7dSjeremylt // Create FDM element inverse 9115ed3f7dSjeremylt CeedOperatorCreateFDMElementInverse(op_apply, &op_inv, CEED_REQUEST_IMMEDIATE); 9215ed3f7dSjeremylt 9315ed3f7dSjeremylt // Create vectors 9415ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &U); 9515ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &V); 9615ed3f7dSjeremylt CeedVectorCreate(ceed, num_dofs, &W); 9715ed3f7dSjeremylt 9815ed3f7dSjeremylt // Create Schur complement for element corners 9915ed3f7dSjeremylt CeedScalar S[16]; 10015ed3f7dSjeremylt for (CeedInt i = 0; i < 4; i++) { 10115ed3f7dSjeremylt CeedScalar *u; 10215ed3f7dSjeremylt CeedVectorSetValue(U, 0.0); 10315ed3f7dSjeremylt CeedVectorGetArray(U, CEED_MEM_HOST, &u); 10415ed3f7dSjeremylt switch (i) { 10515ed3f7dSjeremylt case 0: u[0] = 1.0; break; 10615ed3f7dSjeremylt case 1: u[P-1] = 1.0; break; 10715ed3f7dSjeremylt case 2: u[P*P-P] = 1.0; break; 10815ed3f7dSjeremylt case 3: u[P*P-1] = 1.0; break; 10915ed3f7dSjeremylt } 11015ed3f7dSjeremylt CeedVectorRestoreArray(U, &u); 11115ed3f7dSjeremylt 11215ed3f7dSjeremylt CeedOperatorApply(op_inv, U, V, CEED_REQUEST_IMMEDIATE); 11315ed3f7dSjeremylt 11415ed3f7dSjeremylt const CeedScalar *v; 11515ed3f7dSjeremylt CeedVectorGetArrayRead(V, CEED_MEM_HOST, &v); 11615ed3f7dSjeremylt S[0*4+i] = v[0]; 11715ed3f7dSjeremylt S[1*4+i] = v[P-1]; 11815ed3f7dSjeremylt S[2*4+i] = v[P*P-P]; 11915ed3f7dSjeremylt S[3*4+i] = v[P*P-1]; 12015ed3f7dSjeremylt CeedVectorRestoreArrayRead(V, &v); 12115ed3f7dSjeremylt } 12215ed3f7dSjeremylt CeedScalar S_inv[16]; 12315ed3f7dSjeremylt { 12415ed3f7dSjeremylt CeedScalar det; 12515ed3f7dSjeremylt S_inv[0] = S[5] * S[10] * S[15] - 12615ed3f7dSjeremylt S[5] * S[11] * S[14] - 12715ed3f7dSjeremylt S[9] * S[6] * S[15] + 12815ed3f7dSjeremylt S[9] * S[7] * S[14] + 12915ed3f7dSjeremylt S[13] * S[6] * S[11] - 13015ed3f7dSjeremylt S[13] * S[7] * S[10]; 13115ed3f7dSjeremylt 13215ed3f7dSjeremylt S_inv[4] = -S[4] * S[10] * S[15] + 13315ed3f7dSjeremylt S[4] * S[11] * S[14] + 13415ed3f7dSjeremylt S[8] * S[6] * S[15] - 13515ed3f7dSjeremylt S[8] * S[7] * S[14] - 13615ed3f7dSjeremylt S[12] * S[6] * S[11] + 13715ed3f7dSjeremylt S[12] * S[7] * S[10]; 13815ed3f7dSjeremylt 13915ed3f7dSjeremylt S_inv[8] = S[4] * S[9] * S[15] - 14015ed3f7dSjeremylt S[4] * S[11] * S[13] - 14115ed3f7dSjeremylt S[8] * S[5] * S[15] + 14215ed3f7dSjeremylt S[8] * S[7] * S[13] + 14315ed3f7dSjeremylt S[12] * S[5] * S[11] - 14415ed3f7dSjeremylt S[12] * S[7] * S[9]; 14515ed3f7dSjeremylt 14615ed3f7dSjeremylt S_inv[12] = -S[4] * S[9] * S[14] + 14715ed3f7dSjeremylt S[4] * S[10] * S[13] + 14815ed3f7dSjeremylt S[8] * S[5] * S[14] - 14915ed3f7dSjeremylt S[8] * S[6] * S[13] - 15015ed3f7dSjeremylt S[12] * S[5] * S[10] + 15115ed3f7dSjeremylt S[12] * S[6] * S[9]; 15215ed3f7dSjeremylt 15315ed3f7dSjeremylt S_inv[1] = -S[1] * S[10] * S[15] + 15415ed3f7dSjeremylt S[1] * S[11] * S[14] + 15515ed3f7dSjeremylt S[9] * S[2] * S[15] - 15615ed3f7dSjeremylt S[9] * S[3] * S[14] - 15715ed3f7dSjeremylt S[13] * S[2] * S[11] + 15815ed3f7dSjeremylt S[13] * S[3] * S[10]; 15915ed3f7dSjeremylt 16015ed3f7dSjeremylt S_inv[5] = S[0] * S[10] * S[15] - 16115ed3f7dSjeremylt S[0] * S[11] * S[14] - 16215ed3f7dSjeremylt S[8] * S[2] * S[15] + 16315ed3f7dSjeremylt S[8] * S[3] * S[14] + 16415ed3f7dSjeremylt S[12] * S[2] * S[11] - 16515ed3f7dSjeremylt S[12] * S[3] * S[10]; 16615ed3f7dSjeremylt 16715ed3f7dSjeremylt S_inv[9] = -S[0] * S[9] * S[15] + 16815ed3f7dSjeremylt S[0] * S[11] * S[13] + 16915ed3f7dSjeremylt S[8] * S[1] * S[15] - 17015ed3f7dSjeremylt S[8] * S[3] * S[13] - 17115ed3f7dSjeremylt S[12] * S[1] * S[11] + 17215ed3f7dSjeremylt S[12] * S[3] * S[9]; 17315ed3f7dSjeremylt 17415ed3f7dSjeremylt S_inv[13] = S[0] * S[9] * S[14] - 17515ed3f7dSjeremylt S[0] * S[10] * S[13] - 17615ed3f7dSjeremylt S[8] * S[1] * S[14] + 17715ed3f7dSjeremylt S[8] * S[2] * S[13] + 17815ed3f7dSjeremylt S[12] * S[1] * S[10] - 17915ed3f7dSjeremylt S[12] * S[2] * S[9]; 18015ed3f7dSjeremylt 18115ed3f7dSjeremylt S_inv[2] = S[1] * S[6] * S[15] - 18215ed3f7dSjeremylt S[1] * S[7] * S[14] - 18315ed3f7dSjeremylt S[5] * S[2] * S[15] + 18415ed3f7dSjeremylt S[5] * S[3] * S[14] + 18515ed3f7dSjeremylt S[13] * S[2] * S[7] - 18615ed3f7dSjeremylt S[13] * S[3] * S[6]; 18715ed3f7dSjeremylt 18815ed3f7dSjeremylt S_inv[6] = -S[0] * S[6] * S[15] + 18915ed3f7dSjeremylt S[0] * S[7] * S[14] + 19015ed3f7dSjeremylt S[4] * S[2] * S[15] - 19115ed3f7dSjeremylt S[4] * S[3] * S[14] - 19215ed3f7dSjeremylt S[12] * S[2] * S[7] + 19315ed3f7dSjeremylt S[12] * S[3] * S[6]; 19415ed3f7dSjeremylt 19515ed3f7dSjeremylt S_inv[10] = S[0] * S[5] * S[15] - 19615ed3f7dSjeremylt S[0] * S[7] * S[13] - 19715ed3f7dSjeremylt S[4] * S[1] * S[15] + 19815ed3f7dSjeremylt S[4] * S[3] * S[13] + 19915ed3f7dSjeremylt S[12] * S[1] * S[7] - 20015ed3f7dSjeremylt S[12] * S[3] * S[5]; 20115ed3f7dSjeremylt 20215ed3f7dSjeremylt S_inv[14] = -S[0] * S[5] * S[14] + 20315ed3f7dSjeremylt S[0] * S[6] * S[13] + 20415ed3f7dSjeremylt S[4] * S[1] * S[14] - 20515ed3f7dSjeremylt S[4] * S[2] * S[13] - 20615ed3f7dSjeremylt S[12] * S[1] * S[6] + 20715ed3f7dSjeremylt S[12] * S[2] * S[5]; 20815ed3f7dSjeremylt 20915ed3f7dSjeremylt S_inv[3] = -S[1] * S[6] * S[11] + 21015ed3f7dSjeremylt S[1] * S[7] * S[10] + 21115ed3f7dSjeremylt S[5] * S[2] * S[11] - 21215ed3f7dSjeremylt S[5] * S[3] * S[10] - 21315ed3f7dSjeremylt S[9] * S[2] * S[7] + 21415ed3f7dSjeremylt S[9] * S[3] * S[6]; 21515ed3f7dSjeremylt 21615ed3f7dSjeremylt S_inv[7] = S[0] * S[6] * S[11] - 21715ed3f7dSjeremylt S[0] * S[7] * S[10] - 21815ed3f7dSjeremylt S[4] * S[2] * S[11] + 21915ed3f7dSjeremylt S[4] * S[3] * S[10] + 22015ed3f7dSjeremylt S[8] * S[2] * S[7] - 22115ed3f7dSjeremylt S[8] * S[3] * S[6]; 22215ed3f7dSjeremylt 22315ed3f7dSjeremylt S_inv[11] = -S[0] * S[5] * S[11] + 22415ed3f7dSjeremylt S[0] * S[7] * S[9] + 22515ed3f7dSjeremylt S[4] * S[1] * S[11] - 22615ed3f7dSjeremylt S[4] * S[3] * S[9] - 22715ed3f7dSjeremylt S[8] * S[1] * S[7] + 22815ed3f7dSjeremylt S[8] * S[3] * S[5]; 22915ed3f7dSjeremylt 23015ed3f7dSjeremylt S_inv[15] = S[0] * S[5] * S[10] - 23115ed3f7dSjeremylt S[0] * S[6] * S[9] - 23215ed3f7dSjeremylt S[4] * S[1] * S[10] + 23315ed3f7dSjeremylt S[4] * S[2] * S[9] + 23415ed3f7dSjeremylt S[8] * S[1] * S[6] - 23515ed3f7dSjeremylt S[8] * S[2] * S[5]; 23615ed3f7dSjeremylt 23715ed3f7dSjeremylt det = 1/(S[0]*S_inv[0] + S[1]*S_inv[4] + S[2]*S_inv[8] + S[3]*S_inv[12]); 23815ed3f7dSjeremylt 23915ed3f7dSjeremylt for (CeedInt i = 0; i < 16; i++) 24015ed3f7dSjeremylt S_inv[i] *= det; 24115ed3f7dSjeremylt } 24215ed3f7dSjeremylt 24315ed3f7dSjeremylt // Set initial values 24415ed3f7dSjeremylt { 24515ed3f7dSjeremylt CeedScalar nodes[P]; 24615ed3f7dSjeremylt CeedLobattoQuadrature(P, nodes, NULL); 24715ed3f7dSjeremylt CeedScalar *u; 24815ed3f7dSjeremylt CeedVectorGetArray(U, CEED_MEM_HOST, &u); 24915ed3f7dSjeremylt for (CeedInt i=0; i<P; i++) 25015ed3f7dSjeremylt for (CeedInt j=0; j<P; j++) 251*66ce82e0Sjeremylt u[i*P+j] = -(nodes[i] - 1.0)*(nodes[i] + 1.0) - 252*66ce82e0Sjeremylt (nodes[j] - 1.0)*(nodes[j] + 1.0); 25315ed3f7dSjeremylt CeedVectorRestoreArray(U, &u); 25415ed3f7dSjeremylt } 25515ed3f7dSjeremylt 25615ed3f7dSjeremylt // Apply original operator 25715ed3f7dSjeremylt CeedOperatorApply(op_apply, U, V, CEED_REQUEST_IMMEDIATE); 25815ed3f7dSjeremylt 25915ed3f7dSjeremylt // Apply FDM element inverse 26015ed3f7dSjeremylt { 26115ed3f7dSjeremylt // -- Zero corners 26215ed3f7dSjeremylt CeedScalar *v; 26315ed3f7dSjeremylt CeedVectorGetArray(V, CEED_MEM_HOST, &v); 26415ed3f7dSjeremylt v[0] = 0.0; 26515ed3f7dSjeremylt v[P-1] = 0.0; 26615ed3f7dSjeremylt v[P*P-P] = 0.0; 26715ed3f7dSjeremylt v[P*P-1] = 0.0; 26815ed3f7dSjeremylt CeedVectorRestoreArray(V, &v); 26915ed3f7dSjeremylt 27015ed3f7dSjeremylt // -- Apply FDM inverse to interior 27115ed3f7dSjeremylt CeedOperatorApply(op_inv, V, W, CEED_REQUEST_IMMEDIATE); 27215ed3f7dSjeremylt 27315ed3f7dSjeremylt // -- Pick off corners 27415ed3f7dSjeremylt const CeedScalar *w; 27515ed3f7dSjeremylt CeedScalar w_Pi[4]; 27615ed3f7dSjeremylt CeedVectorGetArrayRead(W, CEED_MEM_HOST, &w); 27715ed3f7dSjeremylt w_Pi[0] = w[0]; 27815ed3f7dSjeremylt w_Pi[1] = w[P-1]; 27915ed3f7dSjeremylt w_Pi[2] = w[P*P-P]; 28015ed3f7dSjeremylt w_Pi[3] = w[P*P-1]; 28115ed3f7dSjeremylt CeedVectorRestoreArrayRead(W, &w); 28215ed3f7dSjeremylt 28315ed3f7dSjeremylt // -- Apply inverse of Schur complement 28415ed3f7dSjeremylt CeedScalar v_Pi[4]; 28515ed3f7dSjeremylt for (CeedInt i=0; i<4; i++) { 28615ed3f7dSjeremylt CeedScalar sum = 0.0; 28715ed3f7dSjeremylt for (CeedInt j=0; j<4; j++) { 28815ed3f7dSjeremylt sum += w_Pi[j] * S_inv[i*4+j]; 28915ed3f7dSjeremylt } 29015ed3f7dSjeremylt v_Pi[i] = -sum; 29115ed3f7dSjeremylt } 29215ed3f7dSjeremylt 29315ed3f7dSjeremylt // -- Set corners 29415ed3f7dSjeremylt CeedVectorGetArray(V, CEED_MEM_HOST, &v); 29515ed3f7dSjeremylt v[0] = v_Pi[0]; 29615ed3f7dSjeremylt v[P-1] = v_Pi[1]; 29715ed3f7dSjeremylt v[P*P-P] = v_Pi[2]; 29815ed3f7dSjeremylt v[P*P-1] = v_Pi[3]; 29915ed3f7dSjeremylt CeedVectorRestoreArray(V, &v); 30015ed3f7dSjeremylt 30115ed3f7dSjeremylt // -- Apply full FDM inverse again 30215ed3f7dSjeremylt CeedOperatorApply(op_inv, V, W, CEED_REQUEST_IMMEDIATE); 30315ed3f7dSjeremylt } 30415ed3f7dSjeremylt 30515ed3f7dSjeremylt 30615ed3f7dSjeremylt // Check output 30715ed3f7dSjeremylt { 30815ed3f7dSjeremylt const CeedScalar *u, *w; 30915ed3f7dSjeremylt CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); 31015ed3f7dSjeremylt CeedVectorGetArrayRead(W, CEED_MEM_HOST, &w); 31115ed3f7dSjeremylt for (CeedInt i=0; i<P; i++) 31215ed3f7dSjeremylt for (CeedInt j=0; j<P; j++) 31315ed3f7dSjeremylt if (fabs(u[i*P+j] - w[i*P+j]) > 5e-14) 31415ed3f7dSjeremylt // LCOV_EXCL_START 31515ed3f7dSjeremylt printf("[%d, %d] Error in inverse: %e != %e\n", i, j, w[i*P+j], u[i*P+j]); 31615ed3f7dSjeremylt // LCOV_EXCL_STOP 31715ed3f7dSjeremylt CeedVectorRestoreArrayRead(U, &u); 31815ed3f7dSjeremylt CeedVectorRestoreArrayRead(W, &w); 31915ed3f7dSjeremylt } 32015ed3f7dSjeremylt 32115ed3f7dSjeremylt // Cleanup 32215ed3f7dSjeremylt CeedQFunctionDestroy(&qf_setup_diff); 32315ed3f7dSjeremylt CeedQFunctionDestroy(&qf_apply); 32415ed3f7dSjeremylt CeedOperatorDestroy(&op_setup_diff); 32515ed3f7dSjeremylt CeedOperatorDestroy(&op_apply); 32615ed3f7dSjeremylt CeedOperatorDestroy(&op_inv); 32715ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_u_i); 32815ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_x_i); 32915ed3f7dSjeremylt CeedElemRestrictionDestroy(&elem_restr_qd_i); 33015ed3f7dSjeremylt CeedBasisDestroy(&basis_x); 33115ed3f7dSjeremylt CeedBasisDestroy(&basis_u); 33215ed3f7dSjeremylt CeedVectorDestroy(&X); 33315ed3f7dSjeremylt CeedVectorDestroy(&q_data_diff); 33415ed3f7dSjeremylt CeedVectorDestroy(&U); 33515ed3f7dSjeremylt CeedVectorDestroy(&V); 33615ed3f7dSjeremylt CeedVectorDestroy(&W); 33715ed3f7dSjeremylt CeedDestroy(&ceed); 33815ed3f7dSjeremylt return 0; 33915ed3f7dSjeremylt } 340