xref: /libCEED/julia/LibCEED.jl/examples/ex1-volume.jl (revision edb2538e3dd6743c029967fc4e89c6fcafedb8c2)
1using LibCEED, Printf
2
3include("common.jl")
4
5function transform_mesh_coords!(dim, mesh_size, mesh_coords)
6    @witharray coords = mesh_coords begin
7        if dim == 1
8            for i = 1:mesh_size
9                # map [0,1] to [0,1] varying the mesh density
10                coords[i] = 0.5 + 1.0/sqrt(3.0)*sin((2.0/3.0)*pi*(coords[i] - 0.5))
11            end
12            exact_volume = 1.0
13        else
14            num_nodes = mesh_size÷dim
15            @inbounds @simd for i = 1:num_nodes
16                # map (x,y) from [0,1]x[0,1] to the quarter annulus with polar
17                # coordinates, (r,phi) in [1,2]x[0,pi/2] with area = 3/4*pi
18                u = coords[i]
19                v = coords[i+num_nodes]
20                u = 1.0 + u
21                v = pi/2*v
22                coords[i] = u*cos(v)
23                coords[i+num_nodes] = u*sin(v)
24            end
25            exact_volume = 3.0/4.0*pi
26        end
27        return exact_volume
28    end
29end
30
31function run_ex1(; ceed_spec, dim, mesh_order, sol_order, num_qpts, prob_size, gallery)
32    ncompx = dim
33    prob_size < 0 && (prob_size = 256*1024)
34
35    ceed = Ceed(ceed_spec)
36    mesh_basis =
37        create_tensor_h1_lagrange_basis(ceed, dim, ncompx, mesh_order + 1, num_qpts, GAUSS)
38    sol_basis =
39        create_tensor_h1_lagrange_basis(ceed, dim, 1, sol_order + 1, num_qpts, GAUSS)
40
41    # Determine the mesh size based on the given approximate problem size.
42    nxyz = get_cartesian_mesh_size(dim, sol_order, prob_size)
43    println("Mesh size: ", nxyz)
44
45    # Build CeedElemRestriction objects describing the mesh and solution discrete
46    # representations.
47    mesh_size, mesh_rstr, _ =
48        build_cartesian_restriction(ceed, dim, nxyz, mesh_order, ncompx, num_qpts)
49    sol_size, sol_rstr, sol_rstr_i = build_cartesian_restriction(
50        ceed,
51        dim,
52        nxyz,
53        sol_order,
54        1,
55        num_qpts,
56        mode=RestrictionAndStrided,
57    )
58    println("Number of mesh nodes     : ", div(mesh_size, dim))
59    println("Number of solution nodes : ", sol_size)
60
61    # Create a CeedVector with the mesh coordinates.
62    mesh_coords = CeedVector(ceed, mesh_size)
63    set_cartesian_mesh_coords!(dim, nxyz, mesh_order, mesh_coords)
64    # Apply a transformation to the mesh.
65    exact_vol = transform_mesh_coords!(dim, mesh_size, mesh_coords)
66
67    # Create the Q-function that builds the mass operator (i.e. computes its
68    # quadrature data) and set its context data.
69    if !gallery
70        @interior_qf build_qfunc = (
71            ceed,
72            dim=dim,
73            (J, :in, EVAL_GRAD, dim, dim),
74            (w, :in, EVAL_WEIGHT),
75            (qdata, :out, EVAL_NONE),
76            begin
77                qdata .= w*det(J)
78            end,
79        )
80    else
81        build_qfunc = create_interior_qfunction(ceed, "Mass$(dim)DBuild")
82    end
83
84    # Create the operator that builds the quadrature data for the mass operator.
85    build_oper = Operator(
86        ceed,
87        qf=build_qfunc,
88        fields=[
89            (gallery ? :dx : :J, mesh_rstr, mesh_basis, CeedVectorActive()),
90            (gallery ? :weights : :w, ElemRestrictionNone(), mesh_basis, CeedVectorNone()),
91            (:qdata, sol_rstr_i, BasisNone(), CeedVectorActive()),
92        ],
93    )
94
95    # Compute the quadrature data for the mass operator.
96    elem_qpts = num_qpts^dim
97    num_elem = prod(nxyz)
98    qdata = CeedVector(ceed, num_elem*elem_qpts)
99
100    print("Computing the quadrature data for the mass operator ...")
101    flush(stdout)
102    apply!(build_oper, mesh_coords, qdata)
103    println(" done.")
104
105    # Create the Q-function that defines the action of the mass operator.
106    if !gallery
107        @interior_qf apply_qfunc = (
108            ceed,
109            (u, :in, EVAL_INTERP),
110            (qdata, :in, EVAL_NONE),
111            (v, :out, EVAL_INTERP),
112            begin
113                v .= qdata*u
114            end,
115        )
116    else
117        apply_qfunc = create_interior_qfunction(ceed, "MassApply")
118    end
119
120    # Create the mass operator.
121    oper = Operator(
122        ceed,
123        qf=apply_qfunc,
124        fields=[
125            (:u, sol_rstr, sol_basis, CeedVectorActive()),
126            (:qdata, sol_rstr_i, BasisNone(), qdata),
127            (:v, sol_rstr, sol_basis, CeedVectorActive()),
128        ],
129    )
130
131    # Compute the mesh volume using the mass operator: vol = 1^T \cdot M \cdot 1
132    print("Computing the mesh volume using the formula: vol = 1^T.M.1 ...")
133    flush(stdout)
134    # Create auxiliary solution-size vectors.
135    u = CeedVector(ceed, sol_size)
136    v = CeedVector(ceed, sol_size)
137    # Initialize 'u' with ones.
138    u[] = 1.0
139    # Apply the mass operator: 'u' -> 'v'.
140    apply!(oper, u, v)
141    # Compute and print the sum of the entries of 'v' giving the mesh volume.
142    vol = witharray_read(sum, v, MEM_HOST)
143
144    println(" done.")
145    @printf("Exact mesh volume    : % .14g\n", exact_vol)
146    @printf("Computed mesh volume : % .14g\n", vol)
147    @printf("Volume error         : % .14g\n", vol - exact_vol)
148end
149
150run_ex1(
151    ceed_spec="/cpu/self",
152    dim=3,
153    mesh_order=4,
154    sol_order=4,
155    num_qpts=4 + 2,
156    prob_size=-1,
157    gallery=false,
158)
159