xref: /libCEED/julia/LibCEED.jl/src/CeedVector.jl (revision d8e1a4b6f5dbf7727064245c064b125e542dddad)
1557acef3SWill Paznerimport LinearAlgebra: norm, axpy!
244554ea0SWill Pazner
344554ea0SWill Paznerabstract type AbstractCeedVector end
444554ea0SWill Pazner
544554ea0SWill Paznerstruct CeedVectorActive <: AbstractCeedVector end
644554ea0SWill PaznerBase.getindex(::CeedVectorActive) = C.CEED_VECTOR_ACTIVE[]
744554ea0SWill Pazner
844554ea0SWill Paznerstruct CeedVectorNone <: AbstractCeedVector end
944554ea0SWill PaznerBase.getindex(::CeedVectorNone) = C.CEED_VECTOR_NONE[]
1044554ea0SWill Pazner
1144554ea0SWill Paznermutable struct CeedVector <: AbstractCeedVector
1244554ea0SWill Pazner    ref::RefValue{C.CeedVector}
1344554ea0SWill Pazner    arr::Union{Nothing,AbstractArray}
1444554ea0SWill Pazner    CeedVector(ref::Ref{C.CeedVector}) = new(ref, nothing)
1544554ea0SWill Paznerend
1644554ea0SWill Pazner
1744554ea0SWill Pazner"""
18*63a9f6bcSWill Pazner    CeedVector(c::Ceed, len::Integer; allocate::Bool=true)
1944554ea0SWill Pazner
20*63a9f6bcSWill PaznerCreates a `CeedVector` of given length. If `allocate` is false, then no memory is allocated.
21*63a9f6bcSWill PaznerAttemping to access the vector before calling `setarray!` will fail. By default, `allocate` is
22*63a9f6bcSWill Paznertrue, and libCEED will allocate (host) memory for the vector.
2344554ea0SWill Pazner"""
24*63a9f6bcSWill Paznerfunction CeedVector(c::Ceed, len::Integer; allocate::Bool=true)
2544554ea0SWill Pazner    ref = Ref{C.CeedVector}()
2644554ea0SWill Pazner    C.CeedVectorCreate(c[], len, ref)
2744554ea0SWill Pazner    obj = CeedVector(ref)
2844554ea0SWill Pazner    finalizer(obj) do x
2944554ea0SWill Pazner        # ccall(:jl_safe_printf, Cvoid, (Cstring, Cstring), "Finalizing %s.\n", repr(x))
3044554ea0SWill Pazner        destroy(x)
3144554ea0SWill Pazner    end
32*63a9f6bcSWill Pazner    if allocate
33*63a9f6bcSWill Pazner        setarray!(obj, MEM_HOST, COPY_VALUES, C_NULL)
34*63a9f6bcSWill Pazner    end
3544554ea0SWill Pazner    return obj
3644554ea0SWill Paznerend
3744554ea0SWill Paznerdestroy(v::CeedVector) = C.CeedVectorDestroy(v.ref) # COV_EXCL_LINE
3844554ea0SWill PaznerBase.getindex(v::CeedVector) = v.ref[]
3944554ea0SWill Pazner
4044554ea0SWill PaznerBase.summary(io::IO, v::CeedVector) = print(io, length(v), "-element CeedVector")
4144554ea0SWill Paznerfunction Base.show(io::IO, ::MIME"text/plain", v::CeedVector)
4244554ea0SWill Pazner    summary(io, v)
4344554ea0SWill Pazner    println(io, ":")
4444554ea0SWill Pazner    witharray_read(v, MEM_HOST) do arr
4544554ea0SWill Pazner        Base.print_array(io, arr)
4644554ea0SWill Pazner    end
4744554ea0SWill Paznerend
4844554ea0SWill PaznerBase.show(io::IO, v::CeedVector) = witharray_read(a -> show(io, a), v, MEM_HOST)
4944554ea0SWill Pazner
5044554ea0SWill Paznerfunction Base.length(::Type{T}, v::CeedVector) where {T}
510057404bSWill Pazner    len = Ref{C.CeedSize}()
5244554ea0SWill Pazner    C.CeedVectorGetLength(v[], len)
5344554ea0SWill Pazner    return T(len[])
5444554ea0SWill Paznerend
5544554ea0SWill Pazner
5644554ea0SWill PaznerBase.ndims(::CeedVector) = 1
5744554ea0SWill PaznerBase.ndims(::Type{CeedVector}) = 1
5844554ea0SWill PaznerBase.axes(v::CeedVector) = (Base.OneTo(length(v)),)
5944554ea0SWill PaznerBase.size(v::CeedVector) = (length(Int, v),)
6044554ea0SWill PaznerBase.length(v::CeedVector) = length(Int, v)
6144554ea0SWill Pazner
6244554ea0SWill Pazner"""
63278ca478SWill Pazner    setvalue!(v::CeedVector, val::Real)
6444554ea0SWill Pazner
6544554ea0SWill PaznerSet the [`CeedVector`](@ref) to a constant value.
6644554ea0SWill Pazner"""
67278ca478SWill Paznersetvalue!(v::CeedVector, val::Real) = C.CeedVectorSetValue(v[], val)
6844554ea0SWill Pazner"""
69278ca478SWill Pazner    setindex!(v::CeedVector, val::Real)
7044554ea0SWill Pazner    v[] = val
7144554ea0SWill Pazner
7244554ea0SWill PaznerSet the [`CeedVector`](@ref) to a constant value, synonymous to [`setvalue!`](@ref).
7344554ea0SWill Pazner"""
74278ca478SWill PaznerBase.setindex!(v::CeedVector, val::Real) = setvalue!(v, val)
7544554ea0SWill Pazner
7644554ea0SWill Pazner"""
7744554ea0SWill Pazner    norm(v::CeedVector, ntype::NormType)
7844554ea0SWill Pazner
7944554ea0SWill PaznerReturn the norm of the given [`CeedVector`](@ref).
8044554ea0SWill Pazner
8144554ea0SWill PaznerThe norm type can either be specified as one of `NORM_1`, `NORM_2`, `NORM_MAX`.
8244554ea0SWill Pazner"""
8344554ea0SWill Paznerfunction norm(v::CeedVector, ntype::NormType)
8444554ea0SWill Pazner    nrm = Ref{CeedScalar}()
8544554ea0SWill Pazner    C.CeedVectorNorm(v[], ntype, nrm)
8644554ea0SWill Pazner    nrm[]
8744554ea0SWill Paznerend
8844554ea0SWill Pazner
8944554ea0SWill Pazner"""
9044554ea0SWill Pazner    norm(v::CeedVector, p::Real)
9144554ea0SWill Pazner
9244554ea0SWill PaznerReturn the norm of the given [`CeedVector`](@ref), see [`norm(::CeedVector,
9344554ea0SWill Pazner::NormType)`](@ref).
9444554ea0SWill Pazner
9544554ea0SWill Pazner`p` can have value 1, 2, or Inf, corresponding to `NORM_1`, `NORM_2`, and `NORM_MAX`,
9644554ea0SWill Paznerrespectively.
9744554ea0SWill Pazner"""
9844554ea0SWill Paznerfunction norm(v::CeedVector, p::Real)
9944554ea0SWill Pazner    if p == 1
10044554ea0SWill Pazner        ntype = NORM_1
10144554ea0SWill Pazner    elseif p == 2
10244554ea0SWill Pazner        ntype = NORM_2
10344554ea0SWill Pazner    elseif isinf(p)
10444554ea0SWill Pazner        ntype = NORM_MAX
10544554ea0SWill Pazner    else
10644554ea0SWill Pazner        error("norm(v::CeedVector, p): p must be 1, 2, or Inf")
10744554ea0SWill Pazner    end
10844554ea0SWill Pazner    norm(v, ntype)
10944554ea0SWill Paznerend
11044554ea0SWill Pazner
11144554ea0SWill Pazner"""
11244554ea0SWill Pazner    reciprocal!(v::CeedVector)
11344554ea0SWill Pazner
11444554ea0SWill PaznerSet `v` to be equal to its elementwise reciprocal.
11544554ea0SWill Pazner"""
11644554ea0SWill Paznerreciprocal!(v::CeedVector) = C.CeedVectorReciprocal(v[])
11744554ea0SWill Pazner
11844554ea0SWill Pazner"""
11944554ea0SWill Pazner    setarray!(v::CeedVector, mtype::MemType, cmode::CopyMode, arr)
12044554ea0SWill Pazner
12144554ea0SWill PaznerSet the array used by a [`CeedVector`](@ref), freeing any previously allocated array if
12244554ea0SWill Paznerapplicable. The backend may copy values to a different [`MemType`](@ref). See also
12344554ea0SWill Pazner[`syncarray!`](@ref) and [`takearray!`](@ref).
12444554ea0SWill Pazner
12544554ea0SWill Pazner!!! warning "Avoid OWN_POINTER CopyMode"
12644554ea0SWill Pazner    The [`CopyMode`](@ref) `OWN_POINTER` is not suitable for use with arrays that are
12744554ea0SWill Pazner    allocated by Julia, since those cannot be properly freed from libCEED.
12844554ea0SWill Pazner"""
12944554ea0SWill Paznerfunction setarray!(v::CeedVector, mtype::MemType, cmode::CopyMode, arr)
13044554ea0SWill Pazner    C.CeedVectorSetArray(v[], mtype, cmode, arr)
13144554ea0SWill Pazner    if cmode == USE_POINTER
13244554ea0SWill Pazner        v.arr = arr
13344554ea0SWill Pazner    end
13444554ea0SWill Paznerend
13544554ea0SWill Pazner
13644554ea0SWill Pazner"""
13744554ea0SWill Pazner    syncarray!(v::CeedVector, mtype::MemType)
13844554ea0SWill Pazner
13944554ea0SWill PaznerSync the [`CeedVector`](@ref) to a specified [`MemType`](@ref). This function is used to
14044554ea0SWill Paznerforce synchronization of arrays set with [`setarray!`](@ref). If the requested memtype is
14144554ea0SWill Pazneralready synchronized, this function results in a no-op.
14244554ea0SWill Pazner"""
14344554ea0SWill Paznersyncarray!(v::CeedVector, mtype::MemType) = C.CeedVectorSyncArray(v[], mtype)
14444554ea0SWill Pazner
14544554ea0SWill Pazner"""
14644554ea0SWill Pazner    takearray!(v::CeedVector, mtype::MemType)
14744554ea0SWill Pazner
14844554ea0SWill PaznerTake ownership of the [`CeedVector`](@ref) array and remove the array from the
14944554ea0SWill Pazner[`CeedVector`](@ref). The caller is responsible for managing and freeing the array. The
15044554ea0SWill Paznerarray is returns as a `Ptr{CeedScalar}`.
15144554ea0SWill Pazner"""
15244554ea0SWill Paznerfunction takearray!(v::CeedVector, mtype::MemType)
15344554ea0SWill Pazner    ptr = Ref{Ptr{CeedScalar}}()
15444554ea0SWill Pazner    C.CeedVectorTakeArray(v[], mtype, ptr)
15544554ea0SWill Pazner    v.arr = nothing
15644554ea0SWill Pazner    ptr[]
15744554ea0SWill Paznerend
15844554ea0SWill Pazner
15944554ea0SWill Pazner# Helper function to parse arguments of @witharray and @witharray_read
16044554ea0SWill Paznerfunction witharray_parse(assignment, args)
16144554ea0SWill Pazner    if !Meta.isexpr(assignment, :(=))
16244554ea0SWill Pazner        error("@witharray must have first argument of the form v_arr=v") # COV_EXCL_LINE
16344554ea0SWill Pazner    end
16444554ea0SWill Pazner    arr = assignment.args[1]
16544554ea0SWill Pazner    v = assignment.args[2]
16644554ea0SWill Pazner    mtype = MEM_HOST
16744554ea0SWill Pazner    sz = :((length($(esc(v))),))
16844554ea0SWill Pazner    body = args[end]
16944554ea0SWill Pazner    for i = 1:length(args)-1
17044554ea0SWill Pazner        a = args[i]
17144554ea0SWill Pazner        if !Meta.isexpr(a, :(=))
17244554ea0SWill Pazner            error("Incorrect call to @witharray or @witharray_read") # COV_EXCL_LINE
17344554ea0SWill Pazner        end
17444554ea0SWill Pazner        if a.args[1] == :mtype
17544554ea0SWill Pazner            mtype = a.args[2]
17644554ea0SWill Pazner        elseif a.args[1] == :size
17744554ea0SWill Pazner            sz = esc(a.args[2])
17844554ea0SWill Pazner        end
17944554ea0SWill Pazner    end
18044554ea0SWill Pazner    arr, v, sz, mtype, body
18144554ea0SWill Paznerend
18244554ea0SWill Pazner
18344554ea0SWill Pazner"""
18444554ea0SWill Pazner    @witharray(v_arr=v, [size=(dims...)], [mtype=MEM_HOST], body)
18544554ea0SWill Pazner
18644554ea0SWill PaznerExecutes `body`, having extracted the contents of the [`CeedVector`](@ref) `v` as an array
18744554ea0SWill Paznerwith name `v_arr`. If the [`memory type`](@ref MemType) `mtype` is not provided, `MEM_HOST`
18844554ea0SWill Paznerwill be used. If the size is not specified, a flat vector will be assumed.
18944554ea0SWill Pazner
19044554ea0SWill Pazner# Examples
19144554ea0SWill PaznerNegate the contents of `CeedVector` `v`:
19244554ea0SWill Pazner```
193557acef3SWill Pazner@witharray v_arr=v v_arr .*= -1.0
19444554ea0SWill Pazner```
19544554ea0SWill Pazner"""
19644554ea0SWill Paznermacro witharray(assignment, args...)
19744554ea0SWill Pazner    arr, v, sz, mtype, body = witharray_parse(assignment, args)
19844554ea0SWill Pazner    quote
19944554ea0SWill Pazner        arr_ref = Ref{Ptr{C.CeedScalar}}()
20044554ea0SWill Pazner        C.CeedVectorGetArray($(esc(v))[], $(esc(mtype)), arr_ref)
20144554ea0SWill Pazner        try
20244554ea0SWill Pazner            $(esc(arr)) = UnsafeArray(arr_ref[], Int.($sz))
20344554ea0SWill Pazner            $(esc(body))
20444554ea0SWill Pazner        finally
20544554ea0SWill Pazner            C.CeedVectorRestoreArray($(esc(v))[], arr_ref)
20644554ea0SWill Pazner        end
20744554ea0SWill Pazner    end
20844554ea0SWill Paznerend
20944554ea0SWill Pazner
21044554ea0SWill Pazner"""
21144554ea0SWill Pazner    @witharray_read(v_arr=v, [size=(dims...)], [mtype=MEM_HOST], body)
21244554ea0SWill Pazner
21344554ea0SWill PaznerSame as [`@witharray`](@ref), but provides read-only access to the data.
21444554ea0SWill Pazner"""
21544554ea0SWill Paznermacro witharray_read(assignment, args...)
21644554ea0SWill Pazner    arr, v, sz, mtype, body = witharray_parse(assignment, args)
21744554ea0SWill Pazner    quote
21844554ea0SWill Pazner        arr_ref = Ref{Ptr{C.CeedScalar}}()
21944554ea0SWill Pazner        C.CeedVectorGetArrayRead($(esc(v))[], $(esc(mtype)), arr_ref)
22044554ea0SWill Pazner        try
22144554ea0SWill Pazner            $(esc(arr)) = UnsafeArray(arr_ref[], Int.($sz))
22244554ea0SWill Pazner            $(esc(body))
22344554ea0SWill Pazner        finally
22444554ea0SWill Pazner            C.CeedVectorRestoreArrayRead($(esc(v))[], arr_ref)
22544554ea0SWill Pazner        end
22644554ea0SWill Pazner    end
22744554ea0SWill Paznerend
22844554ea0SWill Pazner
22944554ea0SWill Pazner"""
23044554ea0SWill Pazner    setindex!(v::CeedVector, v2::AbstractArray)
23144554ea0SWill Pazner    v[] = v2
23244554ea0SWill Pazner
23344554ea0SWill PaznerSets the values of [`CeedVector`](@ref) `v` equal to those of `v2` using broadcasting.
23444554ea0SWill Pazner"""
23544554ea0SWill PaznerBase.setindex!(v::CeedVector, v2::AbstractArray) = @witharray(a = v, a .= v2)
23644554ea0SWill Pazner
23744554ea0SWill Pazner"""
23844554ea0SWill Pazner    CeedVector(c::Ceed, v2::AbstractVector; mtype=MEM_HOST, cmode=COPY_VALUES)
23944554ea0SWill Pazner
24044554ea0SWill PaznerCreates a new [`CeedVector`](@ref) using the contents of the given vector `v2`. By default,
24144554ea0SWill Paznerthe contents of `v2` will be copied to the new [`CeedVector`](@ref), but this behavior can
24244554ea0SWill Paznerbe changed by specifying a different `cmode`.
24344554ea0SWill Pazner"""
24444554ea0SWill Paznerfunction CeedVector(c::Ceed, v2::AbstractVector; mtype=MEM_HOST, cmode=COPY_VALUES)
245*63a9f6bcSWill Pazner    v = CeedVector(c, length(v2); allocate=false)
24644554ea0SWill Pazner    setarray!(v, mtype, cmode, v2)
24744554ea0SWill Pazner    v
24844554ea0SWill Paznerend
24944554ea0SWill Pazner
25044554ea0SWill Pazner"""
25144554ea0SWill Pazner    Vector(v::CeedVector)
25244554ea0SWill Pazner
25344554ea0SWill PaznerCreate a new `Vector` by copying the contents of `v`.
25444554ea0SWill Pazner"""
25544554ea0SWill Paznerfunction Base.Vector(v::CeedVector)
25644554ea0SWill Pazner    v2 = Vector{CeedScalar}(undef, length(v))
25744554ea0SWill Pazner    @witharray_read(a = v, v2 .= a)
25844554ea0SWill Paznerend
25944554ea0SWill Pazner
26044554ea0SWill Pazner"""
26144554ea0SWill Pazner    witharray(f, v::CeedVector, mtype=MEM_HOST)
26244554ea0SWill Pazner
26344554ea0SWill PaznerCalls `f` with an array containing the data of the `CeedVector` `v`, using [`memory
26444554ea0SWill Paznertype`](@ref MemType) `mtype`.
26544554ea0SWill Pazner
26644554ea0SWill PaznerBecause of performance issues involving closures, if `f` is a complex operation, it may be
26744554ea0SWill Paznermore efficient to use the macro version `@witharray` (cf. the section on "Performance of
26844554ea0SWill Paznercaptured variable" in the [Julia
26944554ea0SWill Paznerdocumentation](https://docs.julialang.org/en/v1/manual/performance-tips) and related [GitHub
27044554ea0SWill Paznerissue](https://github.com/JuliaLang/julia/issues/15276).
27144554ea0SWill Pazner
27244554ea0SWill Pazner# Examples
27344554ea0SWill Pazner
27444554ea0SWill PaznerReturn the sum of a vector:
27544554ea0SWill Pazner```
27644554ea0SWill Paznerwitharray(sum, v)
27744554ea0SWill Pazner```
27844554ea0SWill Pazner"""
27944554ea0SWill Paznerfunction witharray(f, v::CeedVector, mtype::MemType=MEM_HOST)
28044554ea0SWill Pazner    arr_ref = Ref{Ptr{C.CeedScalar}}()
28144554ea0SWill Pazner    C.CeedVectorGetArray(v[], mtype, arr_ref)
28244554ea0SWill Pazner    arr = UnsafeArray(arr_ref[], (length(v),))
28344554ea0SWill Pazner    res = try
28444554ea0SWill Pazner        f(arr)
28544554ea0SWill Pazner    finally
28644554ea0SWill Pazner        C.CeedVectorRestoreArray(v[], arr_ref)
28744554ea0SWill Pazner    end
28844554ea0SWill Pazner    return res
28944554ea0SWill Paznerend
29044554ea0SWill Pazner
29144554ea0SWill Pazner"""
29244554ea0SWill Pazner    witharray_read(f, v::CeedVector, mtype::MemType=MEM_HOST)
29344554ea0SWill Pazner
29444554ea0SWill PaznerSame as [`witharray`](@ref), but with read-only access to the data.
29544554ea0SWill Pazner
29644554ea0SWill Pazner# Examples
29744554ea0SWill Pazner
29844554ea0SWill PaznerDisplay the contents of a vector:
29944554ea0SWill Pazner```
30044554ea0SWill Paznerwitharray_read(display, v)
30144554ea0SWill Pazner```
30244554ea0SWill Pazner"""
30344554ea0SWill Paznerfunction witharray_read(f, v::CeedVector, mtype::MemType=MEM_HOST)
30444554ea0SWill Pazner    arr_ref = Ref{Ptr{C.CeedScalar}}()
30544554ea0SWill Pazner    C.CeedVectorGetArrayRead(v[], mtype, arr_ref)
30644554ea0SWill Pazner    arr = UnsafeArray(arr_ref[], (length(v),))
30744554ea0SWill Pazner    res = try
30844554ea0SWill Pazner        f(arr)
30944554ea0SWill Pazner    finally
31044554ea0SWill Pazner        C.CeedVectorRestoreArrayRead(v[], arr_ref)
31144554ea0SWill Pazner    end
31244554ea0SWill Pazner    return res
31344554ea0SWill Paznerend
314557acef3SWill Pazner
315557acef3SWill Pazner"""
316557acef3SWill Pazner    scale!(v::CeedVector, a::Real)
317557acef3SWill Pazner
318557acef3SWill PaznerOverwrite `v` with `a*v` for scalar `a`. Returns `v`.
319557acef3SWill Pazner"""
320557acef3SWill Paznerfunction scale!(v::CeedVector, a::Real)
321557acef3SWill Pazner    C.CeedVectorScale(v[], a)
322557acef3SWill Pazner    return v
323557acef3SWill Paznerend
324557acef3SWill Pazner
325557acef3SWill Pazner"""
326557acef3SWill Pazner    axpy!(a::Real, x::CeedVector, y::CeedVector)
327557acef3SWill Pazner
328557acef3SWill PaznerOverwrite `y` with `x*a + y`, where `a` is a scalar. Returns `y`.
329557acef3SWill Pazner
330557acef3SWill Pazner!!! warning "Different argument order"
331557acef3SWill Pazner    In order to be consistent with `LinearAlgebra.axpy!`, the arguments are passed in order: `a`,
332557acef3SWill Pazner    `x`, `y`. This is different than the order of arguments of the C function `CeedVectorAXPY`.
333557acef3SWill Pazner"""
334557acef3SWill Paznerfunction axpy!(a::Real, x::CeedVector, y::CeedVector)
335557acef3SWill Pazner    C.CeedVectorAXPY(y[], a, x[])
336557acef3SWill Pazner    return y
337557acef3SWill Paznerend
338557acef3SWill Pazner
339557acef3SWill Pazner"""
340557acef3SWill Pazner    pointwisemult!(w::CeedVector, x::CeedVector, y::CeedVector)
341557acef3SWill Pazner
342557acef3SWill PaznerOverwrite `w` with `x .* y`. Any subset of x, y, and w may be the same vector. Returns `w`.
343557acef3SWill Pazner"""
344557acef3SWill Paznerfunction pointwisemult!(w::CeedVector, x::CeedVector, y::CeedVector)
345557acef3SWill Pazner    C.CeedVectorPointwiseMult(w[], x[], y[])
346557acef3SWill Pazner    return w
347557acef3SWill Paznerend
348