module RefLists using Printf import ..CrystFEL: libcrystfel import ..CrystFEL.Symmetry: SymOpList, InternalSymOpList, symmetry_name export RefList, loadreflist, savereflist! export Reflection, UnmergedReflection, MergedReflection export InternalRefList # The internal libcrystfel structures, not exposed directly # We only ever have e.g. a Ptr{InternalRefList}, never a real InternalRefList mutable struct InternalRefList end mutable struct InternalReflection end mutable struct InternalRefListIterator end # The Julian exposed types abstract type Reflection end mutable struct RefList{T<:Reflection} internalptr::Ptr{InternalRefList} symmetry::SymOpList end mutable struct RefListIterator lastrefl::Ptr{InternalReflection} internalptr::Ptr{InternalRefListIterator} end mutable struct MergedReflection <: Reflection internalptr::Ptr{InternalReflection} end mutable struct UnmergedReflection <: Reflection internalptr::Ptr{InternalReflection} end function RefList{MergedReflection}(sym::SymOpList) out = @ccall libcrystfel.reflist_new()::Ptr{InternalRefList} if out == C_NULL throw(ErrorException("Failed to create RefList")) end finalizer(RefList{MergedReflection}(out, sym)) do x @ccall libcrystfel.reflist_free(x.internalptr::Ptr{InternalRefList})::Cvoid end end function Base.iterate(reflist::RefList{T}) where T rli = Ref{Ptr{InternalRefListIterator}}(C_NULL) refl = ccall((:first_refl, libcrystfel), Ptr{InternalReflection}, (Ptr{InternalRefList},Ref{Ptr{InternalRefListIterator}}), reflist.internalptr, rli) if refl == C_NULL return nothing # no reflections! end iter = RefListIterator(refl,rli[]) finalizer(iter) do x ccall((:free_reflistiterator, libcrystfel), Cvoid, (Ptr{InternalRefListIterator},), x.internalptr) end return T(refl),iter end function Base.iterate(::RefList{T}, iter) where T refl = ccall((:next_refl, libcrystfel), Ptr{InternalReflection}, (Ptr{InternalReflection},Ptr{InternalRefListIterator}), iter.lastrefl, iter.internalptr) if refl == C_NULL iter.internalptr = C_NULL # libcrystfel already freed it return nothing end iter.lastrefl = refl return T(refl),iter end Base.IteratorEltype(::RefList{T}) where T = T Base.isdone(iter::RefListIterator) = ((iter.internalptr == C_NULL) && (iter.lastrefl != C_NULL)) Base.length(reflist::RefList) = ccall((:num_reflections, libcrystfel), Cint, (Ptr{InternalRefList},), reflist.internalptr) function Base.getindex(reflist::RefList{T}, indices) where T refl = @ccall libcrystfel.find_refl(reflist.internalptr::Ptr{InternalRefList}, indices[1]::Cint, indices[2]::Cint, indices[3]::Cint)::Ptr{InternalReflection} if refl == C_NULL return nothing else return T(refl) end end function Base.get!(reflist::RefList{T}, indices) where T refl = @ccall libcrystfel.find_refl(reflist.internalptr::Ptr{InternalRefList}, indices[1]::Cint, indices[2]::Cint, indices[3]::Cint)::Ptr{InternalReflection} if refl == C_NULL return push!(reflist, indices) else return T(refl) end end function Base.push!(reflist::RefList{T}, indices) where T refl = @ccall libcrystfel.add_refl(reflist.internalptr::Ptr{InternalRefList}, indices[1]::Cint, indices[2]::Cint, indices[3]::Cint)::Ptr{InternalReflection} if refl == C_NULL return nothing else return T(refl) end end function loadreflist(filename::AbstractString) psym = Ref{Cstring}() out = ccall((:read_reflections_2, libcrystfel), Ptr{InternalRefList}, (Cstring,Ref{Cstring}), filename, psym) if out == C_NULL throw(ArgumentError("Failed to load reflection list")) end symmetryname = unsafe_string(psym[]) return RefList{MergedReflection}(out, SymOpList(symmetryname)) end function savereflist!(reflist::RefList{MergedReflection}, filename::AbstractString) r = @ccall libcrystfel.write_reflist_2(filename::Cstring, reflist.internalptr::Ptr{InternalRefList}, reflist.symmetry.internalptr::Ptr{InternalSymOpList})::Cint if r != 0 throw(ErrorException("Failed to save reflection list")) end end function Base.show(io::IO, ::MIME"text/plain", reflist::RefList{MergedReflection}) println(io, "Merged reflection list in point group ", symmetry_name(reflist.symmetry)) print(io, " h k l intensity σ(intens) nmeas") let n = 0 for refl in Iterators.take(reflist, 11) if n == 10 # We have printed 10 already, and are here again. Truncate... print(io, "\n ⋮ ⋮ ⋮ ⋮ ⋮ ⋮") break end let ind = refl.indices write(io, "\n") @printf(io, "%4i %4i %4i %10.2f %10.2f %5i", ind[1], ind[2], ind[3], refl.intensity, refl.sigintensity, refl.nmeasurements) n += 1 end end end end function Base.show(io::IO, ::MIME"text/plain", reflist::RefList{UnmergedReflection}) println(io, "Unmerged reflection list in point group ", symmetry_name(reflist.symmetry)) print(io, " h k l intensity σ(intens) fs ss panel") let n = 0 for refl in Iterators.take(reflist, 11) if n == 10 # We have printed 10 already, and are here again. Truncate... print(io, "\n ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮") break end let ind = refl.indices, pos = refl.detectorposition write(io, "\n") @printf(io, "%4i %4i %4i %10.2f %10.2f %7.2f %7.2f %6i", ind[1], ind[2], ind[3], refl.intensity, refl.sigintensity, pos.fs, pos.ss, pos.panelnumber) n += 1 end end end end function detectorpos(refl::Reflection) pfs = Ref{Cdouble}(0) pss = Ref{Cdouble}(0) pn = ccall((:get_panel_number, libcrystfel), Cint, (Ptr{InternalReflection},), refl.internalptr) ccall((:get_detector_pos, libcrystfel), Cint, (Ptr{InternalReflection},Ref{Cdouble},Ref{Cdouble}), refl.internalptr, pfs, pss) (fs=pfs[], ss=pss[], panelnumber=pn) end function indices(refl::Reflection) h = Ref{Cint}(0) k = Ref{Cint}(0) l = Ref{Cint}(0) ccall((:get_indices, libcrystfel), Cint, (Ptr{InternalReflection},Ref{Cint},Ref{Cint},Ref{Cint}), refl.internalptr, h, k, l) [h[], k[], l[]] end function symmetricindices(refl::Reflection) h = Ref{Cint}(0) k = Ref{Cint}(0) l = Ref{Cint}(0) ccall((:get_symmetric_indices, libcrystfel), Cint, (Ptr{InternalReflection},Ref{Cint},Ref{Cint},Ref{Cint}), refl.internalptr, h, k, l) [h[], k[], l[]] end function Base.getproperty(refl::Reflection, name::Symbol) if name === :intensity ccall((:get_intensity, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :sigintensity ccall((:get_esd_intensity, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :partiality ccall((:get_partiality, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :khalf ccall((:get_khalf, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :kpred ccall((:get_kpred, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :excitationerror ccall((:get_exerr, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :lorentzfactor ccall((:get_lorentz, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :phase ccall((:get_phase, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :peak ccall((:get_peak, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :meanbackground ccall((:get_mean_bg, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :temp1 ccall((:get_temp1, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :temp2 ccall((:get_temp2, libcrystfel), Cdouble, (Ptr{InternalReflection},), refl.internalptr) elseif name === :nmeasurements ccall((:get_redundancy, libcrystfel), Cint, (Ptr{InternalReflection},), refl.internalptr) elseif name === :flag ccall((:get_flag, libcrystfel), Cint, (Ptr{InternalReflection},), refl.internalptr) elseif name === :detectorposition detectorpos(refl) elseif name === :indices indices(refl) elseif name === :symmetricindices symmetricindices(refl) else getfield(refl, name) end end function Base.setproperty!(refl::Reflection, name::Symbol, val) if name === :intensity @ccall libcrystfel.set_intensity(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :sigintensity @ccall libcrystfel.set_esd_intensity(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :partiality @ccall libcrystfel.set_partiality(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :khalf @ccall libcrystfel.set_khalf(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :kpred @ccall libcrystfel.set_kpred(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :excitationerror @ccall libcrystfel.set_exerr(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :lorentzfactor @ccall libcrystfel.set_lorentz(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :phase @ccall libcrystfel.set_phase(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :peak @ccall libcrystfel.set_peak(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :meanbackground @ccall libcrystfel.set_mean_bg(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :temp1 @ccall libcrystfel.set_temp1(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :temp2 @ccall libcrystfel.set_temp2(refl.internalptr::Ptr{InternalReflection}, val::Cdouble)::Cvoid elseif name === :nmeasurements @ccall libcrystfel.set_redundancy(refl.internalptr::Ptr{InternalReflection}, val::Cint)::Cvoid elseif name === :flag @ccall libcrystfel.set_flag(refl.internalptr::Ptr{InternalReflection}, val::Cint)::Cvoid elseif name === :detectorposition @ccall libcrystfel.set_detector_pos(refl.internalptr::Ptr{InternalReflection}, val.fs::Cdouble, val.ss::Cdouble)::Cvoid @ccall libcrystfel.set_panel_number(refl.internalptr::Ptr{InternalReflection}, val.panelnumber::Cint)::Cvoid elseif name === :indices throw(ErrorException("Cannot set the indices of a Reflection")) elseif name === :symmetricindices @ccall libcrystfel.set_symmetric_indices(refl.internalptr::Ptr{InternalReflection}, val[1]::Cint, val[2]::Cint, val[3]::Cint)::Cvoid else setfield!(refl, name, val) end end function Base.propertynames(::UnmergedReflection; private=false) names = (:intensity,:sigintensity,:partiality,:khalf,:kpred,:lorentzfactor, :excitationerror,:phase,:peak,:meanbackground,:temp1,:temp2, :nmeasurements,:flag,:detectorposition,:indices,:symmetricindices) if private tuple(names..., :internalptr) else names end end function Base.propertynames(::MergedReflection; private=false) names = (:intensity,:sigintensity,:phase,:temp1,:temp2, :nmeasurements,:flag,:indices,:symmetricindices) if private tuple(names..., :internalptr) else names end end function Base.show(io::IO, refl::MergedReflection) write(io, "MergedReflection(") show(io, refl.indices) write(io, ", intensity=") show(io, refl.intensity) write(io, ", σ(intensity)=") show(io, refl.sigintensity) write(io, ", nmeasurements=") show(io, refl.nmeasurements) write(io, ")") end function Base.show(io::IO, refl::UnmergedReflection) write(io, "UnmergedReflection(") show(io, refl.indices) write(io, " at "); show(io, refl.detectorposition) write(io, ", intensity=") show(io, refl.intensity) write(io, ", σ(intensity)=") show(io, refl.sigintensity) write(io, ")") end end # of module