xref: /libCEED/julia/LibCEED.jl/examples/ex1-volume-c.jl (revision 21f16bf6c2940c092555e126518ed0c98a2b88a9)
16cf3b68dSWill Paznerusing LibCEED.C, Printf, UnsafeArrays
26cf3b68dSWill Paznerusing LibCEED.C: CeedInt, CeedScalar
36cf3b68dSWill Pazner
46cf3b68dSWill Pazner# A structure used to pass additional data to f_build_mass
56cf3b68dSWill Paznermutable struct BuildContextC
66cf3b68dSWill Pazner    dim::CeedInt
76cf3b68dSWill Pazner    space_dim::CeedInt
86cf3b68dSWill Paznerend
96cf3b68dSWill Pazner
106cf3b68dSWill Pazner# libCEED Q-function for building quadrature data for a mass operator
116cf3b68dSWill Paznerfunction f_build_mass_c(
126cf3b68dSWill Pazner    ctx_ptr::Ptr{Cvoid},
136cf3b68dSWill Pazner    Q::CeedInt,
146cf3b68dSWill Pazner    in_ptr::Ptr{Ptr{CeedScalar}},
156cf3b68dSWill Pazner    out_ptr::Ptr{Ptr{CeedScalar}},
166cf3b68dSWill Pazner)
176cf3b68dSWill Pazner    # in[0] is Jacobians with shape [dim, nc=dim, Q]
186cf3b68dSWill Pazner    # in[1] is quadrature weights, size (Q)
196cf3b68dSWill Pazner    ctx = unsafe_load(Ptr{BuildContextC}(ctx_ptr))
206cf3b68dSWill Pazner    J = UnsafeArray(unsafe_load(in_ptr, 1), (Int(Q), Int(ctx.dim^2)))
216cf3b68dSWill Pazner    w = UnsafeArray(unsafe_load(in_ptr, 2), (Int(Q),))
226cf3b68dSWill Pazner    qdata = UnsafeArray(unsafe_load(out_ptr, 1), (Int(Q),))
236cf3b68dSWill Pazner    if ctx.dim == 1
246cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
256cf3b68dSWill Pazner            qdata[i] = J[i]*w[i]
266cf3b68dSWill Pazner        end
276cf3b68dSWill Pazner    elseif ctx.dim == 2
286cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
296cf3b68dSWill Pazner            qdata[i] = (J[i, 1]*J[i, 4] - J[i, 2]*J[i, 3])*w[i]
306cf3b68dSWill Pazner        end
316cf3b68dSWill Pazner    elseif ctx.dim == 3
326cf3b68dSWill Pazner        @inbounds @simd for i = 1:Q
336cf3b68dSWill Pazner            qdata[i] =
346cf3b68dSWill Pazner                (
356cf3b68dSWill Pazner                    J[i, 1]*(J[i, 5]*J[i, 9] - J[i, 6]*J[i, 8]) -
366cf3b68dSWill Pazner                    J[i, 2]*(J[i, 4]*J[i, 9] - J[i, 6]*J[i, 7]) +
376cf3b68dSWill Pazner                    J[i, 3]*(J[i, 4]*J[i, 8] - J[i, 5]*J[i, 7])
386cf3b68dSWill Pazner                )*w[i]
396cf3b68dSWill Pazner        end
406cf3b68dSWill Pazner    else
416cf3b68dSWill Pazner        error("Bad dimension")
426cf3b68dSWill Pazner    end
436cf3b68dSWill Pazner    return CeedInt(0)
446cf3b68dSWill Paznerend
456cf3b68dSWill Pazner
466cf3b68dSWill Pazner# libCEED Q-function for applying a mass operator
476cf3b68dSWill Paznerfunction f_apply_mass_c(
486cf3b68dSWill Pazner    ctx,
496cf3b68dSWill Pazner    Q::CeedInt,
506cf3b68dSWill Pazner    in_ptr::Ptr{Ptr{CeedScalar}},
516cf3b68dSWill Pazner    out_ptr::Ptr{Ptr{CeedScalar}},
526cf3b68dSWill Pazner)
536cf3b68dSWill Pazner    u = UnsafeArray(unsafe_load(in_ptr, 1), (Int(Q),))
546cf3b68dSWill Pazner    qdata = UnsafeArray(unsafe_load(in_ptr, 2), (Int(Q),))
556cf3b68dSWill Pazner    v = UnsafeArray(unsafe_load(out_ptr, 1), (Int(Q),))
566cf3b68dSWill Pazner    @inbounds @simd for i = 1:Q
576cf3b68dSWill Pazner        v[i] = qdata[i]*u[i]
586cf3b68dSWill Pazner    end
596cf3b68dSWill Pazner    return CeedInt(0)
606cf3b68dSWill Paznerend
616cf3b68dSWill Pazner
626cf3b68dSWill Paznerfunction get_cartesian_mesh_size_c(dim, order, prob_size)
636cf3b68dSWill Pazner    dims = zeros(Int, dim)
646cf3b68dSWill Pazner    # Use the approximate formula:
656cf3b68dSWill Pazner    #    prob_size ~ num_elem * order^dim
666cf3b68dSWill Pazner    num_elem = div(prob_size, order^dim)
676cf3b68dSWill Pazner    s = 0 # find s: num_elem/2 < 2^s <= num_elem
686cf3b68dSWill Pazner    while num_elem > 1
696cf3b68dSWill Pazner        num_elem = div(num_elem, 2)
706cf3b68dSWill Pazner        s += 1
716cf3b68dSWill Pazner    end
726cf3b68dSWill Pazner    r = s%dim
736cf3b68dSWill Pazner    for d = 1:dim
746cf3b68dSWill Pazner        sd = div(s, dim)
756cf3b68dSWill Pazner        if r > 0
766cf3b68dSWill Pazner            sd += 1
776cf3b68dSWill Pazner            r -= 1
786cf3b68dSWill Pazner        end
796cf3b68dSWill Pazner        dims[d] = 2^sd
806cf3b68dSWill Pazner    end
816cf3b68dSWill Pazner    dims
826cf3b68dSWill Paznerend
836cf3b68dSWill Pazner
846cf3b68dSWill Paznerfunction build_cartesian_restriction_c(
856cf3b68dSWill Pazner    ceed,
866cf3b68dSWill Pazner    dim,
876cf3b68dSWill Pazner    nxyz,
886cf3b68dSWill Pazner    order,
896cf3b68dSWill Pazner    ncomp,
906cf3b68dSWill Pazner    num_qpts;
916cf3b68dSWill Pazner    form_strided=false,
926cf3b68dSWill Pazner)
936cf3b68dSWill Pazner    p = order
946cf3b68dSWill Pazner    pp1 = p + 1
956cf3b68dSWill Pazner    nnodes = pp1^dim # number of scal. nodes per element
966cf3b68dSWill Pazner    elem_qpts = num_qpts^dim # number of qpts per element
976cf3b68dSWill Pazner    num_elem = 1
986cf3b68dSWill Pazner    scalar_size = 1
996cf3b68dSWill Pazner
1006cf3b68dSWill Pazner    nd = p*nxyz .+ 1
1016cf3b68dSWill Pazner    num_elem = prod(nxyz)
1026cf3b68dSWill Pazner    scalar_size = prod(nd)
1036cf3b68dSWill Pazner    size = scalar_size*ncomp
1046cf3b68dSWill Pazner
1056cf3b68dSWill Pazner    # elem:         0             1                 n-1
1066cf3b68dSWill Pazner    #        |---*-...-*---|---*-...-*---|- ... -|--...--|
1076cf3b68dSWill Pazner    # nnodes:   0   1    p-1  p  p+1       2*p             n*p
1086cf3b68dSWill Pazner
1096cf3b68dSWill Pazner    el_nodes = zeros(C.CeedInt, num_elem*nnodes)
1106cf3b68dSWill Pazner    exyz = zeros(Int, dim)
1116cf3b68dSWill Pazner    @inbounds for e = 0:(num_elem-1)
1126cf3b68dSWill Pazner        re = e
1136cf3b68dSWill Pazner        for d = 1:dim
1146cf3b68dSWill Pazner            exyz[d] = re%nxyz[d]
1156cf3b68dSWill Pazner            re = div(re, nxyz[d])
1166cf3b68dSWill Pazner        end
1176cf3b68dSWill Pazner        for lnodes = 0:(nnodes-1)
1186cf3b68dSWill Pazner            gnodes = 0
1196cf3b68dSWill Pazner            gnodes_stride = 1
1206cf3b68dSWill Pazner            rnodes = lnodes
1216cf3b68dSWill Pazner            for d = 1:dim
1226cf3b68dSWill Pazner                gnodes += (exyz[d]*p + rnodes%pp1)*gnodes_stride
1236cf3b68dSWill Pazner                gnodes_stride *= nd[d]
1246cf3b68dSWill Pazner                rnodes = div(rnodes, pp1)
1256cf3b68dSWill Pazner            end
1266cf3b68dSWill Pazner            el_nodes[e*nnodes+lnodes+1] = gnodes
1276cf3b68dSWill Pazner        end
1286cf3b68dSWill Pazner    end
1296cf3b68dSWill Pazner
130*edb2538eSJeremy L Thompson    rstr = Ref{C.CeedElemRestriction}()
1316cf3b68dSWill Pazner    C.CeedElemRestrictionCreate(
1326cf3b68dSWill Pazner        ceed[],
1336cf3b68dSWill Pazner        num_elem,
1346cf3b68dSWill Pazner        nnodes,
1356cf3b68dSWill Pazner        ncomp,
1366cf3b68dSWill Pazner        scalar_size,
1376cf3b68dSWill Pazner        ncomp*scalar_size,
1386cf3b68dSWill Pazner        C.CEED_MEM_HOST,
1396cf3b68dSWill Pazner        C.CEED_COPY_VALUES,
1406cf3b68dSWill Pazner        el_nodes,
141*edb2538eSJeremy L Thompson        rstr,
1426cf3b68dSWill Pazner    )
1436cf3b68dSWill Pazner    if form_strided
144*edb2538eSJeremy L Thompson        rstr_i = Ref{C.CeedElemRestriction}()
1456cf3b68dSWill Pazner        err = C.CeedElemRestrictionCreateStrided(
1466cf3b68dSWill Pazner            ceed[],
1476cf3b68dSWill Pazner            num_elem,
1486cf3b68dSWill Pazner            elem_qpts,
1496cf3b68dSWill Pazner            ncomp,
1506cf3b68dSWill Pazner            ncomp*elem_qpts*num_elem,
1516cf3b68dSWill Pazner            C.CEED_STRIDES_BACKEND[],
152*edb2538eSJeremy L Thompson            rstr_i,
1536cf3b68dSWill Pazner        )
154*edb2538eSJeremy L Thompson        return size, rstr, rstr_i
1556cf3b68dSWill Pazner    else
156*edb2538eSJeremy L Thompson        return size, rstr
1576cf3b68dSWill Pazner    end
1586cf3b68dSWill Paznerend
1596cf3b68dSWill Pazner
1606cf3b68dSWill Paznerfunction set_cartesian_mesh_coords_c(dim, nxyz, mesh_order, mesh_coords)
1616cf3b68dSWill Pazner    p = mesh_order
1626cf3b68dSWill Pazner    nd = p*nxyz .+ 1
1636cf3b68dSWill Pazner    num_elem = prod(nxyz)
1646cf3b68dSWill Pazner    scalar_size = prod(nd)
1656cf3b68dSWill Pazner
1666cf3b68dSWill Pazner    coords_ref = Ref{Ptr{C.CeedScalar}}()
1676cf3b68dSWill Pazner    C.CeedVectorGetArray(mesh_coords[], C.CEED_MEM_HOST, coords_ref)
1686cf3b68dSWill Pazner    coords = unsafe_wrap(Array, coords_ref[], scalar_size*dim)
1696cf3b68dSWill Pazner
1706cf3b68dSWill Pazner    nodes = zeros(C.CeedScalar, p + 1)
1716cf3b68dSWill Pazner    # The H1 basis uses Lobatto quadrature points as nodes.
1726cf3b68dSWill Pazner    C.CeedLobattoQuadrature(p + 1, nodes, C_NULL) # nodes are in [-1,1]
1736cf3b68dSWill Pazner    nodes = 0.5 .+ 0.5*nodes
1746cf3b68dSWill Pazner    for gsnodes = 0:(scalar_size-1)
1756cf3b68dSWill Pazner        rnodes = gsnodes
1766cf3b68dSWill Pazner        for d = 1:dim
1776cf3b68dSWill Pazner            d1d = rnodes%nd[d]
1786cf3b68dSWill Pazner            coords[gsnodes+scalar_size*(d-1)+1] = (div(d1d, p) + nodes[d1d%p+1])/nxyz[d]
1796cf3b68dSWill Pazner            rnodes = div(rnodes, nd[d])
1806cf3b68dSWill Pazner        end
1816cf3b68dSWill Pazner    end
1826cf3b68dSWill Pazner    C.CeedVectorRestoreArray(mesh_coords[], coords_ref)
1836cf3b68dSWill Paznerend
1846cf3b68dSWill Pazner
1856cf3b68dSWill Paznerfunction transform_mesh_coords_c(dim, mesh_size, mesh_coords)
1866cf3b68dSWill Pazner    coords_ref = Ref{Ptr{C.CeedScalar}}()
1876cf3b68dSWill Pazner    C.CeedVectorGetArray(mesh_coords[], C.CEED_MEM_HOST, coords_ref)
1886cf3b68dSWill Pazner    coords = unsafe_wrap(Array, coords_ref[], mesh_size)
1896cf3b68dSWill Pazner
1906cf3b68dSWill Pazner    if dim == 1
1916cf3b68dSWill Pazner        for i = 1:mesh_size
1926cf3b68dSWill Pazner            # map [0,1] to [0,1] varying the mesh density
1936cf3b68dSWill Pazner            coords[i] = 0.5 + 1.0/sqrt(3.0)*sin((2.0/3.0)*pi*(coords[i] - 0.5))
1946cf3b68dSWill Pazner        end
1956cf3b68dSWill Pazner        exact_volume = 1
1966cf3b68dSWill Pazner    else
1976cf3b68dSWill Pazner        num_nodes = div(mesh_size, dim)
1986cf3b68dSWill Pazner        for i = 1:num_nodes
1996cf3b68dSWill Pazner            # map (x,y) from [0,1]x[0,1] to the quarter annulus with polar
2006cf3b68dSWill Pazner            # coordinates, (r,phi) in [1,2]x[0,pi/2] with area = 3/4*pi
2016cf3b68dSWill Pazner            u = coords[i]
2026cf3b68dSWill Pazner            v = coords[i+num_nodes]
2036cf3b68dSWill Pazner            u = 1.0 + u
2046cf3b68dSWill Pazner            v = pi/2*v
2056cf3b68dSWill Pazner            coords[i] = u*cos(v)
2066cf3b68dSWill Pazner            coords[i+num_nodes] = u*sin(v)
2076cf3b68dSWill Pazner        end
2086cf3b68dSWill Pazner        exact_volume = 3.0/4.0*pi
2096cf3b68dSWill Pazner    end
2106cf3b68dSWill Pazner
2116cf3b68dSWill Pazner    C.CeedVectorRestoreArray(mesh_coords[], coords_ref)
2126cf3b68dSWill Pazner    return exact_volume
2136cf3b68dSWill Paznerend
2146cf3b68dSWill Pazner
2156cf3b68dSWill Paznerfunction run_ex1_c(; ceed_spec, dim, mesh_order, sol_order, num_qpts, prob_size)
2166cf3b68dSWill Pazner    ncompx = dim
2176cf3b68dSWill Pazner    prob_size < 0 && (prob_size = 256*1024)
2186cf3b68dSWill Pazner
2196cf3b68dSWill Pazner    gallery = false
2206cf3b68dSWill Pazner
2216cf3b68dSWill Pazner    ceed = Ref{C.Ceed}()
2226cf3b68dSWill Pazner    C.CeedInit(ceed_spec, ceed)
2236cf3b68dSWill Pazner
2246cf3b68dSWill Pazner    mesh_basis = Ref{C.CeedBasis}()
2256cf3b68dSWill Pazner    sol_basis = Ref{C.CeedBasis}()
2266cf3b68dSWill Pazner    C.CeedBasisCreateTensorH1Lagrange(
2276cf3b68dSWill Pazner        ceed[],
2286cf3b68dSWill Pazner        dim,
2296cf3b68dSWill Pazner        ncompx,
2306cf3b68dSWill Pazner        mesh_order + 1,
2316cf3b68dSWill Pazner        num_qpts,
2326cf3b68dSWill Pazner        C.CEED_GAUSS,
2336cf3b68dSWill Pazner        mesh_basis,
2346cf3b68dSWill Pazner    )
2356cf3b68dSWill Pazner    C.CeedBasisCreateTensorH1Lagrange(
2366cf3b68dSWill Pazner        ceed[],
2376cf3b68dSWill Pazner        dim,
2386cf3b68dSWill Pazner        1,
2396cf3b68dSWill Pazner        sol_order + 1,
2406cf3b68dSWill Pazner        num_qpts,
2416cf3b68dSWill Pazner        C.CEED_GAUSS,
2426cf3b68dSWill Pazner        sol_basis,
2436cf3b68dSWill Pazner    )
2446cf3b68dSWill Pazner
2456cf3b68dSWill Pazner    # Determine the mesh size based on the given approximate problem size.
2466cf3b68dSWill Pazner    nxyz = get_cartesian_mesh_size_c(dim, sol_order, prob_size)
2476cf3b68dSWill Pazner    println("Mesh size: ", nxyz)
2486cf3b68dSWill Pazner
2496cf3b68dSWill Pazner    # Build CeedElemRestriction objects describing the mesh and solution discrete
2506cf3b68dSWill Pazner    # representations.
251*edb2538eSJeremy L Thompson    mesh_size, mesh_rstr =
2526cf3b68dSWill Pazner        build_cartesian_restriction_c(ceed, dim, nxyz, mesh_order, ncompx, num_qpts)
253*edb2538eSJeremy L Thompson    sol_size, sol_rstr, sol_rstr_i = build_cartesian_restriction_c(
2546cf3b68dSWill Pazner        ceed,
2556cf3b68dSWill Pazner        dim,
2566cf3b68dSWill Pazner        nxyz,
2576cf3b68dSWill Pazner        sol_order,
2586cf3b68dSWill Pazner        1,
2596cf3b68dSWill Pazner        num_qpts,
2606cf3b68dSWill Pazner        form_strided=true,
2616cf3b68dSWill Pazner    )
2626cf3b68dSWill Pazner    println("Number of mesh nodes     : ", div(mesh_size, dim))
2636cf3b68dSWill Pazner    println("Number of solution nodes : ", sol_size)
2646cf3b68dSWill Pazner
2656cf3b68dSWill Pazner    # Create a C.CeedVector with the mesh coordinates.
2666cf3b68dSWill Pazner    mesh_coords = Ref{C.CeedVector}()
2676cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], mesh_size, mesh_coords)
2686cf3b68dSWill Pazner    set_cartesian_mesh_coords_c(dim, nxyz, mesh_order, mesh_coords)
2696cf3b68dSWill Pazner    # Apply a transformation to the mesh.
2706cf3b68dSWill Pazner    exact_vol = transform_mesh_coords_c(dim, mesh_size, mesh_coords)
2716cf3b68dSWill Pazner
2726cf3b68dSWill Pazner    # Create the Q-function that builds the mass operator (i.e. computes its
2736cf3b68dSWill Pazner    # quadrature data) and set its context data.
2746cf3b68dSWill Pazner    build_qfunc = Ref{C.CeedQFunction}()
2756cf3b68dSWill Pazner
2766cf3b68dSWill Pazner    build_ctx = BuildContextC(dim, dim)
2776cf3b68dSWill Pazner    qf_ctx = Ref{C.CeedQFunctionContext}()
2786cf3b68dSWill Pazner    C.CeedQFunctionContextCreate(ceed[], qf_ctx)
2796cf3b68dSWill Pazner    C.CeedQFunctionContextSetData(
2806cf3b68dSWill Pazner        qf_ctx[],
2816cf3b68dSWill Pazner        C.CEED_MEM_HOST,
2826cf3b68dSWill Pazner        C.CEED_USE_POINTER,
2836cf3b68dSWill Pazner        sizeof(build_ctx),
2846cf3b68dSWill Pazner        pointer_from_objref(build_ctx),
2856cf3b68dSWill Pazner    )
2866cf3b68dSWill Pazner
2876cf3b68dSWill Pazner    if !gallery
2886cf3b68dSWill Pazner        qf_build_mass = @cfunction(
2896cf3b68dSWill Pazner            f_build_mass_c,
2906cf3b68dSWill Pazner            C.CeedInt,
2916cf3b68dSWill Pazner            (Ptr{Cvoid}, C.CeedInt, Ptr{Ptr{C.CeedScalar}}, Ptr{Ptr{C.CeedScalar}})
2926cf3b68dSWill Pazner        )
2936cf3b68dSWill Pazner        # This creates the QFunction directly.
2946cf3b68dSWill Pazner        C.CeedQFunctionCreateInterior(ceed[], 1, qf_build_mass, "julia", build_qfunc)
2956cf3b68dSWill Pazner        C.CeedQFunctionAddInput(build_qfunc[], "dx", ncompx*dim, C.CEED_EVAL_GRAD)
2966cf3b68dSWill Pazner        C.CeedQFunctionAddInput(build_qfunc[], "weights", 1, C.CEED_EVAL_WEIGHT)
2976cf3b68dSWill Pazner        C.CeedQFunctionAddOutput(build_qfunc[], "qdata", 1, C.CEED_EVAL_NONE)
2986cf3b68dSWill Pazner        C.CeedQFunctionSetContext(build_qfunc[], qf_ctx[])
2996cf3b68dSWill Pazner    else
3006cf3b68dSWill Pazner        # This creates the QFunction via the gallery.
3016cf3b68dSWill Pazner        name = "Mass$(dim)DBuild"
3026cf3b68dSWill Pazner        C.CeedQFunctionCreateInteriorByName(ceed[], name, build_qfunc)
3036cf3b68dSWill Pazner    end
3046cf3b68dSWill Pazner
3056cf3b68dSWill Pazner    # Create the operator that builds the quadrature data for the mass operator.
3066cf3b68dSWill Pazner    build_oper = Ref{C.CeedOperator}()
3076cf3b68dSWill Pazner    C.CeedOperatorCreate(
3086cf3b68dSWill Pazner        ceed[],
3096cf3b68dSWill Pazner        build_qfunc[],
3106cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
3116cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
3126cf3b68dSWill Pazner        build_oper,
3136cf3b68dSWill Pazner    )
3146cf3b68dSWill Pazner    C.CeedOperatorSetField(
3156cf3b68dSWill Pazner        build_oper[],
3166cf3b68dSWill Pazner        "dx",
317*edb2538eSJeremy L Thompson        mesh_rstr[],
3186cf3b68dSWill Pazner        mesh_basis[],
3196cf3b68dSWill Pazner        C.CEED_VECTOR_ACTIVE[],
3206cf3b68dSWill Pazner    )
3216cf3b68dSWill Pazner    C.CeedOperatorSetField(
3226cf3b68dSWill Pazner        build_oper[],
3236cf3b68dSWill Pazner        "weights",
3246cf3b68dSWill Pazner        C.CEED_ELEMRESTRICTION_NONE[],
3256cf3b68dSWill Pazner        mesh_basis[],
3266cf3b68dSWill Pazner        C.CEED_VECTOR_NONE[],
3276cf3b68dSWill Pazner    )
3286cf3b68dSWill Pazner    C.CeedOperatorSetField(
3296cf3b68dSWill Pazner        build_oper[],
3306cf3b68dSWill Pazner        "qdata",
331*edb2538eSJeremy L Thompson        sol_rstr_i[],
332356036faSJeremy L Thompson        C.CEED_BASIS_NONE[],
3336cf3b68dSWill Pazner        C.CEED_VECTOR_ACTIVE[],
3346cf3b68dSWill Pazner    )
3356cf3b68dSWill Pazner
3366cf3b68dSWill Pazner    # Compute the quadrature data for the mass operator.
3376cf3b68dSWill Pazner    qdata = Ref{C.CeedVector}()
3386cf3b68dSWill Pazner    elem_qpts = num_qpts^dim
3396cf3b68dSWill Pazner    num_elem = prod(nxyz)
3406cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], num_elem*elem_qpts, qdata)
3416cf3b68dSWill Pazner
3426cf3b68dSWill Pazner    print("Computing the quadrature data for the mass operator ...")
3436cf3b68dSWill Pazner    flush(stdout)
3446cf3b68dSWill Pazner    GC.@preserve build_ctx C.CeedOperatorApply(
3456cf3b68dSWill Pazner        build_oper[],
3466cf3b68dSWill Pazner        mesh_coords[],
3476cf3b68dSWill Pazner        qdata[],
3486cf3b68dSWill Pazner        C.CEED_REQUEST_IMMEDIATE[],
3496cf3b68dSWill Pazner    )
3506cf3b68dSWill Pazner    println(" done.")
3516cf3b68dSWill Pazner
3526cf3b68dSWill Pazner    # Create the Q-function that defines the action of the mass operator.
3536cf3b68dSWill Pazner    apply_qfunc = Ref{C.CeedQFunction}()
3546cf3b68dSWill Pazner    if !gallery
3556cf3b68dSWill Pazner        qf_apply_mass = @cfunction(
3566cf3b68dSWill Pazner            f_apply_mass_c,
3576cf3b68dSWill Pazner            C.CeedInt,
3586cf3b68dSWill Pazner            (Ptr{Cvoid}, C.CeedInt, Ptr{Ptr{C.CeedScalar}}, Ptr{Ptr{C.CeedScalar}})
3596cf3b68dSWill Pazner        )
3606cf3b68dSWill Pazner        # This creates the QFunction directly.
3616cf3b68dSWill Pazner        C.CeedQFunctionCreateInterior(ceed[], 1, qf_apply_mass, "julia", apply_qfunc)
3626cf3b68dSWill Pazner        C.CeedQFunctionAddInput(apply_qfunc[], "u", 1, C.CEED_EVAL_INTERP)
3636cf3b68dSWill Pazner        C.CeedQFunctionAddInput(apply_qfunc[], "qdata", 1, C.CEED_EVAL_NONE)
3646cf3b68dSWill Pazner        C.CeedQFunctionAddOutput(apply_qfunc[], "v", 1, C.CEED_EVAL_INTERP)
3656cf3b68dSWill Pazner    else
3666cf3b68dSWill Pazner        # This creates the QFunction via the gallery.
3676cf3b68dSWill Pazner        C.CeedQFunctionCreateInteriorByName(ceed[], "MassApply", apply_qfunc)
3686cf3b68dSWill Pazner    end
3696cf3b68dSWill Pazner
3706cf3b68dSWill Pazner    # Create the mass operator.
3716cf3b68dSWill Pazner    oper = Ref{C.CeedOperator}()
3726cf3b68dSWill Pazner    C.CeedOperatorCreate(
3736cf3b68dSWill Pazner        ceed[],
3746cf3b68dSWill Pazner        apply_qfunc[],
3756cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
3766cf3b68dSWill Pazner        C.CEED_QFUNCTION_NONE[],
3776cf3b68dSWill Pazner        oper,
3786cf3b68dSWill Pazner    )
379*edb2538eSJeremy L Thompson    C.CeedOperatorSetField(oper[], "u", sol_rstr[], sol_basis[], C.CEED_VECTOR_ACTIVE[])
380*edb2538eSJeremy L Thompson    C.CeedOperatorSetField(oper[], "qdata", sol_rstr_i[], C.CEED_BASIS_NONE[], qdata[])
381*edb2538eSJeremy L Thompson    C.CeedOperatorSetField(oper[], "v", sol_rstr[], sol_basis[], C.CEED_VECTOR_ACTIVE[])
3826cf3b68dSWill Pazner
3836cf3b68dSWill Pazner    # Compute the mesh volume using the mass operator: vol = 1^T \cdot M \cdot 1
3846cf3b68dSWill Pazner    print("Computing the mesh volume using the formula: vol = 1^T.M.1 ...")
3856cf3b68dSWill Pazner    flush(stdout)
3866cf3b68dSWill Pazner    # Create auxiliary solution-size vectors.
3876cf3b68dSWill Pazner    u = Ref{C.CeedVector}()
3886cf3b68dSWill Pazner    v = Ref{C.CeedVector}()
3896cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], sol_size, u)
3906cf3b68dSWill Pazner    C.CeedVectorCreate(ceed[], sol_size, v)
3916cf3b68dSWill Pazner
3926cf3b68dSWill Pazner    # Initialize 'u' with ones.
3936cf3b68dSWill Pazner    C.CeedVectorSetValue(u[], 1.0)
3946cf3b68dSWill Pazner
3956cf3b68dSWill Pazner    # Apply the mass operator: 'u' -> 'v'.
3966cf3b68dSWill Pazner    C.CeedOperatorApply(oper[], u[], v[], C.CEED_REQUEST_IMMEDIATE[])
3976cf3b68dSWill Pazner
3986cf3b68dSWill Pazner    # Compute and print the sum of the entries of 'v' giving the mesh volume.
3996cf3b68dSWill Pazner    v_host_ref = Ref{Ptr{C.CeedScalar}}()
4006cf3b68dSWill Pazner    C.CeedVectorGetArrayRead(v[], C.CEED_MEM_HOST, v_host_ref)
4016cf3b68dSWill Pazner    v_host = unsafe_wrap(Array, v_host_ref[], sol_size)
4026cf3b68dSWill Pazner    vol = sum(v_host)
4036cf3b68dSWill Pazner    C.CeedVectorRestoreArrayRead(v[], v_host_ref)
4046cf3b68dSWill Pazner
4056cf3b68dSWill Pazner    println(" done.")
4066cf3b68dSWill Pazner    @printf("Exact mesh volume    : % .14g\n", exact_vol)
4076cf3b68dSWill Pazner    @printf("Computed mesh volume : % .14g\n", vol)
4086cf3b68dSWill Pazner    @printf("Volume error         : % .14g\n", vol - exact_vol)
4096cf3b68dSWill Pazner
4106cf3b68dSWill Pazner    # Free dynamically allocated memory.
4116cf3b68dSWill Pazner    C.CeedVectorDestroy(u)
4126cf3b68dSWill Pazner    C.CeedVectorDestroy(v)
4136cf3b68dSWill Pazner    C.CeedVectorDestroy(qdata)
4146cf3b68dSWill Pazner    C.CeedVectorDestroy(mesh_coords)
4156cf3b68dSWill Pazner    C.CeedOperatorDestroy(oper)
4166cf3b68dSWill Pazner    C.CeedQFunctionDestroy(apply_qfunc)
4176cf3b68dSWill Pazner    C.CeedOperatorDestroy(build_oper)
4186cf3b68dSWill Pazner    C.CeedQFunctionDestroy(build_qfunc)
419*edb2538eSJeremy L Thompson    C.CeedElemRestrictionDestroy(sol_rstr)
420*edb2538eSJeremy L Thompson    C.CeedElemRestrictionDestroy(mesh_rstr)
421*edb2538eSJeremy L Thompson    C.CeedElemRestrictionDestroy(sol_rstr_i)
4226cf3b68dSWill Pazner    C.CeedBasisDestroy(sol_basis)
4236cf3b68dSWill Pazner    C.CeedBasisDestroy(mesh_basis)
4246cf3b68dSWill Pazner    C.CeedDestroy(ceed)
4256cf3b68dSWill Paznerend
4266cf3b68dSWill Pazner
4276cf3b68dSWill Paznerrun_ex1_c(
4286cf3b68dSWill Pazner    ceed_spec="/cpu/self",
4296cf3b68dSWill Pazner    dim=3,
4306cf3b68dSWill Pazner    mesh_order=4,
4316cf3b68dSWill Pazner    sol_order=4,
4326cf3b68dSWill Pazner    num_qpts=4 + 2,
4336cf3b68dSWill Pazner    prob_size=-1,
4346cf3b68dSWill Pazner)
435