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
3 changes: 2 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[deps]
Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
SpaceDataModel = "0b37b92c-f0c5-4a52-bd5c-390dec20857c"
SpaceDataModel = "0b37b92c-f0c5-4a52-bd5c-390dec20857c"
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ makedocs(
pages = [
"Home" => "index.md",
"Interface" => "interface.md",
"Coordinate Systems" => "coordinate.md",
"API" => "api.md",
],
checkdocs = :exports,
Expand Down
81 changes: 81 additions & 0 deletions docs/src/coordinate.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- - A **Coordinate Transformation** is a mapping between different coordinate systems. -->

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
56 changes: 1 addition & 55 deletions docs/src/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
4 changes: 4 additions & 0 deletions src/SpaceDataModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
3 changes: 1 addition & 2 deletions src/coord.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Base: String


"""
AbstractCoordinateSystem

Expand All @@ -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()`.
Expand Down
19 changes: 19 additions & 0 deletions src/coordinates/reference_frame.jl
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions src/coordinates/representation.jl
Original file line number Diff line number Diff line change
@@ -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
Loading