xref: /libCEED/julia/LibCEED.jl/test/runtests.jl (revision edb2538e3dd6743c029967fc4e89c6fcafedb8c2)
1using Test, LibCEED, LinearAlgebra, StaticArrays
2
3showstr(x) = sprint(show, MIME("text/plain"), x)
4summarystr(x) = sprint(summary, x)
5getoutput(fname) =
6    chomp(read(joinpath(@__DIR__, "output", string(CeedScalar), fname), String))
7
8function checkoutput(str, fname)
9    if str != getoutput(fname)
10        write(fname, str)
11        return false
12    end
13    return true
14end
15
16mutable struct CtxData
17    io::IOBuffer
18    x::Vector{Float64}
19end
20
21const run_dev_tests = !isrelease() || ("--run-dev-tests" in ARGS)
22
23if run_dev_tests
24    include("rundevtests.jl")
25end
26
27if !LibCEED.ceedversion_ge(LibCEED.minimum_libceed_version) && !run_dev_tests
28    @warn "Skipping tests because of incompatible libCEED versions."
29else
30    @testset "LibCEED Release Tests" begin
31        @testset "LibCEED" begin
32            @test ceedversion() isa VersionNumber
33            @test isrelease() isa Bool
34            @test isfile(get_libceed_path())
35        end
36
37        @testset "Ceed" begin
38            res = "/cpu/self/ref/serial"
39            c = Ceed(res)
40            @test isdeterministic(c)
41            @test getresource(c) == res
42            @test !iscuda(c)
43            @test get_preferred_memtype(c) == MEM_HOST
44            @test_throws LibCEED.CeedError create_interior_qfunction(c, "")
45            @test showstr(c) == """
46                Ceed
47                  Ceed Resource: $res
48                  Preferred MemType: host"""
49        end
50
51        @testset "Context" begin
52            c = Ceed()
53            data = zeros(CeedScalar, 3)
54            ctx = Context(c, data)
55            @test showstr(ctx) == """
56                CeedQFunctionContext
57                  Context Data Size: $(sizeof(data))"""
58            @test_throws Exception set_data!(ctx, MEM_HOST, OWN_POINTER, data)
59        end
60
61        @testset "CeedVector" begin
62            n = 10
63            c = Ceed()
64            v = CeedVector(c, n)
65            @test size(v) == (n,)
66            @test length(v) == n
67            @test axes(v) == (1:n,)
68            @test ndims(v) == 1
69            @test ndims(CeedVector) == 1
70
71            v[] = 0.0
72            @test @witharray(a = v, all(a .== 0.0))
73
74            v1 = rand(CeedScalar, n)
75            v2 = CeedVector(c, v1)
76            @test @witharray_read(a = v2, mtype = MEM_HOST, a == v1)
77            @test Vector(v2) == v1
78            v[] = v1
79            for p ∈ [1, 2, Inf]
80                @test norm(v, p) ≈ norm(v1, p)
81            end
82            @test_throws Exception norm(v, 3)
83            @test witharray_read(sum, v) == sum(v1)
84            reciprocal!(v)
85            @test @witharray(a = v, mtype = MEM_HOST, all(a .== CeedScalar(1.0)./v1))
86
87            witharray(x -> x .= 1.0, v)
88            @test @witharray(a = v, all(a .== 1.0))
89
90            @test summarystr(v) == "$n-element CeedVector"
91            @test sprint(show, v) == @witharray_read(a = v, sprint(show, a))
92            io = IOBuffer()
93            summary(io, v)
94            println(io, ":")
95            @witharray_read(a = v, Base.print_array(io, a))
96            s1 = String(take!(io))
97            @test showstr(v) == s1
98
99            setarray!(v, MEM_HOST, USE_POINTER, v1)
100            syncarray!(v, MEM_HOST)
101            @test @witharray_read(a = v, a == v1)
102            p = takearray!(v, MEM_HOST)
103            @test p == pointer(v1)
104
105            m = rand(CeedScalar, 10, 10)
106            vm = CeedVector(c, vec(m))
107            @test @witharray_read(a = vm, size = size(m), a == m)
108
109            @test CeedVectorActive()[] == LibCEED.C.CEED_VECTOR_ACTIVE[]
110            @test CeedVectorNone()[] == LibCEED.C.CEED_VECTOR_NONE[]
111
112            w1 = rand(CeedScalar, n)
113            w2 = rand(CeedScalar, n)
114            w3 = rand(CeedScalar, n)
115
116            cv1 = CeedVector(c, w1)
117            cv2 = CeedVector(c, w2)
118            cv3 = CeedVector(c, w3)
119
120            alpha = rand(CeedScalar)
121
122            scale!(cv1, alpha)
123            w1 .*= alpha
124            @test @witharray_read(a = cv1, a == w1)
125
126            pointwisemult!(cv1, cv2, cv3)
127            w1 .= w2.*w3
128            @test @witharray_read(a = cv1, a == w1)
129
130            axpy!(alpha, cv2, cv1)
131            axpy!(alpha, w2, w1)
132            @test @witharray_read(a = cv1, a ≈ w1)
133        end
134
135        @testset "Basis" begin
136            c = Ceed()
137            dim = 3
138            ncomp = 1
139            p = 4
140            q = 6
141            b1 = create_tensor_h1_lagrange_basis(c, dim, ncomp, p, q, GAUSS_LOBATTO)
142
143            @test getdimension(b1) == 3
144            @test gettopology(b1) == HEX
145            @test getnumcomponents(b1) == ncomp
146            @test getnumnodes(b1) == p^dim
147            @test getnumnodes1d(b1) == p
148            @test getnumqpts(b1) == q^dim
149            @test getnumqpts1d(b1) == q
150
151            q1d, w1d = lobatto_quadrature(3, AbscissaAndWeights)
152            @test q1d ≈ CeedScalar[-1.0, 0.0, 1.0]
153            @test w1d ≈ CeedScalar[1/3, 4/3, 1/3]
154
155            q1d, w1d = gauss_quadrature(3)
156            @test q1d ≈ CeedScalar[-sqrt(3/5), 0.0, sqrt(3/5)]
157            @test w1d ≈ CeedScalar[5/9, 8/9, 5/9]
158
159            b1d = CeedScalar[1.0 0.0; 0.5 0.5; 0.0 1.0]
160            d1d = CeedScalar[-0.5 0.5; -0.5 0.5; -0.5 0.5]
161            q1d = CeedScalar[-1.0, 0.0, 1.0]
162            w1d = CeedScalar[1/3, 4/3, 1/3]
163            q, p = size(b1d)
164            d2d = zeros(CeedScalar, 2, q*q, p*p)
165            d2d[1, :, :] = kron(b1d, d1d)
166            d2d[2, :, :] = kron(d1d, b1d)
167
168            dim2 = 2
169            b2 = create_tensor_h1_basis(c, dim2, 1, p, q, b1d, d1d, q1d, w1d)
170            @test getinterp(b2) == kron(b1d, b1d)
171            @test getinterp1d(b2) == b1d
172            @test getgrad(b2) == d2d
173            @test getgrad1d(b2) == d1d
174
175            b3 = create_h1_basis(
176                c,
177                LINE,
178                1,
179                p,
180                q,
181                b1d,
182                reshape(d1d, 1, q, p),
183                reshape(q1d, 1, q),
184                w1d,
185            )
186            @test getqref(b3) == reshape(q1d, 1, q)
187            @test getqweights(b3) == w1d
188
189            v = rand(CeedScalar, 2)
190            vq = apply(b3, v)
191            vd = apply(b3, v; emode=EVAL_GRAD)
192            @test vq ≈ b1d*v
193            @test vd ≈ d1d*v
194        end
195
196        @testset "Request" begin
197            @test RequestImmediate()[] == LibCEED.C.CEED_REQUEST_IMMEDIATE[]
198            @test RequestOrdered()[] == LibCEED.C.CEED_REQUEST_ORDERED[]
199        end
200
201        @testset "Misc" begin
202            for dim = 1:3
203                D = CeedDim(dim)
204                J = rand(CeedScalar, dim, dim)
205                @test det(J, D) ≈ det(J)
206                J = J + J' # make symmetric
207                @test setvoigt(SMatrix{dim,dim}(J)) == setvoigt(J, D)
208                @test getvoigt(setvoigt(J, D)) == J
209                V = zeros(CeedScalar, dim*(dim + 1)÷2)
210                setvoigt!(V, J, D)
211                @test V == setvoigt(J, D)
212                J2 = zeros(CeedScalar, dim, dim)
213                getvoigt!(J2, V, D)
214                @test J2 == J
215            end
216        end
217
218        @testset "Operator" begin
219            c = Ceed()
220            @interior_qf id = (
221                c,
222                (input, :in, EVAL_INTERP),
223                (output, :out, EVAL_INTERP),
224                begin
225                    output[] = input
226                end,
227            )
228            b = create_tensor_h1_lagrange_basis(c, 3, 1, 3, 3, GAUSS_LOBATTO)
229            n = getnumnodes(b)
230            offsets = Vector{CeedInt}(0:n-1)
231            r = create_elem_restriction(c, 1, n, 1, 1, n, offsets)
232            op = Operator(
233                c;
234                qf=id,
235                fields=[
236                    (:input, r, b, CeedVectorActive()),
237                    (:output, r, b, CeedVectorActive()),
238                ],
239            )
240
241            v = rand(CeedScalar, n)
242            v1 = CeedVector(c, v)
243            v2 = CeedVector(c, n)
244            apply!(op, v1, v2)
245            @test @witharray_read(a1 = v1, @witharray_read(a2 = v2, a1 == a2))
246            apply_add!(op, v1, v2)
247            @test @witharray_read(a1 = v1, @witharray_read(a2 = v2, a1 + a1 == a2))
248
249            diag_vector = create_lvector(r)
250            LibCEED.assemble_diagonal!(op, diag_vector)
251            @test @witharray_read(a = diag_vector, a == ones(n))
252            # TODO: change this test after bug-fix in libCEED
253            diag_vector[] = 0.0
254            LibCEED.assemble_add_diagonal!(op, diag_vector)
255            @test @witharray(a = diag_vector, a == fill(1.0, n))
256
257            comp_op = create_composite_operator(c, [op])
258            apply!(comp_op, v1, v2)
259            @test @witharray_read(a1 = v1, @witharray_read(a2 = v2, a1 == a2))
260
261            @test showstr(op) == """
262                CeedOperator
263                  1 elements with 27 quadrature points each
264                  2 fields
265                  1 input field:
266                    Input field 0:
267                      Name: "input"
268                      Size: 1
269                      EvalMode: interpolation
270                      Active vector
271                  1 output field:
272                    Output field 0:
273                      Name: "output"
274                      Size: 1
275                      EvalMode: interpolation
276                      Active vector"""
277        end
278
279        @testset "ElemRestriction" begin
280            c = Ceed()
281            n = 10
282            offsets = Vector{CeedInt}([0:n-1; n-1:2*n-2])
283            lsize = 2*n - 1
284            r = create_elem_restriction(c, 2, n, 1, lsize, lsize, offsets)
285            @test getcompstride(r) == lsize
286            @test getnumelements(r) == 2
287            @test getelementsize(r) == n
288            @test getlvectorsize(r) == lsize
289            @test getnumcomponents(r) == 1
290            @test length(create_lvector(r)) == lsize
291            @test length(create_evector(r)) == 2*n
292            lv, ev = create_vectors(r)
293            @test length(lv) == lsize
294            @test length(ev) == 2*n
295            mult = getmultiplicity(r)
296            mult2 = ones(lsize)
297            mult2[n] = 2
298            @test mult == mult2
299            rand_lv = rand(CeedScalar, lsize)
300            rand_ev = [rand_lv[1:n]; rand_lv[n:end]]
301            @test apply(r, rand_lv) == rand_ev
302            @test apply(r, rand_ev; tmode=TRANSPOSE) == rand_lv.*mult
303            @test showstr(r) == string(
304                "CeedElemRestriction from (19, 1) to 2 elements ",
305                "with 10 nodes each and component stride 19",
306            )
307
308            strides = CeedInt[1, n, n]
309            rs = create_elem_restriction_strided(c, 1, n, 1, n, strides)
310            @test showstr(rs) == string(
311                "CeedElemRestriction from (10, 1) to 1 elements ",
312                "with 10 nodes each and strides [1, $n, $n]",
313            )
314
315            @test ElemRestrictionNone()[] == LibCEED.C.CEED_ELEMRESTRICTION_NONE[]
316        end
317
318        @testset "QFunction" begin
319            c = Ceed()
320            @test showstr(create_interior_qfunction(c, "Poisson3DApply")) == """
321                 Gallery CeedQFunction - Poisson3DApply
322                   2 input fields:
323                     Input field 0:
324                       Name: "du"
325                       Size: 3
326                       EvalMode: "gradient"
327                     Input field 1:
328                       Name: "qdata"
329                       Size: 6
330                       EvalMode: "none"
331                   1 output field:
332                     Output field 0:
333                       Name: "dv"
334                       Size: 3
335                       EvalMode: "gradient\""""
336
337            id = create_identity_qfunction(c, 1, EVAL_INTERP, EVAL_INTERP)
338            Q = 10
339            v = rand(CeedScalar, Q)
340            v1 = CeedVector(c, v)
341            v2 = CeedVector(c, Q)
342            apply!(id, Q, [v1], [v2])
343            @test @witharray(a = v2, a == v)
344
345            @interior_qf id2 = (c, (a, :in, EVAL_INTERP), (b, :out, EVAL_INTERP), b .= a)
346            v2[] = 0.0
347            apply!(id2, Q, [v1], [v2])
348            @test @witharray(a = v2, a == v)
349
350            ctxdata = CtxData(IOBuffer(), rand(CeedScalar, 3))
351            ctx = Context(c, ctxdata)
352            dim = 3
353            @interior_qf qf = (
354                c,
355                dim=dim,
356                ctxdata::CtxData,
357                (a, :in, EVAL_GRAD, dim),
358                (b, :in, EVAL_NONE),
359                (c, :out, EVAL_INTERP),
360                begin
361                    c[] = b*sum(a)
362                    show(ctxdata.io, MIME("text/plain"), ctxdata.x)
363                end,
364            )
365            set_context!(qf, ctx)
366            in_sz, out_sz = LibCEED.get_field_sizes(qf)
367            @test in_sz == [dim, 1]
368            @test out_sz == [1]
369            v1 = rand(CeedScalar, dim)
370            v2 = rand(CeedScalar, 1)
371            cv1 = CeedVector(c, v1)
372            cv2 = CeedVector(c, v2)
373            cv3 = CeedVector(c, 1)
374            apply!(qf, 1, [cv1, cv2], [cv3])
375            @test String(take!(ctxdata.io)) == showstr(ctxdata.x)
376            @test @witharray_read(v3 = cv3, v3[1] == v2[1]*sum(v1))
377
378            @test QFunctionNone()[] == LibCEED.C.CEED_QFUNCTION_NONE[]
379        end
380    end
381end
382