diff --git a/docs/Project.toml b/docs/Project.toml index 7938a1f..a5ac1fa 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,3 +1,4 @@ [deps] +Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -SpaceDataModel = "0b37b92c-f0c5-4a52-bd5c-390dec20857c" \ No newline at end of file +SpaceDataModel = "0b37b92c-f0c5-4a52-bd5c-390dec20857c" diff --git a/docs/make.jl b/docs/make.jl index b83cc60..3d6721f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -10,6 +10,7 @@ makedocs( pages = [ "Home" => "index.md", "Interface" => "interface.md", + "Coordinate Systems" => "coordinate.md", "API" => "api.md", ], checkdocs = :exports, diff --git a/docs/src/coordinate.md b/docs/src/coordinate.md new file mode 100644 index 0000000..7e5b34a --- /dev/null +++ b/docs/src/coordinate.md @@ -0,0 +1,81 @@ +# Coordinate Systems + +Similart to the definitions in [Astropy](https://docs.astropy.org/en/stable/coordinates/definitions.html): we adopt the following terminology: + +- A **Coordinate Representation** (chart) is a particular way of describing a unique point in a vector space. + Common ones include `Cartesian3`, `Spherical`, and `Geodetic` based on [`AbstractRepresentation`](@ref). +- A **Reference System** is a scheme for orienting points in a space and describing how they transform to other systems. + For example, the Earth-centered, Earth-fixed (ECEF) reference system tells you (i) origin at the geocenter, (ii) axes rotate with the Earth. But it does not uniquely specify: (i) whether Z is ITRF pole, [Conventional International Origin pole](https://www.wikiwand.com/en/articles/Conventional_International_Origin), "instantaneous rotation axis", etc (ii) whether the axes are aligned to a particular [geodetic datum](https://www.wikiwand.com/en/articles/Geodetic_datum). +- A **Reference Frame** is a specific realization of a reference system (e.g., the [ICRF](https://www.wikiwand.com/en/articles/International_Celestial_Reference_System_and_its_realizations), or J2000 equatorial coordinates). + For example, GEO is a simplified ECEF realization suitable for space-physics transformations (GEO↔GSE/GSM/SM/MAG). It differs from “true” geodesy realization like [ITRF](https://www.wikiwand.com/en/articles/International_Terrestrial_Reference_System_and_Frame) in that it ignores small corrections like polar motion and uses a simplified Earth rotation model. +- A **Coordinate** is a combination of all of the above that specifies a unique point. + + + +The package exports the following types [`AbstractReferenceSystem`](@ref), [`AbstractRepresentation`](@ref), [`AbstractReferenceFrame`](@ref), and [`AbstractCoordinateVector`](@ref): + +And related functions: + +- [`getcsys`](@ref): Function to retrieve the coordinate system from an object + + +!!! note "Notes" + Because of the ambiguity of meaning of "coordinate system", this term should be avoided wherever possible. However, for backward compatibility, we still export [`AbstractCoordinateSystem`](@ref) which serves a practical purpose of combining reference frame and coordinate representation. + +## Implementation Approaches + +Here we demonstrate two approaches to implementing coordinate vectors and their associated systems: + +### Approach 1: Explicit Coordinate System Field + +Store the coordinate system directly as a field in the vector type: + +```@repl coord +using SpaceDataModel: Cartesian3, AbstractReferenceFrame, AbstractCoordinateVector +import SpaceDataModel: getcsys +# Define a reference frame +struct GEO <: AbstractReferenceFrame end + +# Define a vector with an explicit reference frame and representation +struct CoordinateVector{F, R, T} <: AbstractCoordinateVector + x::T + y::T + z::T +end + +𝐫 = CoordinateVector{GEO, Cartesian3, Float64}(1, 2, 3) + +# Implementation of getcsys +getcsys(::CoordinateVector{F, R}) where {F, R} = (F(), R()) +getcsys(𝐫) +``` + +### Approach 2: Implicit Coordinate System + +Associate a specific coordinate system with a vector type: + +```@repl coord +# Define a vector type specific to a coordinate system +struct GEOVector{D} <: AbstractCoordinateVector + data::D +end + +# Implementation of getcsys returns the appropriate system +getcsys(::GEOVector) = (GEO(), Cartesian3()) +𝐫2 = GEOVector([1, 2, 3]) +getcsys(𝐫2) +``` + +Both approaches are highly efficient and provide equivalent performance due to Julia's type inference system. + +```@example coord +using Chairmarks +@b getcsys($𝐫), getcsys($𝐫2) +``` + +## Elsewhere + +- [Astronomical Coordinate Systems (astropy.coordinates) — Astropy](https://docs.astropy.org/en/stable/coordinates/index.html) +- [CoordRefSystems.jl](https://github.com/JuliaEarth/CoordRefSystems.jl) provides conversions between Coordinate Reference Systems (CRS) for cartography use cases. +- [Geodesy.jl](https://github.com/JuliaGeo/Geodesy.jl) for working with points in various world and local coordinate systems. +- [WCS.jl](https://juliaastro.org/WCS/stable/) : Astronomical World Coordinate System library \ No newline at end of file diff --git a/docs/src/interface.md b/docs/src/interface.md index 3a2974e..4dd61cf 100644 --- a/docs/src/interface.md +++ b/docs/src/interface.md @@ -20,58 +20,4 @@ These functions are generic and can be extended to support custom data types. getmeta setmeta setmeta! -``` - -## Coordinate Systems - -The package exports three key components for coordinate system handling: - -- [`AbstractCoordinateSystem`](@ref): Base abstract type for all coordinate system implementations -- [`AbstractCoordinateVector`](@ref): Base abstract type to represent coordinates in a coordinate systems -- [`getcsys`](@ref): Function to retrieve the coordinate system from an object - - -There are two main approaches to implementing coordinate vectors and their associated systems: - -### Approach 1: Explicit Coordinate System Field - -Store the coordinate system directly as a field in the vector type: - -```julia -# Define a coordinate system -struct GEO <: AbstractCoordinateSystem end - -# Define a vector with an explicit coordinate system field -struct CoordinateVector{D, T} <: AbstractCoordinateVector - data::D - csys::T -end - -# Implementation of getcsys simply returns the stored field -getcsys(x::CoordinateVector) = x.csys -``` - -### Approach 2: Implicit Coordinate System - -Associate a specific coordinate system with a vector type: - -```julia -# Define a coordinate system -struct GEO <: AbstractCoordinateSystem end - -# Define a vector type specific to a coordinate system -struct GEOVector{D} <: AbstractCoordinateVector - data::D -end - -# Implementation of getcsys returns the appropriate system -getcsys(x::GEOVector) = GEO() -``` - -Both approaches are highly efficient and provide equivalent performance due to Julia's type inference system. - -### Elsewhere - -- [CoordRefSystems.jl](https://github.com/JuliaEarth/CoordRefSystems.jl) provides conversions between Coordinate Reference Systems (CRS) for cartography use cases. -- [Geodesy.jl](https://github.com/JuliaGeo/Geodesy.jl) for working with points in various world and local coordinate systems. -- [WCS.jl](https://juliaastro.org/WCS/stable/) : Astronomical World Coordinate System library \ No newline at end of file +``` \ No newline at end of file diff --git a/src/SpaceDataModel.jl b/src/SpaceDataModel.jl index e62af77..3f76ac1 100644 --- a/src/SpaceDataModel.jl +++ b/src/SpaceDataModel.jl @@ -9,6 +9,7 @@ export AbstractModel, AbstractProject, AbstractInstrument, AbstractProduct, Abst export AbstractDataVariable export Project, Instrument, DataSet, LDataSet, Product export Event +export AbstractReferenceFrame, AbstractRepresentation export AbstractCoordinateSystem, AbstractCoordinateVector, getcsys export getmeta, setmeta!, setmeta export getdim, tdimnum @@ -24,6 +25,9 @@ include("catalog.jl") include("coord.jl") include("workload.jl") +include("coordinates/reference_frame.jl") +include("coordinates/representation.jl") + include("variable_interface.jl") const getdim = dim diff --git a/src/coord.jl b/src/coord.jl index 3741dfa..3678228 100644 --- a/src/coord.jl +++ b/src/coord.jl @@ -1,6 +1,5 @@ import Base: String - """ AbstractCoordinateSystem @@ -18,7 +17,7 @@ abstract type AbstractCoordinateVector end """ getcsys(x) -Get the coordinate system of `x`. +Get the coordinate system of `x`. Ideally, this should return both the reference frame and coordinate representation. If `x` is a instance of `AbstractCoordinateSystem`, return `x` itself. If `x` is a type of `AbstractCoordinateSystem`, return an instance of the coordinate system, i.e. `x()`. diff --git a/src/coordinates/reference_frame.jl b/src/coordinates/reference_frame.jl new file mode 100644 index 0000000..30c7455 --- /dev/null +++ b/src/coordinates/reference_frame.jl @@ -0,0 +1,19 @@ +# https://docs.astropy.org/en/stable/coordinates/frames.html +# https://docs.sunpy.org/en/stable/reference/coordinates/index.html + +""" +A Reference System is a scheme for orienting points in a space and describing how they transform to other systems. + +See also: [`AbstractReferenceFrame`](@ref) +""" +abstract type AbstractReferenceSystem end + +""" +A specific realization of a reference system. +""" +abstract type AbstractReferenceFrame end + +""" +Frames can depend on epoch and planetary orientation models +""" +abstract type TimeDependentFrame <: AbstractReferenceFrame end diff --git a/src/coordinates/representation.jl b/src/coordinates/representation.jl new file mode 100644 index 0000000..adcc34d --- /dev/null +++ b/src/coordinates/representation.jl @@ -0,0 +1,12 @@ +""" +Abstract base for representing a point in a 3D coordinate system. + +# Reference: +- https://docs.astropy.org/en/stable/coordinates/representations.html +- https://github.com/JuliaEarth/CoordRefSystems.jl/blob/main/src/crs.jl +""" +abstract type AbstractRepresentation end + +struct Cartesian3 <: AbstractRepresentation end +struct Spherical <: AbstractRepresentation end # (r, θ, ϕ) or (r, lat, lon)—define explicitly! +struct Geodetic <: AbstractRepresentation end # (lat, lon, h) on ellipsoid