acorn/schema/research_activity/aspect/data.rs
1use crate::prelude::*;
2#[cfg(feature = "std")]
3use crate::schema::agent::Model;
4use crate::schema::namespaces::{codemeta, schema_org};
5use crate::util::{LinkedData, StringInterpolation, ToMarkdown};
6use bon::Builder;
7use core::str::FromStr;
8use derive_more::Display;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_repr::{Deserialize_repr, Serialize_repr};
12
13/// Description of obstacles to shared access
14///
15/// Data availability is strongly related to the concept of "openness" and the "presumed open principle" for data.
16///
17/// Where openness is characterized as open, public, shared, or closed, availability takes a more direct approach to
18/// describing the actual availability of data, which may be open but still unavailable due to other factors
19/// (e.g., technical barriers, legal barriers, etc.).
20#[derive(Clone, Debug, Default, Deserialize_repr, Display, Serialize_repr, PartialEq, PartialOrd, JsonSchema)]
21#[repr(u8)]
22#[serde(deny_unknown_fields)]
23pub enum Availability {
24 /// Data is not available by any means
25 #[default]
26 Unavailable = 0,
27 /// Data is available but access is restricted (partial availability)
28 Restricted = 1,
29 /// Data is available and access is unrestricted (open source)
30 Unrestricted = 2,
31}
32/// Describe the data that a system can process, use, and depend on
33///
34/// The attribute of data that designates "real" vs "synthetic" is intended to capture the ***origin*** of the data, which can have implications for its quality, reliability, and applicability to different tasks.
35#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
36pub enum Data {
37 /// Data that has been collected from natural events
38 Real(DataDescription),
39 /// Data that has been artificially created by computer algorithms
40 Synthetic(DataDescription),
41 /// Opaque data artifact
42 #[cfg(feature = "std")]
43 Model(Box<Model>),
44}
45/// Framework for assessing the readiness of a data set
46///
47/// Adapted from the concept of "data readiness levels" as described by N. Lawrence in [Data Readiness Levels](http://arxiv.org/abs/1705.02245).
48#[derive(Clone, Debug, Deserialize, Display, Serialize, JsonSchema)]
49pub enum DataReadinessLevel {
50 /// Bottom of Band C. Hearsay data — existence is not yet verified. Signs include statements such
51 /// as "The sales department should have a record of that." Problems may include whether the data
52 /// is actually being recorded, the format in which it is recorded, privacy or legal constraints,
53 /// and topology limitations (e.g., data distributed across many devices).
54 #[display("Level E: Hearsay")]
55 E,
56 /// Top of Band C. Data is machine readable and ethical procedures for data handling have been
57 /// addressed. It is ready to be loaded into analysis software or made available via a data
58 /// repository. Reaching D often requires significant bespoke software and human understanding
59 /// of systems, ethics, and the law.
60 #[display("Level D: Accessible")]
61 D,
62 /// Beginning of Band C. Data is accessible and loaded into analysis software but its faithfulness
63 /// and representation have not yet been characterized. Missing values, noise, data entry errors,
64 /// unit correctness, and collection bias have not been assessed.
65 #[display("Level C: Loaded")]
66 C,
67 /// End of Band B. The analyst understands how faithful the data is to its original description.
68 /// A broad idea of limitations in the data is present and an intuition about what may really be
69 /// possible with the data set is beginning to form. Getting to this point is often the most
70 /// expensive part of a data project.
71 #[display("Level B: Faithful")]
72 B,
73 /// Data in context. The data set has been assessed as appropriate for a specific task or question.
74 /// Any remedial steps have been taken and the data is ready to be deployed in the given context.
75 /// A data set may be A1 for one question but only B1 for a different question; the task definition
76 /// is an important pre-requisite for this band.
77 #[display("Level A: Appropriate")]
78 A,
79}
80/// Levels adapted from NASA Earth Observing System Data and Information System ([EOSDIS]) data processing levels,
81/// which are intended to describe the level of processing that has been applied to a given data set.
82/// These levels are widely used in the Earth science community and provide a useful framework for understanding the maturity and usability of data products.
83///
84/// See <https://www.earthdata.nasa.gov/learn/earth-observation-data-basics/data-processing-levels> for more information.
85///
86/// [EOSDIS]: https://www.earthdata.nasa.gov/about/esdis/eosdis
87#[derive(Clone, Debug, Deserialize, Display, Serialize, JsonSchema)]
88pub enum GeospatialDataProcessingLevel {
89 /// Reconstructed, unprocessed ("raw") instrument and payload data at full resolution,
90 /// with any and all communications artifacts (e.g., synchronization frames,
91 /// communications headers, duplicate data) removed.
92 #[display("Level 0: Raw")]
93 L0,
94 /// Level 1A (L1A) data are reconstructed, unprocessed instrument data at full
95 /// resolution, time-referenced, and annotated with ancillary information.
96 /// This ancillary information can include radiometric and geometric calibration
97 /// coefficients and georeferencing parameters (e.g., platform ephemeris).
98 #[display("Level 1A: Annotated")]
99 L1A,
100 /// L1B data are L1A data that have been processed to instrument units
101 /// (not all instruments have L1B source data).
102 #[display("Level 1B: Processed Annotated")]
103 L1B,
104 /// L1C data are L1B data that include new variables to describe the spectra.
105 /// These variables allow the user to identify which L1C channels have been
106 /// copied directly from the L1B and which have been synthesized from L1B and why.
107 #[display("Level 1C: Spectral Variables")]
108 L1C,
109 /// Derived geophysical variables at the same resolution and location as
110 /// L1 source data.
111 #[display("Level 2: Derived Geophysical")]
112 L2,
113 /// L2A data contains information derived from the geolocated instrument data,
114 /// such as ground elevation, highest and lowest surface return elevations,
115 /// energy quantile heights ("relative height" metrics), and other
116 /// waveform-derived metrics describing the intercepted surface.
117 #[display("Level 2A: Derived Surface")]
118 L2A,
119 /// L2B data are L2A data that have been processed to instrument units
120 /// (not all instruments will have a L2B equivalent).
121 #[display("Level 2B: Processed Derived Surface")]
122 L2B,
123 /// Variables mapped on uniform space-time grid scales, usually with some
124 /// completeness and consistency.
125 #[display("Level 3: Gridded")]
126 L3,
127 /// L3A data are generally periodic summaries (weekly, 10-day, monthly)
128 /// of L2 products.
129 #[display("Level 3A: Periodic Summaries")]
130 L3A,
131 /// Model output or results from analyses of lower-level data
132 /// (e.g., variables derived from multiple measurements).
133 #[display("Level 4: Model Output")]
134 L4,
135}
136/// Specific type or form of data that a system can process and learn from
137#[derive(Clone, Debug, Default, Display, Deserialize, Serialize, JsonSchema)]
138#[serde(rename_all = "lowercase")]
139pub enum Modality {
140 /// Textual data that includes text and tabular data
141 #[default]
142 #[display("text")]
143 Text,
144 /// Audio data such as MPEG
145 #[display("audio")]
146 Audio,
147 /// Video data such as MP4
148 #[display("video")]
149 Video,
150 /// Signal data
151 #[display("signal")]
152 Signal,
153 /// Graph data or generally data with relational structure
154 #[display("graph")]
155 Graph,
156 /// Image data such as PNG, JPEG
157 #[display("image")]
158 Image,
159 /// PDF document data
160 #[display("pdf")]
161 Pdf,
162}
163/// Framework for partitioning data by quality using metaphor of mined metals
164#[derive(Clone, Debug, Display, Deserialize, Serialize, JsonSchema)]
165pub enum Quality {
166 /// Raw and unprocessed
167 Raw = 0,
168 /// Ingested
169 Bronze = 1,
170 /// Processed in some form short of being "AI ready" (e.g., large scale consumption)
171 Silver = 2,
172 /// AI-ready
173 Gold = 3,
174 /// AI-ready data that is adapted to a specific application and/or subjected to additional processing
175 Platinum = 4,
176}
177/// Common attributes of data
178#[derive(Builder, Clone, Debug, Deserialize, Serialize, JsonSchema)]
179#[builder(start_fn = init)]
180pub struct DataDescription {
181 /// Linked data (e.g., JSON-LD) context for data description
182 #[serde(rename = "@context")]
183 pub context: Option<DataDescriptionContext>,
184 /// Linked data (e.g., JSON-LD) type for data description
185 #[serde(rename = "@type")]
186 pub description_type: Option<String>,
187 /// Replaces ADEPT concept of "openness"
188 pub availability: Option<Availability>,
189 /// License that governs use of data
190 // TODO: validate with is_license
191 pub license: Option<String>,
192 /// Modality of data
193 pub modality: Option<Modality>,
194 /// Quality of data
195 pub quality: Option<Quality>,
196}
197/// Linked data (e.g., JSON-LD) context for data description
198#[derive(Builder, Clone, Debug, Deserialize, Serialize, JsonSchema)]
199#[builder(start_fn = init, on(String, into))]
200pub struct DataDescriptionContext {
201 pub(crate) availability: String,
202 pub(crate) license: String,
203 pub(crate) modality: String,
204 pub(crate) quality: String,
205}
206impl Default for DataDescription {
207 fn default() -> Self {
208 DataDescription::init().build()
209 }
210}
211impl Default for DataDescriptionContext {
212 fn default() -> Self {
213 DataDescriptionContext::init()
214 .availability(schema_org("DefinedTerm"))
215 .license(codemeta("softwareVersion"))
216 .modality(schema_org("DefinedTerm"))
217 .quality(schema_org("DefinedTerm"))
218 .build()
219 }
220}
221impl ToMarkdown for Data {
222 fn to_markdown(&self) -> String {
223 match self {
224 | Self::Real(description) => format!("- Real{}", description.to_markdown()),
225 | Self::Synthetic(description) => format!("- Synthetic{}", description.to_markdown()),
226 #[cfg(feature = "std")]
227 | Self::Model(model) => match model.as_ref() {
228 | Model::SLM(details) => format!("- Model\n - Kind: SLM\n{}", details.to_markdown().with_indent(2)),
229 | Model::LLM(details) => format!("- Model\n - Kind: LLM\n{}", details.to_markdown().with_indent(2)),
230 },
231 }
232 }
233}
234impl ToMarkdown for DataDescription {
235 fn to_markdown(&self) -> String {
236 let lines = [
237 self.availability.as_ref().map(|value| format!("Availability: {value}")),
238 self.license.as_ref().map(|value| format!("License: {value}")),
239 self.modality.as_ref().map(|value| format!("Modality: {value}")),
240 self.quality.as_ref().map(|value| format!("Quality: {}", value)),
241 ]
242 .into_iter()
243 .flatten()
244 .collect::<Vec<_>>();
245 if lines.is_empty() {
246 String::new()
247 } else {
248 format!("\n{}", lines.to_markdown().trim_start().with_indent(2))
249 }
250 }
251}
252impl LinkedData for DataDescription {
253 fn with_context(&self) -> Self {
254 Self {
255 context: Some(DataDescriptionContext::default()),
256 description_type: None,
257 ..self.clone()
258 }
259 }
260}
261impl FromStr for GeospatialDataProcessingLevel {
262 type Err = String;
263
264 fn from_str(value: &str) -> Result<Self, Self::Err> {
265 match value {
266 | "LV0" | "L0" | "0" => Ok(Self::L0),
267 | "LV1A" | "L1A" | "1A" => Ok(Self::L1A),
268 | "LV1B" | "L1B" | "1B" => Ok(Self::L1B),
269 | "LV1C" | "L1C" | "1C" => Ok(Self::L1C),
270 | "LV2" | "L2" | "2" => Ok(Self::L2),
271 | "LV2A" | "L2A" | "2A" => Ok(Self::L2A),
272 | "LV2B" | "L2B" | "2B" => Ok(Self::L2B),
273 | "LV3" | "L3" | "3" => Ok(Self::L3),
274 | "LV3A" | "L3A" | "3A" => Ok(Self::L3A),
275 | "LV4" | "L4" | "4" => Ok(Self::L4),
276 | _ => Err(format!("unknown GeospatialDataProcessingLevel: {value}")),
277 }
278 }
279}