xref: /libCEED/julia/LibCEED.jl/src/CeedVector.jl (revision 44554ea01e90fce366fc2a203c44be15754a38d6)
1*44554ea0SWill Paznerimport LinearAlgebra: norm
2*44554ea0SWill Pazner
3*44554ea0SWill Paznerabstract type AbstractCeedVector end
4*44554ea0SWill Pazner
5*44554ea0SWill Paznerstruct CeedVectorActive <: AbstractCeedVector end
6*44554ea0SWill PaznerBase.getindex(::CeedVectorActive) = C.CEED_VECTOR_ACTIVE[]
7*44554ea0SWill Pazner
8*44554ea0SWill Paznerstruct CeedVectorNone <: AbstractCeedVector end
9*44554ea0SWill PaznerBase.getindex(::CeedVectorNone) = C.CEED_VECTOR_NONE[]
10*44554ea0SWill Pazner
11*44554ea0SWill Paznermutable struct CeedVector <: AbstractCeedVector
12*44554ea0SWill Pazner    ref::RefValue{C.CeedVector}
13*44554ea0SWill Pazner    arr::Union{Nothing,AbstractArray}
14*44554ea0SWill Pazner    CeedVector(ref::Ref{C.CeedVector}) = new(ref, nothing)
15*44554ea0SWill Paznerend
16*44554ea0SWill Pazner
17*44554ea0SWill Pazner"""
18*44554ea0SWill Pazner    CeedVector(c::Ceed, len::Integer)
19*44554ea0SWill Pazner
20*44554ea0SWill PaznerCreates a `CeedVector` of given length.
21*44554ea0SWill Pazner"""
22*44554ea0SWill Paznerfunction CeedVector(c::Ceed, len::Integer)
23*44554ea0SWill Pazner    ref = Ref{C.CeedVector}()
24*44554ea0SWill Pazner    C.CeedVectorCreate(c[], len, ref)
25*44554ea0SWill Pazner    obj = CeedVector(ref)
26*44554ea0SWill Pazner    finalizer(obj) do x
27*44554ea0SWill Pazner        # ccall(:jl_safe_printf, Cvoid, (Cstring, Cstring), "Finalizing %s.\n", repr(x))
28*44554ea0SWill Pazner        destroy(x)
29*44554ea0SWill Pazner    end
30*44554ea0SWill Pazner    return obj
31*44554ea0SWill Paznerend
32*44554ea0SWill Paznerdestroy(v::CeedVector) = C.CeedVectorDestroy(v.ref) # COV_EXCL_LINE
33*44554ea0SWill PaznerBase.getindex(v::CeedVector) = v.ref[]
34*44554ea0SWill Pazner
35*44554ea0SWill PaznerBase.summary(io::IO, v::CeedVector) = print(io, length(v), "-element CeedVector")
36*44554ea0SWill Paznerfunction Base.show(io::IO, ::MIME"text/plain", v::CeedVector)
37*44554ea0SWill Pazner    summary(io, v)
38*44554ea0SWill Pazner    println(io, ":")
39*44554ea0SWill Pazner    witharray_read(v, MEM_HOST) do arr
40*44554ea0SWill Pazner        Base.print_array(io, arr)
41*44554ea0SWill Pazner    end
42*44554ea0SWill Paznerend
43*44554ea0SWill PaznerBase.show(io::IO, v::CeedVector) = witharray_read(a -> show(io, a), v, MEM_HOST)
44*44554ea0SWill Pazner
45*44554ea0SWill Paznerfunction Base.length(::Type{T}, v::CeedVector) where {T}
46*44554ea0SWill Pazner    len = Ref{C.CeedInt}()
47*44554ea0SWill Pazner    C.CeedVectorGetLength(v[], len)
48*44554ea0SWill Pazner    return T(len[])
49*44554ea0SWill Paznerend
50*44554ea0SWill Pazner
51*44554ea0SWill PaznerBase.ndims(::CeedVector) = 1
52*44554ea0SWill PaznerBase.ndims(::Type{CeedVector}) = 1
53*44554ea0SWill PaznerBase.axes(v::CeedVector) = (Base.OneTo(length(v)),)
54*44554ea0SWill PaznerBase.size(v::CeedVector) = (length(Int, v),)
55*44554ea0SWill PaznerBase.length(v::CeedVector) = length(Int, v)
56*44554ea0SWill Pazner
57*44554ea0SWill Pazner"""
58*44554ea0SWill Pazner    setvalue!(v::CeedVector, val::CeedScalar)
59*44554ea0SWill Pazner
60*44554ea0SWill PaznerSet the [`CeedVector`](@ref) to a constant value.
61*44554ea0SWill Pazner"""
62*44554ea0SWill Paznersetvalue!(v::CeedVector, val::CeedScalar) = C.CeedVectorSetValue(v[], val)
63*44554ea0SWill Pazner"""
64*44554ea0SWill Pazner    setindex!(v::CeedVector, val::CeedScalar)
65*44554ea0SWill Pazner    v[] = val
66*44554ea0SWill Pazner
67*44554ea0SWill PaznerSet the [`CeedVector`](@ref) to a constant value, synonymous to [`setvalue!`](@ref).
68*44554ea0SWill Pazner"""
69*44554ea0SWill PaznerBase.setindex!(v::CeedVector, val::CeedScalar) = setvalue!(v, val)
70*44554ea0SWill Pazner
71*44554ea0SWill Pazner"""
72*44554ea0SWill Pazner    norm(v::CeedVector, ntype::NormType)
73*44554ea0SWill Pazner
74*44554ea0SWill PaznerReturn the norm of the given [`CeedVector`](@ref).
75*44554ea0SWill Pazner
76*44554ea0SWill PaznerThe norm type can either be specified as one of `NORM_1`, `NORM_2`, `NORM_MAX`.
77*44554ea0SWill Pazner"""
78*44554ea0SWill Paznerfunction norm(v::CeedVector, ntype::NormType)
79*44554ea0SWill Pazner    nrm = Ref{CeedScalar}()
80*44554ea0SWill Pazner    C.CeedVectorNorm(v[], ntype, nrm)
81*44554ea0SWill Pazner    nrm[]
82*44554ea0SWill Paznerend
83*44554ea0SWill Pazner
84*44554ea0SWill Pazner"""
85*44554ea0SWill Pazner    norm(v::CeedVector, p::Real)
86*44554ea0SWill Pazner
87*44554ea0SWill PaznerReturn the norm of the given [`CeedVector`](@ref), see [`norm(::CeedVector,
88*44554ea0SWill Pazner::NormType)`](@ref).
89*44554ea0SWill Pazner
90*44554ea0SWill Pazner`p` can have value 1, 2, or Inf, corresponding to `NORM_1`, `NORM_2`, and `NORM_MAX`,
91*44554ea0SWill Paznerrespectively.
92*44554ea0SWill Pazner"""
93*44554ea0SWill Paznerfunction norm(v::CeedVector, p::Real)
94*44554ea0SWill Pazner    if p == 1
95*44554ea0SWill Pazner        ntype = NORM_1
96*44554ea0SWill Pazner    elseif p == 2
97*44554ea0SWill Pazner        ntype = NORM_2
98*44554ea0SWill Pazner    elseif isinf(p)
99*44554ea0SWill Pazner        ntype = NORM_MAX
100*44554ea0SWill Pazner    else
101*44554ea0SWill Pazner        error("norm(v::CeedVector, p): p must be 1, 2, or Inf")
102*44554ea0SWill Pazner    end
103*44554ea0SWill Pazner    norm(v, ntype)
104*44554ea0SWill Paznerend
105*44554ea0SWill Pazner
106*44554ea0SWill Pazner"""
107*44554ea0SWill Pazner    reciprocal!(v::CeedVector)
108*44554ea0SWill Pazner
109*44554ea0SWill PaznerSet `v` to be equal to its elementwise reciprocal.
110*44554ea0SWill Pazner"""
111*44554ea0SWill Paznerreciprocal!(v::CeedVector) = C.CeedVectorReciprocal(v[])
112*44554ea0SWill Pazner
113*44554ea0SWill Pazner"""
114*44554ea0SWill Pazner    setarray!(v::CeedVector, mtype::MemType, cmode::CopyMode, arr)
115*44554ea0SWill Pazner
116*44554ea0SWill PaznerSet the array used by a [`CeedVector`](@ref), freeing any previously allocated array if
117*44554ea0SWill Paznerapplicable. The backend may copy values to a different [`MemType`](@ref). See also
118*44554ea0SWill Pazner[`syncarray!`](@ref) and [`takearray!`](@ref).
119*44554ea0SWill Pazner
120*44554ea0SWill Pazner!!! warning "Avoid OWN_POINTER CopyMode"
121*44554ea0SWill Pazner    The [`CopyMode`](@ref) `OWN_POINTER` is not suitable for use with arrays that are
122*44554ea0SWill Pazner    allocated by Julia, since those cannot be properly freed from libCEED.
123*44554ea0SWill Pazner"""
124*44554ea0SWill Paznerfunction setarray!(v::CeedVector, mtype::MemType, cmode::CopyMode, arr)
125*44554ea0SWill Pazner    C.CeedVectorSetArray(v[], mtype, cmode, arr)
126*44554ea0SWill Pazner    if cmode == USE_POINTER
127*44554ea0SWill Pazner        v.arr = arr
128*44554ea0SWill Pazner    end
129*44554ea0SWill Paznerend
130*44554ea0SWill Pazner
131*44554ea0SWill Pazner"""
132*44554ea0SWill Pazner    syncarray!(v::CeedVector, mtype::MemType)
133*44554ea0SWill Pazner
134*44554ea0SWill PaznerSync the [`CeedVector`](@ref) to a specified [`MemType`](@ref). This function is used to
135*44554ea0SWill Paznerforce synchronization of arrays set with [`setarray!`](@ref). If the requested memtype is
136*44554ea0SWill Pazneralready synchronized, this function results in a no-op.
137*44554ea0SWill Pazner"""
138*44554ea0SWill Paznersyncarray!(v::CeedVector, mtype::MemType) = C.CeedVectorSyncArray(v[], mtype)
139*44554ea0SWill Pazner
140*44554ea0SWill Pazner"""
141*44554ea0SWill Pazner    takearray!(v::CeedVector, mtype::MemType)
142*44554ea0SWill Pazner
143*44554ea0SWill PaznerTake ownership of the [`CeedVector`](@ref) array and remove the array from the
144*44554ea0SWill Pazner[`CeedVector`](@ref). The caller is responsible for managing and freeing the array. The
145*44554ea0SWill Paznerarray is returns as a `Ptr{CeedScalar}`.
146*44554ea0SWill Pazner"""
147*44554ea0SWill Paznerfunction takearray!(v::CeedVector, mtype::MemType)
148*44554ea0SWill Pazner    ptr = Ref{Ptr{CeedScalar}}()
149*44554ea0SWill Pazner    C.CeedVectorTakeArray(v[], mtype, ptr)
150*44554ea0SWill Pazner    v.arr = nothing
151*44554ea0SWill Pazner    ptr[]
152*44554ea0SWill Paznerend
153*44554ea0SWill Pazner
154*44554ea0SWill Pazner# Helper function to parse arguments of @witharray and @witharray_read
155*44554ea0SWill Paznerfunction witharray_parse(assignment, args)
156*44554ea0SWill Pazner    if !Meta.isexpr(assignment, :(=))
157*44554ea0SWill Pazner        error("@witharray must have first argument of the form v_arr=v") # COV_EXCL_LINE
158*44554ea0SWill Pazner    end
159*44554ea0SWill Pazner    arr = assignment.args[1]
160*44554ea0SWill Pazner    v = assignment.args[2]
161*44554ea0SWill Pazner    mtype = MEM_HOST
162*44554ea0SWill Pazner    sz = :((length($(esc(v))),))
163*44554ea0SWill Pazner    body = args[end]
164*44554ea0SWill Pazner    for i = 1:length(args)-1
165*44554ea0SWill Pazner        a = args[i]
166*44554ea0SWill Pazner        if !Meta.isexpr(a, :(=))
167*44554ea0SWill Pazner            error("Incorrect call to @witharray or @witharray_read") # COV_EXCL_LINE
168*44554ea0SWill Pazner        end
169*44554ea0SWill Pazner        if a.args[1] == :mtype
170*44554ea0SWill Pazner            mtype = a.args[2]
171*44554ea0SWill Pazner        elseif a.args[1] == :size
172*44554ea0SWill Pazner            sz = esc(a.args[2])
173*44554ea0SWill Pazner        end
174*44554ea0SWill Pazner    end
175*44554ea0SWill Pazner    arr, v, sz, mtype, body
176*44554ea0SWill Paznerend
177*44554ea0SWill Pazner
178*44554ea0SWill Pazner"""
179*44554ea0SWill Pazner    @witharray(v_arr=v, [size=(dims...)], [mtype=MEM_HOST], body)
180*44554ea0SWill Pazner
181*44554ea0SWill PaznerExecutes `body`, having extracted the contents of the [`CeedVector`](@ref) `v` as an array
182*44554ea0SWill Paznerwith name `v_arr`. If the [`memory type`](@ref MemType) `mtype` is not provided, `MEM_HOST`
183*44554ea0SWill Paznerwill be used. If the size is not specified, a flat vector will be assumed.
184*44554ea0SWill Pazner
185*44554ea0SWill Pazner# Examples
186*44554ea0SWill PaznerNegate the contents of `CeedVector` `v`:
187*44554ea0SWill Pazner```
188*44554ea0SWill Pazner@witharray v_arr=v v_arr *= -1.0
189*44554ea0SWill Pazner```
190*44554ea0SWill Pazner"""
191*44554ea0SWill Paznermacro witharray(assignment, args...)
192*44554ea0SWill Pazner    arr, v, sz, mtype, body = witharray_parse(assignment, args)
193*44554ea0SWill Pazner    quote
194*44554ea0SWill Pazner        arr_ref = Ref{Ptr{C.CeedScalar}}()
195*44554ea0SWill Pazner        C.CeedVectorGetArray($(esc(v))[], $(esc(mtype)), arr_ref)
196*44554ea0SWill Pazner        try
197*44554ea0SWill Pazner            $(esc(arr)) = UnsafeArray(arr_ref[], Int.($sz))
198*44554ea0SWill Pazner            $(esc(body))
199*44554ea0SWill Pazner        finally
200*44554ea0SWill Pazner            C.CeedVectorRestoreArray($(esc(v))[], arr_ref)
201*44554ea0SWill Pazner        end
202*44554ea0SWill Pazner    end
203*44554ea0SWill Paznerend
204*44554ea0SWill Pazner
205*44554ea0SWill Pazner"""
206*44554ea0SWill Pazner    @witharray_read(v_arr=v, [size=(dims...)], [mtype=MEM_HOST], body)
207*44554ea0SWill Pazner
208*44554ea0SWill PaznerSame as [`@witharray`](@ref), but provides read-only access to the data.
209*44554ea0SWill Pazner"""
210*44554ea0SWill Paznermacro witharray_read(assignment, args...)
211*44554ea0SWill Pazner    arr, v, sz, mtype, body = witharray_parse(assignment, args)
212*44554ea0SWill Pazner    quote
213*44554ea0SWill Pazner        arr_ref = Ref{Ptr{C.CeedScalar}}()
214*44554ea0SWill Pazner        C.CeedVectorGetArrayRead($(esc(v))[], $(esc(mtype)), arr_ref)
215*44554ea0SWill Pazner        try
216*44554ea0SWill Pazner            $(esc(arr)) = UnsafeArray(arr_ref[], Int.($sz))
217*44554ea0SWill Pazner            $(esc(body))
218*44554ea0SWill Pazner        finally
219*44554ea0SWill Pazner            C.CeedVectorRestoreArrayRead($(esc(v))[], arr_ref)
220*44554ea0SWill Pazner        end
221*44554ea0SWill Pazner    end
222*44554ea0SWill Paznerend
223*44554ea0SWill Pazner
224*44554ea0SWill Pazner"""
225*44554ea0SWill Pazner    setindex!(v::CeedVector, v2::AbstractArray)
226*44554ea0SWill Pazner    v[] = v2
227*44554ea0SWill Pazner
228*44554ea0SWill PaznerSets the values of [`CeedVector`](@ref) `v` equal to those of `v2` using broadcasting.
229*44554ea0SWill Pazner"""
230*44554ea0SWill PaznerBase.setindex!(v::CeedVector, v2::AbstractArray) = @witharray(a = v, a .= v2)
231*44554ea0SWill Pazner
232*44554ea0SWill Pazner"""
233*44554ea0SWill Pazner    CeedVector(c::Ceed, v2::AbstractVector; mtype=MEM_HOST, cmode=COPY_VALUES)
234*44554ea0SWill Pazner
235*44554ea0SWill PaznerCreates a new [`CeedVector`](@ref) using the contents of the given vector `v2`. By default,
236*44554ea0SWill Paznerthe contents of `v2` will be copied to the new [`CeedVector`](@ref), but this behavior can
237*44554ea0SWill Paznerbe changed by specifying a different `cmode`.
238*44554ea0SWill Pazner"""
239*44554ea0SWill Paznerfunction CeedVector(c::Ceed, v2::AbstractVector; mtype=MEM_HOST, cmode=COPY_VALUES)
240*44554ea0SWill Pazner    v = CeedVector(c, length(v2))
241*44554ea0SWill Pazner    setarray!(v, mtype, cmode, v2)
242*44554ea0SWill Pazner    v
243*44554ea0SWill Paznerend
244*44554ea0SWill Pazner
245*44554ea0SWill Pazner"""
246*44554ea0SWill Pazner    Vector(v::CeedVector)
247*44554ea0SWill Pazner
248*44554ea0SWill PaznerCreate a new `Vector` by copying the contents of `v`.
249*44554ea0SWill Pazner"""
250*44554ea0SWill Paznerfunction Base.Vector(v::CeedVector)
251*44554ea0SWill Pazner    v2 = Vector{CeedScalar}(undef, length(v))
252*44554ea0SWill Pazner    @witharray_read(a = v, v2 .= a)
253*44554ea0SWill Paznerend
254*44554ea0SWill Pazner
255*44554ea0SWill Pazner"""
256*44554ea0SWill Pazner    witharray(f, v::CeedVector, mtype=MEM_HOST)
257*44554ea0SWill Pazner
258*44554ea0SWill PaznerCalls `f` with an array containing the data of the `CeedVector` `v`, using [`memory
259*44554ea0SWill Paznertype`](@ref MemType) `mtype`.
260*44554ea0SWill Pazner
261*44554ea0SWill PaznerBecause of performance issues involving closures, if `f` is a complex operation, it may be
262*44554ea0SWill Paznermore efficient to use the macro version `@witharray` (cf. the section on "Performance of
263*44554ea0SWill Paznercaptured variable" in the [Julia
264*44554ea0SWill Paznerdocumentation](https://docs.julialang.org/en/v1/manual/performance-tips) and related [GitHub
265*44554ea0SWill Paznerissue](https://github.com/JuliaLang/julia/issues/15276).
266*44554ea0SWill Pazner
267*44554ea0SWill Pazner# Examples
268*44554ea0SWill Pazner
269*44554ea0SWill PaznerReturn the sum of a vector:
270*44554ea0SWill Pazner```
271*44554ea0SWill Paznerwitharray(sum, v)
272*44554ea0SWill Pazner```
273*44554ea0SWill Pazner"""
274*44554ea0SWill Paznerfunction witharray(f, v::CeedVector, mtype::MemType=MEM_HOST)
275*44554ea0SWill Pazner    arr_ref = Ref{Ptr{C.CeedScalar}}()
276*44554ea0SWill Pazner    C.CeedVectorGetArray(v[], mtype, arr_ref)
277*44554ea0SWill Pazner    arr = UnsafeArray(arr_ref[], (length(v),))
278*44554ea0SWill Pazner    res = try
279*44554ea0SWill Pazner        f(arr)
280*44554ea0SWill Pazner    finally
281*44554ea0SWill Pazner        C.CeedVectorRestoreArray(v[], arr_ref)
282*44554ea0SWill Pazner    end
283*44554ea0SWill Pazner    return res
284*44554ea0SWill Paznerend
285*44554ea0SWill Pazner
286*44554ea0SWill Pazner"""
287*44554ea0SWill Pazner    witharray_read(f, v::CeedVector, mtype::MemType=MEM_HOST)
288*44554ea0SWill Pazner
289*44554ea0SWill PaznerSame as [`witharray`](@ref), but with read-only access to the data.
290*44554ea0SWill Pazner
291*44554ea0SWill Pazner# Examples
292*44554ea0SWill Pazner
293*44554ea0SWill PaznerDisplay the contents of a vector:
294*44554ea0SWill Pazner```
295*44554ea0SWill Paznerwitharray_read(display, v)
296*44554ea0SWill Pazner```
297*44554ea0SWill Pazner"""
298*44554ea0SWill Paznerfunction witharray_read(f, v::CeedVector, mtype::MemType=MEM_HOST)
299*44554ea0SWill Pazner    arr_ref = Ref{Ptr{C.CeedScalar}}()
300*44554ea0SWill Pazner    C.CeedVectorGetArrayRead(v[], mtype, arr_ref)
301*44554ea0SWill Pazner    arr = UnsafeArray(arr_ref[], (length(v),))
302*44554ea0SWill Pazner    res = try
303*44554ea0SWill Pazner        f(arr)
304*44554ea0SWill Pazner    finally
305*44554ea0SWill Pazner        C.CeedVectorRestoreArrayRead(v[], arr_ref)
306*44554ea0SWill Pazner    end
307*44554ea0SWill Pazner    return res
308*44554ea0SWill Paznerend
309