-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #78 from SasView/76-basic-outline-of-new-data-types
76 basic outline of new data types
- Loading branch information
Showing
7 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from dataclasses import dataclass | ||
from units_temp import Quantity, NamedQuantity | ||
|
||
import numpy as np | ||
|
||
from sasdata.model_requirements import ModellingRequirements | ||
|
||
|
||
|
||
|
||
@dataclass | ||
class SASData: | ||
abscissae: list[NamedQuantity[np.ndarray]] | ||
ordinate: NamedQuantity[np.ndarray] | ||
other: list[NamedQuantity[np.ndarray]] | ||
|
||
metadata: MetaData | ||
model_requirements: ModellingRequirements |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
""" Information used for providing guesses about what text based files contain """ | ||
|
||
from dataclasses import dataclass | ||
|
||
# | ||
# VERY ROUGH DRAFT - FOR PROTOTYPING PURPOSES | ||
# | ||
|
||
@dataclass | ||
class DatasetType: | ||
name: str | ||
required: list[str] | ||
optional: list[str] | ||
expected_orders: list[list[str]] | ||
|
||
|
||
one_dim = DatasetType( | ||
name="1D I vs Q", | ||
required=["Q", "I"], | ||
optional=["dI", "dQ", "shadow"], | ||
expected_orders=[ | ||
["Q", "I", "dI"], | ||
["Q", "dQ", "I", "dI"]]) | ||
|
||
two_dim = DatasetType( | ||
name="2D I vs Q", | ||
required=["Qx", "Qy", "I"], | ||
optional=["dQx", "dQy", "dI", "Qz", "shadow"], | ||
expected_orders=[ | ||
["Qx", "Qy", "I"], | ||
["Qx", "Qy", "I", "dI"], | ||
["Qx", "Qy", "dQx", "dQy", "I", "dI"]]) | ||
|
||
sesans = DatasetType( | ||
name="SESANS", | ||
required=["z", "G"], | ||
optional=["stuff", "other stuff", "more stuff"], | ||
expected_orders=[["z", "G"]]) | ||
|
||
dataset_types = {dataset.name for dataset in [one_dim, two_dim, sesans]} | ||
|
||
|
||
# | ||
# Some default units, this is not how they should be represented, some might not be correct | ||
# | ||
# The unit options should only be those compatible with the field | ||
# | ||
default_units = { | ||
"Q": "1/A", | ||
"I": "1/cm", | ||
"Qx": "1/A", | ||
"Qy": "1/A", | ||
"Qz": "1/A", | ||
"dI": "1/A", | ||
"dQ": "1/A", | ||
"dQx": "1/A", | ||
"dQy": "1/A", | ||
"dQz": "1/A", | ||
"z": "A", | ||
"G": "<none>", | ||
"shaddow": "<none>", | ||
"temperature": "K", | ||
"magnetic field": "T" | ||
} | ||
|
||
# | ||
# Other possible fields. Ultimately, these should come out of the metadata structure | ||
# | ||
|
||
metadata_fields = [ | ||
"temperature", | ||
"magnetic field", | ||
] | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
|
||
class DistributionModel: | ||
|
||
|
||
@property | ||
def is_density(self) -> bool: | ||
return False | ||
|
||
def standard_deviation(self) -> Quantity: | ||
return NotImplementedError("Variance not implemented yet") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from typing import Generic, TypeVar | ||
|
||
from numpy._typing import ArrayLike | ||
|
||
from sasdata.quantities.quantities import Unit, Quantity | ||
|
||
|
||
class RawMetaData: | ||
pass | ||
|
||
class MetaData: | ||
pass | ||
|
||
|
||
FieldDataType = TypeVar("FieldDataType") | ||
OutputDataType = TypeVar("OutputDataType") | ||
|
||
class Accessor(Generic[FieldDataType, OutputDataType]): | ||
def __init__(self, target_field: str): | ||
self._target_field = target_field | ||
|
||
def _raw_values(self) -> FieldDataType: | ||
raise NotImplementedError("not implemented in base class") | ||
|
||
@property | ||
def value(self) -> OutputDataType: | ||
raise NotImplementedError("value not implemented in base class") | ||
|
||
|
||
|
||
class QuantityAccessor(Accessor[ArrayLike, Quantity[ArrayLike]]): | ||
def __init__(self, target_field: str, units_field: str | None = None): | ||
super().__init__(target_field) | ||
self._units_field = units_field | ||
|
||
def _get_units(self) -> Unit: | ||
pass | ||
|
||
def _raw_values(self) -> ArrayLike: | ||
pass | ||
|
||
|
||
class StringAccessor(Accessor[str]): | ||
@property | ||
def value(self) -> str: | ||
return self._raw_values() | ||
|
||
|
||
class LengthAccessor(QuantityAccessor): | ||
@property | ||
def m(self): | ||
return self.value.in_units_of("m") | ||
|
||
|
||
class TimeAccessor(QuantityAccessor): | ||
pass | ||
|
||
|
||
class TemperatureAccessor(QuantityAccessor): | ||
pass | ||
|
||
|
||
class AbsoluteTemperatureAccessor(QuantityAccessor): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from dataclasses import dataclass | ||
|
||
import numpy as np | ||
|
||
from transforms.operation import Operation | ||
|
||
|
||
@dataclass | ||
class ModellingRequirements: | ||
""" Requirements that need to be passed to any modelling step """ | ||
dimensionality: int | ||
operation: Operation | ||
|
||
|
||
def from_qi_transformation(self, data: np.ndarray) -> np.ndaarray: | ||
pass | ||
|
||
|
||
|
||
|
||
def guess_requirements(abscissae, ordinate) -> ModellingRequirements: | ||
""" Use names of axes and units to guess what kind of processing needs to be done """ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
from typing import Collection, Sequence, TypeVar, Generic | ||
from dataclasses import dataclass | ||
|
||
class Dimensions: | ||
""" | ||
Note that some SI Base units are | ||
For example, moles and angular measures are dimensionless from this perspective, and candelas are | ||
""" | ||
def __init__(self, | ||
length: int = 0, | ||
time: int = 0, | ||
mass: int = 0, | ||
current: int = 0, | ||
temperature: int = 0): | ||
|
||
self.length = length | ||
self.time = time | ||
self.mass = mass | ||
self.current = current | ||
self.temperature = temperature | ||
|
||
def __mul__(self, other: "Dimensions"): | ||
|
||
if not isinstance(other, Dimensions): | ||
return NotImplemented | ||
|
||
return Dimensions( | ||
self.length + other.length, | ||
self.time + other.time, | ||
self.mass + other.mass, | ||
self.current + other.current, | ||
self.temperature + other.temperature) | ||
|
||
def __truediv__(self, other: "Dimensions"): | ||
|
||
if not isinstance(other, Dimensions): | ||
return NotImplemented | ||
|
||
return Dimensions( | ||
self.length - other.length, | ||
self.time - other.time, | ||
self.mass - other.mass, | ||
self.current - other.current, | ||
self.temperature - other.temperature) | ||
|
||
def __pow__(self, power: int): | ||
|
||
if not isinstance(power, int): | ||
return NotImplemented | ||
|
||
return Dimensions( | ||
self.length * power, | ||
self.time * power, | ||
self.mass * power, | ||
self.current * power, | ||
self.temperature * power) | ||
|
||
|
||
@dataclass | ||
class UnitName: | ||
ascii_name: str | ||
unicode_name: str | None = None | ||
|
||
@property | ||
def best_name(self): | ||
if self.unicode_name is None: | ||
return self.ascii_name | ||
else: | ||
return self.unicode_name | ||
|
||
class Unit: | ||
def __init__(self, | ||
si_scaling_factor: float, | ||
dimensions: Dimensions, | ||
name: UnitName | None = None): | ||
|
||
self.scale = si_scaling_factor | ||
self.dimensions = dimensions | ||
self.name = name | ||
|
||
def _components(self, tokens: Sequence["UnitToken"]): | ||
pass | ||
|
||
def __mul__(self, other: "Unit"): | ||
if not isinstance(other, Unit): | ||
return NotImplemented | ||
|
||
return Unit(self.scale * other.scale, self.dimensions * other.dimensions) | ||
|
||
def __truediv__(self, other: "Unit"): | ||
if not isinstance(other, Unit): | ||
return NotImplemented | ||
|
||
return Unit(self.scale / other.scale, self.dimensions / other.dimensions) | ||
|
||
def __pow__(self, power: int): | ||
if not isinstance(power, int): | ||
return NotImplemented | ||
|
||
return Unit(self.scale**power, self.dimensions**power) | ||
|
||
|
||
QuantityType = TypeVar("QuantityType") | ||
class Quantity(Generic[QuantityType]): | ||
def __init__(self, value: QuantityType, units: Unit): | ||
self.value = value | ||
self.units = units | ||
|
||
def in_units_of(self, units: Unit) -> QuantityType: | ||
pass | ||
|
||
class ExpressionMethod: | ||
pass | ||
|
||
|
||
class SetExpressionMethod(ExpressionMethod): | ||
pass | ||
|
||
|
||
class AnyExpressionMethod(ExpressionMethod): | ||
pass | ||
|
||
|
||
class ForceExpressionMethod(ExpressionMethod): | ||
pass | ||
|
||
|
||
class UnitToken: | ||
def __init__(self, unit: Collection[NamedUnit], method: ExpressionMethod): | ||
pass | ||
|
||
unit_dictionary = { | ||
"Amps": Unit(1, Dimensions(current=1), UnitName("A")), | ||
"Coulombs": Unit(1, Dimensions(current=1, time=1), UnitName("C")) | ||
} | ||
|
||
@dataclass | ||
class Disambiguator: | ||
A: Unit = unit_dictionary["Amps"] | ||
C: Unit = unit_dictionary["Coulombs"] | ||
|
||
def parse_units(unit_string: str, disambiguator: Disambiguator = Disambiguator()) -> Unit: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import numpy as np | ||
from sasdata.quantities.quantities import Quantity | ||
|
||
class Operation: | ||
""" Sketch of what model post-processing classes might look like """ | ||
|
||
children: list["Operation"] | ||
named_children: dict[str, "Operation"] | ||
|
||
@property | ||
def name(self) -> str: | ||
raise NotImplementedError("No name for transform") | ||
|
||
def evaluate(self) -> Quantity[np.ndarray]: | ||
pass | ||
|
||
def __call__(self, *children, **named_children): | ||
self.children = children | ||
self.named_children = named_children |