xref: /libCEED/julia/LibCEED.jl/examples/ex1-volume-c.jl (revision 6cf3b68d14a6585b72105699d8534a500a16d388)
1*6cf3b68dSWill Paznerusing LibCEED.C, Printf, UnsafeArrays
2*6cf3b68dSWill Paznerusing LibCEED.C: CeedInt, CeedScalar
3*6cf3b68dSWill Pazner
4*6cf3b68dSWill Pazner# A structure used to pass additional data to f_build_mass
5*6cf3b68dSWill Paznermutable struct BuildContextC
6*6cf3b68dSWill Pazner    dim::CeedInt
7*6cf3b68dSWill Pazner    space_dim::CeedInt
8*6cf3b68dSWill Paznerend
9*6cf3b68dSWill Pazner
10*6cf3b68dSWill Pazner# libCEED Q-function for building quadrature data for a mass operator
11*6cf3b68dSWill Paznerfunction f_build_mass_c(
12*6cf3b68dSWill Pazner    ctx_ptr::Ptr{Cvoid},
13*6cf3b68dSWill Pazner    Q::CeedInt,
14*6cf3b68dSWill Pazner    in_ptr::Ptr{Ptr{CeedScalar}},
15*6cf3b68dSWill Pazner    out_ptr::Ptr{Ptr{CeedScalar}},
16*6cf3b68dSWill Pazner)
17*6cf3b68dSWill Pazner    # in[0] is Jacobians with shape [dim, nc=dim, Q]
18*6cf3b68dSWill Pazner    # in[1] is quadrature weights, size (Q)
19*6cf3b68dSWill Pazner    ctx = unsafe_load(Ptr{BuildContextC}(ctx_ptr))
20*6cf3b68dSWill Pazner    J = UnsafeArray(unsafe_load(in_ptr, 1), (Int(Q), Int(ctx.dim^2)))
21*6cf3b68dSWill Pazner    w = UnsafeArray(unsafe_load(in_ptr, 2), (Int(Q),))
22*6cf3b68dSWill Pazner    qdata = UnsafeArray(unsafe_load(out_ptr, 1), (Int(Q),))
23*6cf3b68dSWill Pazner    if ctx.dim == 1
24*6cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
25*6cf3b68dSWill Pazner            qdata[i] = J[i]*w[i]
26*6cf3b68dSWill Pazner        end
27*6cf3b68dSWill Pazner    elseif ctx.dim == 2
28*6cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
29*6cf3b68dSWill Pazner            qdata[i] = (J[i, 1]*J[i, 4] - J[i, 2]*J[i, 3])*w[i]
30*6cf3b68dSWill Pazner        end
31*6cf3b68dSWill Pazner    elseif ctx.dim == 3
32*6cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
33*6cf3b68dSWill Pazner            qdata[i] =
34*6cf3b68dSWill Pazner                (
35*6cf3b68dSWill Pazner                    J[i, 1]*(J[i, 5]*J[i, 9] - J[i, 6]*J[i, 8]) -
36*6cf3b68dSWill Pazner                    J[i, 2]*(J[i, 4]*J[i, 9] - J[i, 6]*J[i, 7]) +
37*6cf3b68dSWill Pazner                    J[i, 3]*(J[i, 4]*J[i, 8] - J[i, 5]*J[i, 7])
38*6cf3b68dSWill Pazner                )*w[i]
39*6cf3b68dSWill Pazner        end
40*6cf3b68dSWill Pazner    else
41*6cf3b68dSWill Pazner        error("Bad dimension")
42*6cf3b68dSWill Pazner    end
43*6cf3b68dSWill Pazner    return CeedInt(0)
44*6cf3b68dSWill Paznerend
45*6cf3b68dSWill Pazner
46*6cf3b68dSWill Pazner# libCEED Q-function for applying a mass operator
47*6cf3b68dSWill Paznerfunction f_apply_mass_c(
48*6cf3b68dSWill Pazner    ctx,
49*6cf3b68dSWill Pazner    Q::CeedInt,
50*6cf3b68dSWill Pazner    in_ptr::Ptr{Ptr{CeedScalar}},
51*6cf3b68dSWill Pazner    out_ptr::Ptr{Ptr{CeedScalar}},
52*6cf3b68dSWill Pazner)
53*6cf3b68dSWill Pazner    u = UnsafeArray(unsafe_load(in_ptr, 1), (Int(Q),))
54*6cf3b68dSWill Pazner    qdata = UnsafeArray(unsafe_load(in_ptr, 2), (Int(Q),))
55*6cf3b68dSWill Pazner    v = UnsafeArray(unsafe_load(out_ptr, 1), (Int(Q),))
56*6cf3b68dSWill Pazner    @inbounds @simd for i = 1:Q
57*6cf3b68dSWill Pazner        v[i] = qdata[i]*u[i]
58*6cf3b68dSWill Pazner    end
59*6cf3b68dSWill Pazner    return CeedInt(0)
60*6cf3b68dSWill Paznerend
61*6cf3b68dSWill Pazner
62*6cf3b68dSWill Paznerfunction get_cartesian_mesh_size_c(dim, order, prob_size)
63*6cf3b68dSWill Pazner    dims = zeros(Int, dim)
64*6cf3b68dSWill Pazner    # Use the approximate formula:
65*6cf3b68dSWill Pazner    #    prob_size ~ num_elem * order^dim
66*6cf3b68dSWill Pazner    num_elem = div(prob_size, order^dim)
67*6cf3b68dSWill Pazner    s = 0 # find s: num_elem/2 < 2^s <= num_elem
68*6cf3b68dSWill Pazner    while num_elem > 1
69*6cf3b68dSWill Pazner        num_elem = div(num_elem, 2)
70*6cf3b68dSWill Pazner        s += 1
71*6cf3b68dSWill Pazner    end
72*6cf3b68dSWill Pazner    r = s%dim
73*6cf3b68dSWill Pazner    for d = 1:dim
74*6cf3b68dSWill Pazner        sd = div(s, dim)
75*6cf3b68dSWill Pazner        if r > 0
76*6cf3b68dSWill Pazner            sd += 1
77*6cf3b68dSWill Pazner            r -= 1
78*6cf3b68dSWill Pazner        end
79*6cf3b68dSWill Pazner        dims[d] = 2^sd
80*6cf3b68dSWill Pazner    end
81*6cf3b68dSWill Pazner    dims
82*6cf3b68dSWill Paznerend
83*6cf3b68dSWill Pazner
84*6cf3b68dSWill Paznerfunction build_cartesian_restriction_c(
85*6cf3b68dSWill Pazner    ceed,
86*6cf3b68dSWill Pazner    dim,
87*6cf3b68dSWill Pazner    nxyz,
88*6cf3b68dSWill Pazner    order,
89*6cf3b68dSWill Pazner    ncomp,
90*6cf3b68dSWill Pazner    num_qpts;
91*6cf3b68dSWill Pazner    form_strided=false,
92*6cf3b68dSWill Pazner)
93*6cf3b68dSWill Pazner    p = order
94*6cf3b68dSWill Pazner    pp1 = p + 1
95*6cf3b68dSWill Pazner    nnodes = pp1^dim # number of scal. nodes per element
96*6cf3b68dSWill Pazner    elem_qpts = num_qpts^dim # number of qpts per element
97*6cf3b68dSWill Pazner    num_elem = 1
98*6cf3b68dSWill Pazner    scalar_size = 1
99*6cf3b68dSWill Pazner
100*6cf3b68dSWill Pazner    nd = p*nxyz .+ 1
101*6cf3b68dSWill Pazner    num_elem = prod(nxyz)
102*6cf3b68dSWill Pazner    scalar_size = prod(nd)
103*6cf3b68dSWill Pazner    size = scalar_size*ncomp
104*6cf3b68dSWill Pazner
105*6cf3b68dSWill Pazner    # elem:         0             1                 n-1
106*6cf3b68dSWill Pazner    #        |---*-...-*---|---*-...-*---|- ... -|--...--|
107*6cf3b68dSWill Pazner    # nnodes:   0   1    p-1  p  p+1       2*p             n*p
108*6cf3b68dSWill Pazner
109*6cf3b68dSWill Pazner    el_nodes = zeros(C.CeedInt, num_elem*nnodes)
110*6cf3b68dSWill Pazner    exyz = zeros(Int, dim)
111*6cf3b68dSWill Pazner    @inbounds for e = 0:(num_elem-1)
112*6cf3b68dSWill Pazner        re = e
113*6cf3b68dSWill Pazner        for d = 1:dim
114*6cf3b68dSWill Pazner            exyz[d] = re%nxyz[d]
115*6cf3b68dSWill Pazner            re = div(re, nxyz[d])
116*6cf3b68dSWill Pazner        end
117*6cf3b68dSWill Pazner        for lnodes = 0:(nnodes-1)
118*6cf3b68dSWill Pazner            gnodes = 0
119*6cf3b68dSWill Pazner            gnodes_stride = 1
120*6cf3b68dSWill Pazner            rnodes = lnodes
121*6cf3b68dSWill Pazner            for d = 1:dim
122*6cf3b68dSWill Pazner                gnodes += (exyz[d]*p + rnodes%pp1)*gnodes_stride
123*6cf3b68dSWill Pazner                gnodes_stride *= nd[d]
124*6cf3b68dSWill Pazner                rnodes = div(rnodes, pp1)
125*6cf3b68dSWill Pazner            end
126*6cf3b68dSWill Pazner            el_nodes[e*nnodes+lnodes+1] = gnodes
127*6cf3b68dSWill Pazner        end
128*6cf3b68dSWill Pazner    end
129*6cf3b68dSWill Pazner
130*6cf3b68dSWill Pazner    restr = Ref{C.CeedElemRestriction}()
131*6cf3b68dSWill Pazner    C.CeedElemRestrictionCreate(
132*6cf3b68dSWill Pazner        ceed[],
133*6cf3b68dSWill Pazner        num_elem,
134*6cf3b68dSWill Pazner        nnodes,
135*6cf3b68dSWill Pazner        ncomp,
136*6cf3b68dSWill Pazner        scalar_size,
137*6cf3b68dSWill Pazner        ncomp*scalar_size,
138*6cf3b68dSWill Pazner        C.CEED_MEM_HOST,
139*6cf3b68dSWill Pazner        C.CEED_COPY_VALUES,
140*6cf3b68dSWill Pazner        el_nodes,
141*6cf3b68dSWill Pazner        restr,
142*6cf3b68dSWill Pazner    )
143*6cf3b68dSWill Pazner    if form_strided
144*6cf3b68dSWill Pazner        restr_i = Ref{C.CeedElemRestriction}()
145*6cf3b68dSWill Pazner        err = C.CeedElemRestrictionCreateStrided(
146*6cf3b68dSWill Pazner            ceed[],
147*6cf3b68dSWill Pazner            num_elem,
148*6cf3b68dSWill Pazner            elem_qpts,
149*6cf3b68dSWill Pazner            ncomp,
150*6cf3b68dSWill Pazner            ncomp*elem_qpts*num_elem,
151*6cf3b68dSWill Pazner            C.CEED_STRIDES_BACKEND[],
152*6cf3b68dSWill Pazner            restr_i,
153*6cf3b68dSWill Pazner        )
154*6cf3b68dSWill Pazner        return size, restr, restr_i
155*6cf3b68dSWill Pazner    else
156*6cf3b68dSWill Pazner        return size, restr
157*6cf3b68dSWill Pazner    end
158*6cf3b68dSWill Paznerend
159*6cf3b68dSWill Pazner
160*6cf3b68dSWill Paznerfunction set_cartesian_mesh_coords_c(dim, nxyz, mesh_order, mesh_coords)
161*6cf3b68dSWill Pazner    p = mesh_order
162*6cf3b68dSWill Pazner    nd = p*nxyz .+ 1
163*6cf3b68dSWill Pazner    num_elem = prod(nxyz)
164*6cf3b68dSWill Pazner    scalar_size = prod(nd)
165*6cf3b68dSWill Pazner
166*6cf3b68dSWill Pazner    coords_ref = Ref{Ptr{C.CeedScalar}}()
167*6cf3b68dSWill Pazner    C.CeedVectorGetArray(mesh_coords[], C.CEED_MEM_HOST, coords_ref)
168*6cf3b68dSWill Pazner    coords = unsafe_wrap(Array, coords_ref[], scalar_size*dim)
169*6cf3b68dSWill Pazner
170*6cf3b68dSWill Pazner    nodes = zeros(C.CeedScalar, p + 1)
171*6cf3b68dSWill Pazner    # The H1 basis uses Lobatto quadrature points as nodes.
172*6cf3b68dSWill Pazner    C.CeedLobattoQuadrature(p + 1, nodes, C_NULL) # nodes are in [-1,1]
173*6cf3b68dSWill Pazner    nodes = 0.5 .+ 0.5*nodes
174*6cf3b68dSWill Pazner    for gsnodes = 0:(scalar_size-1)
175*6cf3b68dSWill Pazner        rnodes = gsnodes
176*6cf3b68dSWill Pazner        for d = 1:dim
177*6cf3b68dSWill Pazner            d1d = rnodes%nd[d]
178*6cf3b68dSWill Pazner            coords[gsnodes+scalar_size*(d-1)+1] = (div(d1d, p) + nodes[d1d%p+1])/nxyz[d]
179*6cf3b68dSWill Pazner            rnodes = div(rnodes, nd[d])
180*6cf3b68dSWill Pazner        end
181*6cf3b68dSWill Pazner    end
182*6cf3b68dSWill Pazner    C.CeedVectorRestoreArray(mesh_coords[], coords_ref)
183*6cf3b68dSWill Paznerend
184*6cf3b68dSWill Pazner
185*6cf3b68dSWill Paznerfunction transform_mesh_coords_c(dim, mesh_size, mesh_coords)
186*6cf3b68dSWill Pazner    coords_ref = Ref{Ptr{C.CeedScalar}}()
187*6cf3b68dSWill Pazner    C.CeedVectorGetArray(mesh_coords[], C.CEED_MEM_HOST, coords_ref)
188*6cf3b68dSWill Pazner    coords = unsafe_wrap(Array, coords_ref[], mesh_size)
189*6cf3b68dSWill Pazner
190*6cf3b68dSWill Pazner    if dim == 1
191*6cf3b68dSWill Pazner        for i = 1:mesh_size
192*6cf3b68dSWill Pazner            # map [0,1] to [0,1] varying the mesh density
193*6cf3b68dSWill Pazner            coords[i] = 0.5 + 1.0/sqrt(3.0)*sin((2.0/3.0)*pi*(coords[i] - 0.5))
194*6cf3b68dSWill Pazner        end
195*6cf3b68dSWill Pazner        exact_volume = 1
196*6cf3b68dSWill Pazner    else
197*6cf3b68dSWill Pazner        num_nodes = div(mesh_size, dim)
198*6cf3b68dSWill Pazner        for i = 1:num_nodes
199*6cf3b68dSWill Pazner            # map (x,y) from [0,1]x[0,1] to the quarter annulus with polar
200*6cf3b68dSWill Pazner            # coordinates, (r,phi) in [1,2]x[0,pi/2] with area = 3/4*pi
201*6cf3b68dSWill Pazner            u = coords[i]
202*6cf3b68dSWill Pazner            v = coords[i+num_nodes]
203*6cf3b68dSWill Pazner            u = 1.0 + u
204*6cf3b68dSWill Pazner            v = pi/2*v
205*6cf3b68dSWill Pazner            coords[i] = u*cos(v)
206*6cf3b68dSWill Pazner            coords[i+num_nodes] = u*sin(v)
207*6cf3b68dSWill Pazner        end
208*6cf3b68dSWill Pazner        exact_volume = 3.0/4.0*pi
209*6cf3b68dSWill Pazner    end
210*6cf3b68dSWill Pazner
211*6cf3b68dSWill Pazner    C.CeedVectorRestoreArray(mesh_coords[], coords_ref)
212*6cf3b68dSWill Pazner    return exact_volume
213*6cf3b68dSWill Paznerend
214*6cf3b68dSWill Pazner
215*6cf3b68dSWill Paznerfunction run_ex1_c(; ceed_spec, dim, mesh_order, sol_order, num_qpts, prob_size)
216*6cf3b68dSWill Pazner    ncompx = dim
217*6cf3b68dSWill Pazner    prob_size < 0 && (prob_size = 256*1024)
218*6cf3b68dSWill Pazner
219*6cf3b68dSWill Pazner    gallery = false
220*6cf3b68dSWill Pazner
221*6cf3b68dSWill Pazner    ceed = Ref{C.Ceed}()
222*6cf3b68dSWill Pazner    C.CeedInit(ceed_spec, ceed)
223*6cf3b68dSWill Pazner
224*6cf3b68dSWill Pazner    mesh_basis = Ref{C.CeedBasis}()
225*6cf3b68dSWill Pazner    sol_basis = Ref{C.CeedBasis}()
226*6cf3b68dSWill Pazner    C.CeedBasisCreateTensorH1Lagrange(
227*6cf3b68dSWill Pazner        ceed[],
228*6cf3b68dSWill Pazner        dim,
229*6cf3b68dSWill Pazner        ncompx,
230*6cf3b68dSWill Pazner        mesh_order + 1,
231*6cf3b68dSWill Pazner        num_qpts,
232*6cf3b68dSWill Pazner        C.CEED_GAUSS,
233*6cf3b68dSWill Pazner        mesh_basis,
234*6cf3b68dSWill Pazner    )
235*6cf3b68dSWill Pazner    C.CeedBasisCreateTensorH1Lagrange(
236*6cf3b68dSWill Pazner        ceed[],
237*6cf3b68dSWill Pazner        dim,
238*6cf3b68dSWill Pazner        1,
239*6cf3b68dSWill Pazner        sol_order + 1,
240*6cf3b68dSWill Pazner        num_qpts,
241*6cf3b68dSWill Pazner        C.CEED_GAUSS,
242*6cf3b68dSWill Pazner        sol_basis,
243*6cf3b68dSWill Pazner    )
244*6cf3b68dSWill Pazner
245*6cf3b68dSWill Pazner    # Determine the mesh size based on the given approximate problem size.
246*6cf3b68dSWill Pazner    nxyz = get_cartesian_mesh_size_c(dim, sol_order, prob_size)
247*6cf3b68dSWill Pazner    println("Mesh size: ", nxyz)
248*6cf3b68dSWill Pazner
249*6cf3b68dSWill Pazner    # Build CeedElemRestriction objects describing the mesh and solution discrete
250*6cf3b68dSWill Pazner    # representations.
251*6cf3b68dSWill Pazner    mesh_size, mesh_restr =
252*6cf3b68dSWill Pazner        build_cartesian_restriction_c(ceed, dim, nxyz, mesh_order, ncompx, num_qpts)
253*6cf3b68dSWill Pazner    sol_size, sol_restr, sol_restr_i = build_cartesian_restriction_c(
254*6cf3b68dSWill Pazner        ceed,
255*6cf3b68dSWill Pazner        dim,
256*6cf3b68dSWill Pazner        nxyz,
257*6cf3b68dSWill Pazner        sol_order,
258*6cf3b68dSWill Pazner        1,
259*6cf3b68dSWill Pazner        num_qpts,
260*6cf3b68dSWill Pazner        form_strided=true,
261*6cf3b68dSWill Pazner    )
262*6cf3b68dSWill Pazner    println("Number of mesh nodes     : ", div(mesh_size, dim))
263*6cf3b68dSWill Pazner    println("Number of solution nodes : ", sol_size)
264*6cf3b68dSWill Pazner
265*6cf3b68dSWill Pazner    # Create a C.CeedVector with the mesh coordinates.
266*6cf3b68dSWill Pazner    mesh_coords = Ref{C.CeedVector}()
267*6cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], mesh_size, mesh_coords)
268*6cf3b68dSWill Pazner    set_cartesian_mesh_coords_c(dim, nxyz, mesh_order, mesh_coords)
269*6cf3b68dSWill Pazner    # Apply a transformation to the mesh.
270*6cf3b68dSWill Pazner    exact_vol = transform_mesh_coords_c(dim, mesh_size, mesh_coords)
271*6cf3b68dSWill Pazner
272*6cf3b68dSWill Pazner    # Create the Q-function that builds the mass operator (i.e. computes its
273*6cf3b68dSWill Pazner    # quadrature data) and set its context data.
274*6cf3b68dSWill Pazner    build_qfunc = Ref{C.CeedQFunction}()
275*6cf3b68dSWill Pazner
276*6cf3b68dSWill Pazner    build_ctx = BuildContextC(dim, dim)
277*6cf3b68dSWill Pazner    qf_ctx = Ref{C.CeedQFunctionContext}()
278*6cf3b68dSWill Pazner    C.CeedQFunctionContextCreate(ceed[], qf_ctx)
279*6cf3b68dSWill Pazner    C.CeedQFunctionContextSetData(
280*6cf3b68dSWill Pazner        qf_ctx[],
281*6cf3b68dSWill Pazner        C.CEED_MEM_HOST,
282*6cf3b68dSWill Pazner        C.CEED_USE_POINTER,
283*6cf3b68dSWill Pazner        sizeof(build_ctx),
284*6cf3b68dSWill Pazner        pointer_from_objref(build_ctx),
285*6cf3b68dSWill Pazner    )
286*6cf3b68dSWill Pazner
287*6cf3b68dSWill Pazner    if !gallery
288*6cf3b68dSWill Pazner        qf_build_mass = @cfunction(
289*6cf3b68dSWill Pazner            f_build_mass_c,
290*6cf3b68dSWill Pazner            C.CeedInt,
291*6cf3b68dSWill Pazner            (Ptr{Cvoid}, C.CeedInt, Ptr{Ptr{C.CeedScalar}}, Ptr{Ptr{C.CeedScalar}})
292*6cf3b68dSWill Pazner        )
293*6cf3b68dSWill Pazner        # This creates the QFunction directly.
294*6cf3b68dSWill Pazner        C.CeedQFunctionCreateInterior(ceed[], 1, qf_build_mass, "julia", build_qfunc)
295*6cf3b68dSWill Pazner        C.CeedQFunctionAddInput(build_qfunc[], "dx", ncompx*dim, C.CEED_EVAL_GRAD)
296*6cf3b68dSWill Pazner        C.CeedQFunctionAddInput(build_qfunc[], "weights", 1, C.CEED_EVAL_WEIGHT)
297*6cf3b68dSWill Pazner        C.CeedQFunctionAddOutput(build_qfunc[], "qdata", 1, C.CEED_EVAL_NONE)
298*6cf3b68dSWill Pazner        C.CeedQFunctionSetContext(build_qfunc[], qf_ctx[])
299*6cf3b68dSWill Pazner    else
300*6cf3b68dSWill Pazner        # This creates the QFunction via the gallery.
301*6cf3b68dSWill Pazner        name = "Mass$(dim)DBuild"
302*6cf3b68dSWill Pazner        C.CeedQFunctionCreateInteriorByName(ceed[], name, build_qfunc)
303*6cf3b68dSWill Pazner    end
304*6cf3b68dSWill Pazner
305*6cf3b68dSWill Pazner    # Create the operator that builds the quadrature data for the mass operator.
306*6cf3b68dSWill Pazner    build_oper = Ref{C.CeedOperator}()
307*6cf3b68dSWill Pazner    C.CeedOperatorCreate(
308*6cf3b68dSWill Pazner        ceed[],
309*6cf3b68dSWill Pazner        build_qfunc[],
310*6cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
311*6cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
312*6cf3b68dSWill Pazner        build_oper,
313*6cf3b68dSWill Pazner    )
314*6cf3b68dSWill Pazner    C.CeedOperatorSetField(
315*6cf3b68dSWill Pazner        build_oper[],
316*6cf3b68dSWill Pazner        "dx",
317*6cf3b68dSWill Pazner        mesh_restr[],
318*6cf3b68dSWill Pazner        mesh_basis[],
319*6cf3b68dSWill Pazner        C.CEED_VECTOR_ACTIVE[],
320*6cf3b68dSWill Pazner    )
321*6cf3b68dSWill Pazner    C.CeedOperatorSetField(
322*6cf3b68dSWill Pazner        build_oper[],
323*6cf3b68dSWill Pazner        "weights",
324*6cf3b68dSWill Pazner        C.CEED_ELEMRESTRICTION_NONE[],
325*6cf3b68dSWill Pazner        mesh_basis[],
326*6cf3b68dSWill Pazner        C.CEED_VECTOR_NONE[],
327*6cf3b68dSWill Pazner    )
328*6cf3b68dSWill Pazner    C.CeedOperatorSetField(
329*6cf3b68dSWill Pazner        build_oper[],
330*6cf3b68dSWill Pazner        "qdata",
331*6cf3b68dSWill Pazner        sol_restr_i[],
332*6cf3b68dSWill Pazner        C.CEED_BASIS_COLLOCATED[],
333*6cf3b68dSWill Pazner        C.CEED_VECTOR_ACTIVE[],
334*6cf3b68dSWill Pazner    )
335*6cf3b68dSWill Pazner
336*6cf3b68dSWill Pazner    # Compute the quadrature data for the mass operator.
337*6cf3b68dSWill Pazner    qdata = Ref{C.CeedVector}()
338*6cf3b68dSWill Pazner    elem_qpts = num_qpts^dim
339*6cf3b68dSWill Pazner    num_elem = prod(nxyz)
340*6cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], num_elem*elem_qpts, qdata)
341*6cf3b68dSWill Pazner
342*6cf3b68dSWill Pazner    print("Computing the quadrature data for the mass operator ...")
343*6cf3b68dSWill Pazner    flush(stdout)
344*6cf3b68dSWill Pazner    GC.@preserve build_ctx C.CeedOperatorApply(
345*6cf3b68dSWill Pazner        build_oper[],
346*6cf3b68dSWill Pazner        mesh_coords[],
347*6cf3b68dSWill Pazner        qdata[],
348*6cf3b68dSWill Pazner        C.CEED_REQUEST_IMMEDIATE[],
349*6cf3b68dSWill Pazner    )
350*6cf3b68dSWill Pazner    println(" done.")
351*6cf3b68dSWill Pazner
352*6cf3b68dSWill Pazner    # Create the Q-function that defines the action of the mass operator.
353*6cf3b68dSWill Pazner    apply_qfunc = Ref{C.CeedQFunction}()
354*6cf3b68dSWill Pazner    if !gallery
355*6cf3b68dSWill Pazner        qf_apply_mass = @cfunction(
356*6cf3b68dSWill Pazner            f_apply_mass_c,
357*6cf3b68dSWill Pazner            C.CeedInt,
358*6cf3b68dSWill Pazner            (Ptr{Cvoid}, C.CeedInt, Ptr{Ptr{C.CeedScalar}}, Ptr{Ptr{C.CeedScalar}})
359*6cf3b68dSWill Pazner        )
360*6cf3b68dSWill Pazner        # This creates the QFunction directly.
361*6cf3b68dSWill Pazner        C.CeedQFunctionCreateInterior(ceed[], 1, qf_apply_mass, "julia", apply_qfunc)
362*6cf3b68dSWill Pazner        C.CeedQFunctionAddInput(apply_qfunc[], "u", 1, C.CEED_EVAL_INTERP)
363*6cf3b68dSWill Pazner        C.CeedQFunctionAddInput(apply_qfunc[], "qdata", 1, C.CEED_EVAL_NONE)
364*6cf3b68dSWill Pazner        C.CeedQFunctionAddOutput(apply_qfunc[], "v", 1, C.CEED_EVAL_INTERP)
365*6cf3b68dSWill Pazner    else
366*6cf3b68dSWill Pazner        # This creates the QFunction via the gallery.
367*6cf3b68dSWill Pazner        C.CeedQFunctionCreateInteriorByName(ceed[], "MassApply", apply_qfunc)
368*6cf3b68dSWill Pazner    end
369*6cf3b68dSWill Pazner
370*6cf3b68dSWill Pazner    # Create the mass operator.
371*6cf3b68dSWill Pazner    oper = Ref{C.CeedOperator}()
372*6cf3b68dSWill Pazner    C.CeedOperatorCreate(
373*6cf3b68dSWill Pazner        ceed[],
374*6cf3b68dSWill Pazner        apply_qfunc[],
375*6cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
376*6cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
377*6cf3b68dSWill Pazner        oper,
378*6cf3b68dSWill Pazner    )
379*6cf3b68dSWill Pazner    C.CeedOperatorSetField(oper[], "u", sol_restr[], sol_basis[], C.CEED_VECTOR_ACTIVE[])
380*6cf3b68dSWill Pazner    C.CeedOperatorSetField(
381*6cf3b68dSWill Pazner        oper[],
382*6cf3b68dSWill Pazner        "qdata",
383*6cf3b68dSWill Pazner        sol_restr_i[],
384*6cf3b68dSWill Pazner        C.CEED_BASIS_COLLOCATED[],
385*6cf3b68dSWill Pazner        qdata[],
386*6cf3b68dSWill Pazner    )
387*6cf3b68dSWill Pazner    C.CeedOperatorSetField(oper[], "v", sol_restr[], sol_basis[], C.CEED_VECTOR_ACTIVE[])
388*6cf3b68dSWill Pazner
389*6cf3b68dSWill Pazner    # Compute the mesh volume using the mass operator: vol = 1^T \cdot M \cdot 1
390*6cf3b68dSWill Pazner    print("Computing the mesh volume using the formula: vol = 1^T.M.1 ...")
391*6cf3b68dSWill Pazner    flush(stdout)
392*6cf3b68dSWill Pazner    # Create auxiliary solution-size vectors.
393*6cf3b68dSWill Pazner    u = Ref{C.CeedVector}()
394*6cf3b68dSWill Pazner    v = Ref{C.CeedVector}()
395*6cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], sol_size, u)
396*6cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], sol_size, v)
397*6cf3b68dSWill Pazner
398*6cf3b68dSWill Pazner    # Initialize 'u' with ones.
399*6cf3b68dSWill Pazner    C.CeedVectorSetValue(u[], 1.0)
400*6cf3b68dSWill Pazner
401*6cf3b68dSWill Pazner    # Apply the mass operator: 'u' -> 'v'.
402*6cf3b68dSWill Pazner    C.CeedOperatorApply(oper[], u[], v[], C.CEED_REQUEST_IMMEDIATE[])
403*6cf3b68dSWill Pazner
404*6cf3b68dSWill Pazner    # Compute and print the sum of the entries of 'v' giving the mesh volume.
405*6cf3b68dSWill Pazner    v_host_ref = Ref{Ptr{C.CeedScalar}}()
406*6cf3b68dSWill Pazner    C.CeedVectorGetArrayRead(v[], C.CEED_MEM_HOST, v_host_ref)
407*6cf3b68dSWill Pazner    v_host = unsafe_wrap(Array, v_host_ref[], sol_size)
408*6cf3b68dSWill Pazner    vol = sum(v_host)
409*6cf3b68dSWill Pazner    C.CeedVectorRestoreArrayRead(v[], v_host_ref)
410*6cf3b68dSWill Pazner
411*6cf3b68dSWill Pazner    println(" done.")
412*6cf3b68dSWill Pazner    @printf("Exact mesh volume    : % .14g\n", exact_vol)
413*6cf3b68dSWill Pazner    @printf("Computed mesh volume : % .14g\n", vol)
414*6cf3b68dSWill Pazner    @printf("Volume error         : % .14g\n", vol - exact_vol)
415*6cf3b68dSWill Pazner
416*6cf3b68dSWill Pazner    # Free dynamically allocated memory.
417*6cf3b68dSWill Pazner    C.CeedVectorDestroy(u)
418*6cf3b68dSWill Pazner    C.CeedVectorDestroy(v)
419*6cf3b68dSWill Pazner    C.CeedVectorDestroy(qdata)
420*6cf3b68dSWill Pazner    C.CeedVectorDestroy(mesh_coords)
421*6cf3b68dSWill Pazner    C.CeedOperatorDestroy(oper)
422*6cf3b68dSWill Pazner    C.CeedQFunctionDestroy(apply_qfunc)
423*6cf3b68dSWill Pazner    C.CeedOperatorDestroy(build_oper)
424*6cf3b68dSWill Pazner    C.CeedQFunctionDestroy(build_qfunc)
425*6cf3b68dSWill Pazner    C.CeedElemRestrictionDestroy(sol_restr)
426*6cf3b68dSWill Pazner    C.CeedElemRestrictionDestroy(mesh_restr)
427*6cf3b68dSWill Pazner    C.CeedElemRestrictionDestroy(sol_restr_i)
428*6cf3b68dSWill Pazner    C.CeedBasisDestroy(sol_basis)
429*6cf3b68dSWill Pazner    C.CeedBasisDestroy(mesh_basis)
430*6cf3b68dSWill Pazner    C.CeedDestroy(ceed)
431*6cf3b68dSWill Paznerend
432*6cf3b68dSWill Pazner
433*6cf3b68dSWill Paznerrun_ex1_c(
434*6cf3b68dSWill Pazner    ceed_spec="/cpu/self",
435*6cf3b68dSWill Pazner    dim=3,
436*6cf3b68dSWill Pazner    mesh_order=4,
437*6cf3b68dSWill Pazner    sol_order=4,
438*6cf3b68dSWill Pazner    num_qpts=4 + 2,
439*6cf3b68dSWill Pazner    prob_size=-1,
440*6cf3b68dSWill Pazner)
441