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