Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SpaceDataModel

[![Documentation](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaSpacePhysics.github.io/SpaceDataModel.jl/dev/)
[![DOI](https://zenodo.org/badge/958430775.svg)](https://doi.org/10.5281/zenodo.15207556)
[![version](https://juliahub.com/docs/General/SpaceDataModel/stable/version.svg)](https://juliahub.com/ui/Packages/General/SpaceDataModel)

[![Build Status](https://github.com/JuliaSpacePhysics/SpaceDataModel.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaSpacePhysics/SpaceDataModel.jl/actions/workflows/CI.yml?query=branch%3Amain)
[![](https://img.shields.io/badge/%F0%9F%9B%A9%EF%B8%8F_tested_with-JET.jl-233f9a)](https://github.com/aviatesk/JET.jl)
Expand All @@ -14,12 +14,9 @@ SpaceDataModel.jl is a lightweight Julia package providing a flexible data model

For information on using the package, see the documentation available at https://JuliaSpacePhysics.github.io/SpaceDataModel.jl/dev/.

## Installation
**Installation**: at the Julia REPL, run `using Pkg; Pkg.add("SpaceDataModel")`

```julia
using Pkg
Pkg.add("SpaceDataModel")
```
**Documentation**: [![Dev](https://img.shields.io/badge/docs-dev-blue.svg?logo=julia)](https://JuliaSpacePhysics.github.io/SpaceDataModel.jl/dev/)

## Usage

Expand Down
24 changes: 14 additions & 10 deletions ext/SpaceDataModelDimensionalDataExt.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
module SpaceDataModelDimensionalDataExt

import SpaceDataModel
using DimensionalData: AbstractDimArray, TimeDim, dims, Dimension
using DimensionalData: AbstractDimArray, TimeDim, dims, Dimension, Dim
import DimensionalData as DD
import SpaceDataModel: meta, _merge, timedim, unwrap, name
import SpaceDataModel: meta, _merge, tdimnum, timedim, unwrap, name

_merge(::DD.NoMetadata, d, rest...) = merge(d, rest...)
meta(A::AbstractDimArray) = DD.metadata(A)
name(x::Dimension) = DD.name(x)
unwrap(x::Dimension) = parent(x)
SpaceDataModel.getmeta(A::AbstractDimArray) = DD.metadata(A)
SpaceDataModel.name(x::Dimension) = DD.name(x)
SpaceDataModel.unwrap(x::Dimension) = parent(x)

# A no-error version of `dimnum`
_dimnum(x, dim) = DD.hasdim(x, dim) ? DD.dimnum(x, dim) : nothing

SpaceDataModel.tdimnum(x::AbstractDimArray) = @something(
_dimnum(x, TimeDim),
_dimnum(x, Dim{:time}),
tdimnum(parent(x))
)

function SpaceDataModel.timedim(x::AbstractDimArray, query = nothing)
query = something(query, TimeDim)
qdim = dims(x, query)
return isnothing(qdim) ? dims(x, 1) : qdim
end
end
4 changes: 2 additions & 2 deletions src/SpaceDataModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ include("workload.jl")

include("variable_interface.jl")

include("times.jl")
using .Times
include("times.jl"); using .Times
include("timeseries.jl"); using .TimeSeriesAPI

end
11 changes: 0 additions & 11 deletions src/timerange.jl

This file was deleted.

18 changes: 17 additions & 1 deletion src/times.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
module Times
using Dates
using Dates: AbstractTime
export ≃, cadence
export ≃, cadence, parse_datetime

/ₜ(x, n) = x / n
/ₜ(x::AbstractTime, n) = Nanosecond(round(Int64, Dates.tons(x) / n))
Expand Down Expand Up @@ -35,4 +35,20 @@ function cadence(T::Type{<:Real}, times; kw...)
dt = cadence(times; kw...)
return dt isa AbstractTime ? T(Dates.tons(dt) / 1.0e9) : T(dt)
end


#########
# Parsing
#########

"""Check if a string is in Day of Year format (YYYY-DDD)."""
is_doy(str) = occursin(r"^(\d{4})-(\d{3})", str)

parse_doy_date(str, i = 5) = @views Date(str[1:(i - 1)]) + Day(str[(i + 1):(i + 3)]) - Day(1)
parse_doy_datetime(str) = @views parse_doy_date(str) + Time(str[10:end])
_parse_date(str) = is_doy(str) ? parse_doy_date(str) : Date(str)
_parse_datetime(str) = is_doy(str) ? parse_doy_datetime(str) : DateTime(str)

parse_datetime(str)::DateTime = 'T' ∉ str ? _parse_date(str) : _parse_datetime(str)

end
22 changes: 22 additions & 0 deletions src/timeseries.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""A time series-focused namespace for packages to share functions"""
module TimeSeriesAPI
using ..SpaceDataModel: dim, @getfield, unwrap
export tdimnum, timedim, times, tmin, tmax
"""
tdimnum(x)

Get the time dimension number of object `x`.
"""
function tdimnum(x)
@warn "Could not guess the time dimension number, assuming last dimension"
return ndims(x)
end

timedim(x) = dim(x, tdimnum(x))

times(v) = @getfield v (:times, :time) unwrap(timedim(v))

tmin(v) = minimum(times(v))
tmax(v) = maximum(times(v))

end
3 changes: 0 additions & 3 deletions src/variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ Base.setindex!(var::AbstractDataVariable, v, s::Union{String, Symbol}) = setinde
Base.get(var::AbstractDataVariable, s::Union{String, Symbol}, d = nothing) = _get(meta(var), s, d)
Base.get(f::Function, var::AbstractDataVariable, s::Union{String, Symbol}) = get(f, meta(var), s)

tmin(v) = minimum(times(v))
tmax(v) = maximum(times(v))

_timerange_str(times) = "Time Range: $(minimum(times)) to $(maximum(times))"

function Base.show(io::IO, var::T) where {T <: AbstractDataVariable}
Expand Down
6 changes: 2 additions & 4 deletions src/variable_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ function dim(x, s::Union{String, Symbol})
error("Dimension $s not found")
end

timedim(x) = dim(x, ndims(x))

"""
getmeta(x)

Get metadata for object `x`. If `x` does not have metadata, return `NoMetadata()`.

"""
getmeta(x) = @getfield x (:meta, :metadata) NoMetadata()
getmeta(x::AbstractDict) = x

# like get, but handles NamedTuple
_get(x, key, default) = get(x, key, default)
Expand All @@ -50,10 +49,9 @@ Get metadata value associated with `key` for object `x`, or `default` if `key` i
"""
getmeta(x, key, default = nothing) = _get(meta(x), key, default)

meta(x) = getmeta(x) # not exported (to be removed)
const meta = getmeta # not exported (to be removed)

units(v) = @get(v, "units", nothing)
times(v) = @getfield v (:times, :time) unwrap(timedim(v))

function unit(v)
us = units(v)
Expand Down
26 changes: 16 additions & 10 deletions test/ext/DimensionalData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,22 @@ end
@test dim(x, :X) == X(1:3)
@test_throws ErrorException dim(x, :time)

@test timedim(x) == Ti([1, 2, 3, 4, 5])
@test times(x) == [1, 2, 3, 4, 5]
@test tmin(x) == 1
@test tmax(x) == 5
@test unwrap(timedim(x)) == 1:5

@test name(timedim(x)) == :Ti
@test string(name(x)) == ""

@test unwrap(Ti(1:5)) == 1:5
@test Ti(1:5) isa DimensionalData.Dimension
@test unwrap(Ti(view([1, 2, 3, 4, 5], 2:3))) == view(1:5, 2:3)

@testset "TimeSeriesAPI" begin
using SpaceDataModel: tdimnum
x = rand(X(3), Ti(5), Z(2))
@test tdimnum(x) == 2
@test timedim(x) == Ti([1, 2, 3, 4, 5])
@test times(x) == [1, 2, 3, 4, 5]
@test tmin(x) == 1
@test tmax(x) == 5
@test unwrap(timedim(x)) == 1:5
@test name(timedim(x)) == :Ti

x = rand(X(3), Dim{:time}(5), Z(2))
@test tdimnum(x) == 2
@test (@allocated tdimnum(x)) == 0
end
end
Loading