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