diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1ca7029..940cb04 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - python-version: ['3.10', '3.11', '3.12'] + python-version: ['3.12'] fail-fast: false steps: diff --git a/requirements.txt b/requirements.txt index 0eb2649..389c900 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ lxml # Calculation numpy==1.* +scipy # Unit testing pytest @@ -11,3 +12,6 @@ unittest-xml-reporting # Documentation sphinx + +# Other stuff +matplotlib diff --git a/sasdata/checklist.txt b/sasdata/checklist.txt new file mode 100644 index 0000000..c25c7d8 --- /dev/null +++ b/sasdata/checklist.txt @@ -0,0 +1,3 @@ +Things to check once everything is in place: + +1) Do any centigrade fields read in incorrectly? \ No newline at end of file diff --git a/sasdata/data.py b/sasdata/data.py new file mode 100644 index 0000000..544ba27 --- /dev/null +++ b/sasdata/data.py @@ -0,0 +1,45 @@ +from enum import Enum +from typing import TypeVar, Any, Self +from dataclasses import dataclass + +import numpy as np + +from quantities.quantity import NamedQuantity +from sasdata.metadata import Metadata +from sasdata.quantities.accessors import AccessorTarget +from sasdata.data_backing import Group, key_tree + + +class SasData: + def __init__(self, name: str, + data_contents: list[NamedQuantity], + raw_metadata: Group, + verbose: bool=False): + + self.name = name + self._data_contents = data_contents + self._raw_metadata = raw_metadata + self._verbose = verbose + + self.metadata = Metadata(AccessorTarget(raw_metadata, verbose=verbose)) + + # Components that need to be organised after creation + self.ordinate: NamedQuantity[np.ndarray] = None # TODO: fill out + self.abscissae: list[NamedQuantity[np.ndarray]] = None # TODO: fill out + self.mask = None # TODO: fill out + self.model_requirements = None # TODO: fill out + + def summary(self, indent = " ", include_raw=False): + s = f"{self.name}\n" + + for data in self._data_contents: + s += f"{indent}{data}\n" + + s += f"Metadata:\n" + s += "\n" + s += self.metadata.summary() + + if include_raw: + s += key_tree(self._raw_metadata) + + return s \ No newline at end of file diff --git a/sasdata/data_backing.py b/sasdata/data_backing.py new file mode 100644 index 0000000..564f466 --- /dev/null +++ b/sasdata/data_backing.py @@ -0,0 +1,126 @@ +from typing import TypeVar, Self +from dataclasses import dataclass +from enum import Enum + +from sasdata.quantities.quantity import NamedQuantity + +DataType = TypeVar("DataType") + +""" Sasdata metadata tree """ + +def shorten_string(string): + lines = string.split("\n") + if len(lines) <= 1: + return string + else: + return lines[0][:30] + " ... " + lines[-1][-30:] + +@dataclass +class Dataset[DataType]: + name: str + data: DataType + attributes: dict[str, Self | str] + + def summary(self, indent_amount: int = 0, indent: str = " ") -> str: + + s = f"{indent*indent_amount}{self.name.split("/")[-1]}:\n" + s += f"{indent*(indent_amount+1)}{shorten_string(str(self.data))}\n" + for key in self.attributes: + value = self.attributes[key] + if isinstance(value, (Group, Dataset)): + value_string = value.summary(indent_amount+1, indent) + else: + value_string = f"{indent * (indent_amount+1)}{key}: {shorten_string(repr(value))}\n" + + s += value_string + + return s + +@dataclass +class Group: + name: str + children: dict[str, Self | Dataset] + + def summary(self, indent_amount: int=0, indent=" "): + s = f"{indent*indent_amount}{self.name.split("/")[-1]}:\n" + for key in self.children: + s += self.children[key].summary(indent_amount+1, indent) + + return s + +class Function: + """ Representation of a (data driven) function, such as I vs Q """ + + def __init__(self, abscissae: list[NamedQuantity], ordinate: NamedQuantity): + self.abscissae = abscissae + self.ordinate = ordinate + + +class FunctionType(Enum): + """ What kind of function is this, should not be relied upon to be perfectly descriptive + + The functions might be parametrised by more variables than the specification + """ + UNKNOWN = 0 + SCATTERING_INTENSITY_VS_Q = 1 + SCATTERING_INTENSITY_VS_Q_2D = 2 + SCATTERING_INTENSITY_VS_Q_3D = 3 + SCATTERING_INTENSITY_VS_ANGLE = 4 + UNKNOWN_METADATA = 20 + TRANSMISSION = 21 + POLARISATION_EFFICIENCY = 22 + UNKNOWN_REALSPACE = 30 + SESANS = 31 + CORRELATION_FUNCTION_1D = 32 + CORRELATION_FUNCTION_2D = 33 + CORRELATION_FUNCTION_3D = 34 + INTERFACE_DISTRIBUTION_FUNCTION = 35 + PROBABILITY_DISTRIBUTION = 40 + PROBABILITY_DENSITY = 41 + +def function_type_identification_key(names): + """ Create a key from the names of data objects that can be used to assign a function type""" + return ":".join([s.lower() for s in sorted(names)]) + +function_fields_to_type = [ + (["Q"], "I", FunctionType.SCATTERING_INTENSITY_VS_Q), + (["Qx", "Qy"], "I", FunctionType.SCATTERING_INTENSITY_VS_Q_2D), + (["Qx", "Qy", "Qz"], "I", FunctionType.SCATTERING_INTENSITY_VS_Q_3D), + (["Z"], "G", FunctionType.SESANS), + (["lambda"], "T", FunctionType.TRANSMISSION) +] + +function_fields_lookup = { + function_type_identification_key(inputs + [output]): function_type for inputs, output, function_type in function_fields_to_type +} + +def build_main_data(data: list[NamedQuantity]) -> Function: + names = [datum.name for datum in data] + identifier = function_type_identification_key(names) + + if identifier in function_fields_lookup: + function_type = function_fields_lookup[identifier] + else: + function_type = FunctionType.UNKNOWN + + match function_type: + case FunctionType.UNKNOWN: + pass + case _: + raise NotImplementedError("Unknown ") + +def key_tree(data: Group | Dataset, indent_amount=0, indent: str = " ") -> str: + """ Show a metadata tree, showing the names of they keys used to access them""" + s = "" + if isinstance(data, Group): + for key in data.children: + s += indent*indent_amount + key + "\n" + s += key_tree(data.children[key], indent_amount=indent_amount+1, indent=indent) + + if isinstance(data, Dataset): + s += indent*indent_amount + "[data]\n" + for key in data.attributes: + s += indent*indent_amount + key + "\n" + s += key_tree(data.attributes[key], indent_amount=indent_amount+1, indent=indent) + + return s \ No newline at end of file diff --git a/sasdata/dataset_types.py b/sasdata/dataset_types.py new file mode 100644 index 0000000..71c0530 --- /dev/null +++ b/sasdata/dataset_types.py @@ -0,0 +1,79 @@ +""" Information used for providing guesses about what text based files contain """ + +from dataclasses import dataclass + +import sasdata.quantities.units as units + +# +# 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 +# + +unit_kinds = { + "Q": units.inverse_length, + "I": units.inverse_length, + "Qx": units.inverse_length, + "Qy": units.inverse_length, + "Qz": units.inverse_length, + "dI": units.inverse_length, + "dQ": units.inverse_length, + "dQx": units.inverse_length, + "dQy": units.inverse_length, + "dQz": units.inverse_length, + "z": units.length, + "G": units.area, + "shadow": units.dimensionless, + "temperature": units.temperature, + "magnetic field": units.magnetic_flux_density +} + +# +# Other possible fields. Ultimately, these should come out of the metadata structure +# + +metadata_fields = [ + "temperature", + "magnetic field", +] + + + diff --git a/sasdata/distributions.py b/sasdata/distributions.py new file mode 100644 index 0000000..6ad149e --- /dev/null +++ b/sasdata/distributions.py @@ -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") diff --git a/sasdata/manual_tests/__init__.py b/sasdata/manual_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/manual_tests/interpolation.py b/sasdata/manual_tests/interpolation.py new file mode 100644 index 0000000..c46078b --- /dev/null +++ b/sasdata/manual_tests/interpolation.py @@ -0,0 +1,44 @@ +import numpy as np +import matplotlib.pyplot as plt + +from sasdata.quantities.quantity import NamedQuantity +from sasdata.quantities.plotting import quantity_plot +from sasdata.quantities import units + +from sasdata.transforms.rebinning import calculate_interpolation_matrix_1d +from sasdata.transforms.rebinning import InterpolationOptions + +def linear_interpolation_check(): + + for from_bins in [(-10, 10, 10), + (-10, 10, 1000), + (-15, 5, 10), + (15,5, 10)]: + for to_bins in [ + (-15, 0, 10), + (-15, 15, 10), + (0, 20, 100)]: + + plt.figure() + + x = NamedQuantity("x", np.linspace(*from_bins), units=units.meters) + y = x**2 + + quantity_plot(x, y) + + new_x = NamedQuantity("x_new", np.linspace(*to_bins), units=units.meters) + + rebin_mat = calculate_interpolation_matrix_1d(x, new_x, order=InterpolationOptions.LINEAR) + + new_y = y @ rebin_mat + + quantity_plot(new_x, new_y) + + print(new_y.history.summary()) + + plt.show() + + + + +linear_interpolation_check() \ No newline at end of file diff --git a/sasdata/metadata.py b/sasdata/metadata.py new file mode 100644 index 0000000..3c29f33 --- /dev/null +++ b/sasdata/metadata.py @@ -0,0 +1,404 @@ +from tokenize import String + +import numpy as np +from numpy.typing import ArrayLike + +import sasdata.quantities.units as units +from quantities.absolute_temperature import AbsoluteTemperatureAccessor +from sasdata.quantities.accessors import StringAccessor, LengthAccessor, AngleAccessor, QuantityAccessor, \ + DimensionlessAccessor, FloatAccessor, TemperatureAccessor, AccessorTarget + + +class Detector: + """ + Detector information + """ + + def __init__(self, target_object: AccessorTarget): + + # Name of the instrument [string] + self.name = StringAccessor(target_object, "name") + + # Sample to detector distance [float] [mm] + self.distance = LengthAccessor[float](target_object, + "distance", + "distance.units", + default_unit=units.millimeters) + + # Offset of this detector position in X, Y, + # (and Z if necessary) [Vector] [mm] + self.offset = LengthAccessor[ArrayLike](target_object, + "offset", + "offset.units", + default_unit=units.millimeters) + + self.orientation = AngleAccessor[ArrayLike](target_object, + "orientation", + "orientation.units", + default_unit=units.degrees) + + self.beam_center = LengthAccessor[ArrayLike](target_object, + "beam_center", + "beam_center.units", + default_unit=units.millimeters) + + # Pixel size in X, Y, (and Z if necessary) [Vector] [mm] + self.pixel_size = LengthAccessor[ArrayLike](target_object, + "pixel_size", + "pixel_size.units", + default_unit=units.millimeters) + + # Slit length of the instrument for this detector.[float] [mm] + self.slit_length = LengthAccessor[float](target_object, + "slit_length", + "slit_length.units", + default_unit=units.millimeters) + + def summary(self): + return (f"Detector:\n" + f" Name: {self.name.value}\n" + f" Distance: {self.distance.value}\n" + f" Offset: {self.offset.value}\n" + f" Orientation: {self.orientation.value}\n" + f" Beam center: {self.beam_center.value}\n" + f" Pixel size: {self.pixel_size.value}\n" + f" Slit length: {self.slit_length.value}\n") + + +class Aperture: + + def __init__(self, target_object: AccessorTarget): + + # Name + self.name = StringAccessor(target_object, "name") + + # Type + self.type = StringAccessor(target_object, "type") + + # Size name - TODO: What is the name of a size + self.size_name = StringAccessor(target_object, "size_name") + + # Aperture size [Vector] # TODO: Wat!?! + self.size = QuantityAccessor[ArrayLike](target_object, + "size", + "size.units", + default_unit=units.millimeters) + + # Aperture distance [float] + self.distance = LengthAccessor[float](target_object, + "distance", + "distance.units", + default_unit=units.millimeters) + + + def summary(self): + return (f"Aperture:\n" + f" Name: {self.name.value}\n" + f" Aperture size: {self.size.value}\n" + f" Aperture distance: {self.distance.value}\n") + +class Collimation: + """ + Class to hold collimation information + """ + + def __init__(self, target_object: AccessorTarget): + + # Name + self.name = StringAccessor(target_object, "name") + # Length [float] [mm] + self.length = LengthAccessor[float](target_object, + "length", + "length.units", + default_unit=units.millimeters) + + + # Todo - how do we handle this + # self.collimator = Collimation(target_object) + + def summary(self): + + #TODO collimation stuff + return ( + f"Collimation:\n" + f" Length: {self.length.value}\n") + + + +class Source: + """ + Class to hold source information + """ + + def __init__(self, target_object: AccessorTarget): + # Name + self.name = StringAccessor(target_object, "name") + + # Generic radiation type (Type and probe give more specific info) [string] + self.radiation = StringAccessor(target_object, "radiation") + + # Type and probe are only written to by the NXcanSAS reader + # Specific radiation type (Synchotron X-ray, Reactor neutron, etc) [string] + self.type = StringAccessor(target_object, "type") + + # Radiation probe (generic probe such as neutron, x-ray, muon, etc) [string] + self.probe_particle = StringAccessor(target_object, "probe") + + # Beam size name + self.beam_size_name = StringAccessor(target_object, "beam_size_name") + + # Beam size [Vector] [mm] + self.beam_size = LengthAccessor[ArrayLike](target_object, + "beam_size", + "beam_size.units", + default_unit=units.millimeters) + + # Beam shape [string] + self.beam_shape = StringAccessor(target_object, "beam_shape") + + # Wavelength [float] [Angstrom] + self.wavelength = LengthAccessor[float](target_object, + "wavelength", + "wavelength.units", + default_unit=units.angstroms) + + # Minimum wavelength [float] [Angstrom] + self.wavelength_min = LengthAccessor[float](target_object, + "wavelength_min", + "wavelength_min.units", + default_unit=units.angstroms) + + # Maximum wavelength [float] [Angstrom] + self.wavelength_max = LengthAccessor[float](target_object, + "wavelength_min", + "wavelength_max.units", + default_unit=units.angstroms) + + # Wavelength spread [float] [Angstrom] + # Quantity because it might have other units, such as percent + self.wavelength_spread = QuantityAccessor[float](target_object, + "wavelength_spread", + "wavelength_spread.units", + default_unit=units.angstroms) + + def summary(self) -> str: + + if self.radiation.value is None and self.type.value and self.probe_particle.value: + radiation = f"{self.type.value} {self.probe_particle.value}" + else: + radiation = f"{self.radiation.value}" + + return (f"Source:\n" + f" Radiation: {radiation}\n" + f" Shape: {self.beam_shape.value}\n" + f" Wavelength: {self.wavelength.value}\n" + f" Min. Wavelength: {self.wavelength_min.value}\n" + f" Max. Wavelength: {self.wavelength_max.value}\n" + f" Wavelength Spread: {self.wavelength_spread.value}\n" + f" Beam Size: {self.beam_size.value}\n") + + + +""" +Definitions of radiation types +""" +NEUTRON = 'neutron' +XRAY = 'x-ray' +MUON = 'muon' +ELECTRON = 'electron' + + +class Sample: + """ + Class to hold the sample description + """ + def __init__(self, target_object: AccessorTarget): + + # Short name for sample + self.name = StringAccessor(target_object, "name") + # ID + + self.sample_id = StringAccessor(target_object, "id") + + # Thickness [float] [mm] + self.thickness = LengthAccessor(target_object, + "thickness", + "thickness.units", + default_unit=units.millimeters) + + # Transmission [float] [fraction] + self.transmission = FloatAccessor(target_object,"transmission") + + # Temperature [float] [No Default] + self.temperature = AbsoluteTemperatureAccessor(target_object, + "temperature", + "temperature.unit", + default_unit=units.kelvin) + # Position [Vector] [mm] + self.position = LengthAccessor[ArrayLike](target_object, + "position", + "position.unit", + default_unit=units.millimeters) + + # Orientation [Vector] [degrees] + self.orientation = AngleAccessor[ArrayLike](target_object, + "orientation", + "orientation.unit", + default_unit=units.degrees) + + # Details + self.details = StringAccessor(target_object, "details") + + + # SESANS zacceptance + zacceptance = (0,"") + yacceptance = (0,"") + + def summary(self) -> str: + return (f"Sample:\n" + f" ID: {self.sample_id.value}\n" + f" Transmission: {self.transmission.value}\n" + f" Thickness: {self.thickness.value}\n" + f" Temperature: {self.temperature.value}\n" + f" Position: {self.position.value}\n" + f" Orientation: {self.orientation.value}\n") + # + # _str += " Details:\n" + # for item in self.details: + # _str += " %s\n" % item + # + # return _str + + +class Process: + """ + Class that holds information about the processes + performed on the data. + """ + def __init__(self, target_object: AccessorTarget): + self.name = StringAccessor(target_object, "name") + self.date = StringAccessor(target_object, "date") + self.description = StringAccessor(target_object, "description") + + #TODO: It seems like these might be lists of strings, this should be checked + + self.term = StringAccessor(target_object, "term") + self.notes = StringAccessor(target_object, "notes") + + def single_line_desc(self): + """ + Return a single line string representing the process + """ + return f"{self.name.value} {self.date.value} {self.description.value}" + + def summary(self): + return (f"Process:\n" + f" Name: {self.name.value}\n" + f" Date: {self.date.value}\n" + f" Description: {self.description.value}\n" + f" Term: {self.term.value}\n" + f" Notes: {self.notes.value}\n" + ) + +class TransmissionSpectrum: + """ + Class that holds information about transmission spectrum + for white beams and spallation sources. + """ + def __init__(self, target_object: AccessorTarget): + # TODO: Needs to be multiple instances + self.name = StringAccessor(target_object, "name") + self.timestamp = StringAccessor(target_object, "timestamp") + + # Wavelength (float) [A] + self.wavelength = LengthAccessor[ArrayLike](target_object, + "wavelength", + "wavelength.units") + + # Transmission (float) [unit less] + self.transmission = DimensionlessAccessor[ArrayLike](target_object, + "transmission", + "units", + default_unit=units.none) + + # Transmission Deviation (float) [unit less] + self.transmission_deviation = DimensionlessAccessor[ArrayLike](target_object, + "transmission_deviation", + "transmission_deviation.units", + default_unit=units.none) + + + def summary(self) -> str: + return (f"Transmission Spectrum:\n" + f" Name: {self.name.value}\n" + f" Timestamp: {self.timestamp.value}\n" + f" Wavelengths: {self.wavelength.value}\n" + f" Transmission: {self.transmission.value}\n") + + +class Instrument: + def __init__(self, target: AccessorTarget): + self.aperture = Aperture(target.with_path_prefix("sasaperture|aperture")) + self.collimation = Collimation(target.with_path_prefix("sascollimation|collimation")) + self.detector = Detector(target.with_path_prefix("sasdetector|detector")) + self.source = Source(target.with_path_prefix("sassource|source")) + + def summary(self): + return ( + self.aperture.summary() + + self.collimation.summary() + + self.detector.summary() + + self.source.summary()) + +def decode_string(data): + """ This is some crazy stuff""" + + if isinstance(data, str): + return data + + elif isinstance(data, np.ndarray): + + if data.dtype == object: + + data = data.reshape(-1) + data = data[0] + + if isinstance(data, bytes): + return data.decode("utf-8") + + return str(data) + + else: + return data.tobytes().decode("utf-8") + + else: + return str(data) + +class Metadata: + def __init__(self, target: AccessorTarget): + self._target = target + + self.instrument = Instrument(target.with_path_prefix("sasinstrument|instrument")) + self.process = Process(target.with_path_prefix("sasprocess|process")) + self.sample = Sample(target.with_path_prefix("sassample|sample")) + self.transmission_spectrum = TransmissionSpectrum(target.with_path_prefix("sastransmission_spectrum|transmission_spectrum")) + + self._title = StringAccessor(target, "title") + self._run = StringAccessor(target, "run") + self._definition = StringAccessor(target, "definition") + + self.title: str = decode_string(self._title.value) + self.run: str = decode_string(self._run.value) + self.definition: str = decode_string(self._definition.value) + + def summary(self): + return ( + f" {self.title}, Run: {self.run}\n" + + " " + "="*len(self.title) + + "=======" + + "="*len(self.run) + "\n\n" + + f"Definition: {self.title}\n" + + self.process.summary() + + self.sample.summary() + + self.instrument.summary() + + self.transmission_spectrum.summary()) \ No newline at end of file diff --git a/sasdata/model_requirements.py b/sasdata/model_requirements.py new file mode 100644 index 0000000..12ad545 --- /dev/null +++ b/sasdata/model_requirements.py @@ -0,0 +1,23 @@ +from dataclasses import dataclass + +import numpy as np + +from sasdata.metadata import Metadata +from sasdata.quantities.quantity 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, metadata: Metadata) -> np.ndarray: + """ Transformation for going from qi to this data""" + pass + + + + +def guess_requirements(abscissae, ordinate) -> ModellingRequirements: + """ Use names of axes and units to guess what kind of processing needs to be done """ \ No newline at end of file diff --git a/sasdata/postprocess.py b/sasdata/postprocess.py new file mode 100644 index 0000000..82ce614 --- /dev/null +++ b/sasdata/postprocess.py @@ -0,0 +1,16 @@ +""" + +Post processing for loaded files + +""" + +def fix_mantid_units_error(data: SasData) -> SasData: + pass + + + +def apply_fixes(data: SasData, mantid_unit_error=True): + if mantid_unit_error: + data = fix_mantid_units_error(data) + + return data diff --git a/sasdata/quantities/__init__.py b/sasdata/quantities/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/quantities/_accessor_base.py b/sasdata/quantities/_accessor_base.py new file mode 100644 index 0000000..b56ecce --- /dev/null +++ b/sasdata/quantities/_accessor_base.py @@ -0,0 +1,153 @@ +from typing import TypeVar, Sequence + +from sasdata.quantities.quantity import Quantity +import sasdata.quantities.units as units +from sasdata.quantities.units import Dimensions, Unit +from sasdata.quantities.unit_parser import parse_unit, parse_unit_from_group + +from sasdata.data_backing import Group, Dataset + +import logging +# logger = logging.getLogger("Accessors") +class LoggerDummy: + def info(self, data): + print(data) +logger = LoggerDummy() + +DataType = TypeVar("DataType") +OutputType = TypeVar("OutputType") + + +class AccessorTarget: + def __init__(self, data: Group, verbose=False, prefix_tokens: tuple=()): + self._data = data + self.verbose = verbose + + self.prefix_tokens = list(prefix_tokens) + + def with_path_prefix(self, path_prexix: str): + """ Get an accessor that looks at a subtree of the metadata with the supplied prefix + + For example, accessors aiming at a.b, when the target it c.d will look at c.d.a.b + """ + return AccessorTarget(self._data, + verbose=self.verbose, + prefix_tokens=tuple(self.prefix_tokens + [path_prexix])) + + def get_value(self, path: str): + + tokens = self.prefix_tokens + path.split(".") + + if self.verbose: + logger.info(f"Finding: {path}") + logger.info(f"Full path: {tokens}") + + # Navigate the tree from the entry we need + + current_tree_position: Group | Dataset = self._data + + for token in tokens: + + options = token.split("|") + + if isinstance(current_tree_position, Group): + + found = False + for option in options: + if option in current_tree_position.children: + current_tree_position = current_tree_position.children[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on group {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.children])) + return None + + elif isinstance(current_tree_position, Dataset): + + found = False + for option in options: + if option in current_tree_position.attributes: + current_tree_position = current_tree_position.attributes[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on attribute {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.attributes])) + return None + + if self.verbose: + logger.info(f"Found value: {current_tree_position}") + + return current_tree_position.data + + + +class Accessor[DataType, OutputType]: + """ Base class """ + def __init__(self, target_object: AccessorTarget, value_target: str): + self.target_object = target_object + self.value_target = value_target + + @property + def value(self) -> OutputType | None: + return self.target_object.get_value(self.value_target) + +class StringAccessor(Accessor[str, str]): + """ String based fields """ + @property + def value(self) -> str | None: + return self.target_object.get_value(self.value_target) + +class FloatAccessor(Accessor[float, float]): + """ Float based fields """ + @property + def value(self) -> float | None: + return self.target_object.get_value(self.value_target) + + + + +class QuantityAccessor[DataType](Accessor[DataType, Quantity[DataType]]): + """ Base class for accessors that work with quantities that have units """ + def __init__(self, target_object: AccessorTarget, value_target: str, unit_target: str, default_unit=units.none): + super().__init__(target_object, value_target) + self._unit_target = unit_target + self.default_unit = default_unit + + def _numerical_part(self) -> DataType | None: + """ Numerical part of the data """ + return self.target_object.get_value(self.value_target) + + def _unit_part(self) -> str | None: + """ String form of units for the data """ + return self.target_object.get_value(self._unit_target) + + @property + def unit(self) -> Unit: + u = self._unit_part() + if u is None: + return self.default_unit + else: + return parse_unit(u) + + @property + def value(self) -> Quantity[DataType] | None: + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + @property + def quantity(self): + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + diff --git a/sasdata/quantities/_autogen_warning.py b/sasdata/quantities/_autogen_warning.py new file mode 100644 index 0000000..5adb4b5 --- /dev/null +++ b/sasdata/quantities/_autogen_warning.py @@ -0,0 +1,79 @@ +warning_text = """ + +This file is autogenerated! + +Do not edit by hand, instead edit the files that build it (%s) + + + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + + + +""" \ No newline at end of file diff --git a/sasdata/quantities/_build_tables.py b/sasdata/quantities/_build_tables.py new file mode 100644 index 0000000..3861195 --- /dev/null +++ b/sasdata/quantities/_build_tables.py @@ -0,0 +1,431 @@ +""" +Builds a data file containing details of units +""" + +import numpy as np +from collections import defaultdict +from _units_base import Dimensions, Unit +from _autogen_warning import warning_text + +bigger_magnitudes = [ + ("E", None, "exa", 1e18), + ("P", None, "peta", 1e15), + ("T", None, "tera", 1e12), + ("G", None, "giga", 1e9), + ("M", None, "mega", 1e6), + ("k", None, "kilo", 1e3) ] + +smaller_magnitudes = [ + ("m", None, "milli", 1e-3), + ("u", "µ", "micro", 1e-6), + ("n", None, "nano", 1e-9), + ("p", None, "pico", 1e-12), + ("f", None, "femto", 1e-15), + ("a", None, "atto", 1e-18)] + +unusual_magnitudes = [ + ("d", None, "deci", 1e-1), + ("c", None, "centi", 1e-2) +] + +all_magnitudes = bigger_magnitudes + smaller_magnitudes + +# Length, time, mass, current, temperature +base_si_units = [ + ("m", None, "meter", "meters", 1, 1, 0, 0, 0, 0, 0, 0, all_magnitudes + unusual_magnitudes), + ("s", None, "second", "seconds", 1, 0, 1, 0, 0, 0, 0, 0, smaller_magnitudes), + ("g", None, "gram", "grams", 1e-3, 0, 0, 1, 0, 0, 0, 0, all_magnitudes), + ("A", None, "ampere", "amperes", 1, 0, 0, 0, 1, 0, 0, 0, all_magnitudes), + ("K", None, "kelvin", "kelvin", 1, 0, 0, 0, 0, 1, 0, 0, all_magnitudes) ] + +derived_si_units = [ + ("Hz", None, "hertz", "hertz", 1, 0, -1, 0, 0, 0, 0, 0, all_magnitudes), + ("N", None, "newton", "newtons", 1, 1, -2, 1, 0, 0, 0, 0, all_magnitudes), + ("Pa", None, "pascal", "pascals", 1, -1, -2, 1, 0, 0, 0, 0, all_magnitudes), + ("J", None, "joule", "joules", 1, 2, -2, 1, 0, 0, 0, 0, all_magnitudes), + ("W", None, "watt", "watts", 1, 2, -3, 1, 0, 0, 0, 0, all_magnitudes), + ("C", None, "coulomb", "coulombs", 1, 0, 1, 0, 1, 0, 0, 0, all_magnitudes), + ("V", None, "volts", "volts", 1, 2, -3, 1, -1, 0, 0, 0, all_magnitudes), + ("Ohm", "Ω", "ohm", "ohms", 1, 2, -3, 1, -2, 0, 0, 0, all_magnitudes), + ("F", None, "farad", "farads", 1, -2, 4, -1, 2, 0, 0, 0, all_magnitudes), + ("S", None, "siemens", "siemens", 1, -2, 3, -1, 2, 0, 0, 0, all_magnitudes), + ("Wb", None, "weber", "webers", 1, 2, -2, 1, -1, 0, 0, 0, all_magnitudes), + ("T", None, "tesla", "tesla", 1, 0, -2, 1, -1, 0, 0, 0, all_magnitudes), + ("H", None, "henry", "henry", 1, 2, -2, 1, -2, 0, 0, 0, all_magnitudes), +] + +non_si_dimensioned_units: list[tuple[str, str | None, str, str, float, int, int, int, int, int, int, int, list]] = [ + ("Ang", "Å", "angstrom", "angstroms", 1e-10, 1, 0, 0, 0, 0, 0, 0, []), + ("min", None, "minute", "minutes", 60, 0, 1, 0, 0, 0, 0, 0, []), + ("h", None, "hour", "hours", 360, 0, 1, 0, 0, 0, 0, 0, []), + ("d", None, "day", "days", 360*24, 0, 1, 0, 0, 0, 0, 0, []), + ("y", None, "year", "years", 360*24*365.2425, 0, 1, 0, 0, 0, 0, 0, []), + ("deg", None, "degree", "degrees", 180/np.pi, 0, 0, 0, 0, 0, 0, 1, []), + ("rad", None, "radian", "radians", 1, 0, 0, 0, 0, 0, 0, 1, []), + ("sr", None, "stradian", "stradians", 1, 0, 0, 0, 0, 0, 0, 2, []), + ("l", None, "litre", "litres", 1e-3, 3, 0, 0, 0, 0, 0, 0, []), + ("eV", None, "electronvolt", "electronvolts", 1.602176634e-19, 2, -2, 1, 0, 0, 0, 0, all_magnitudes), + ("au", None, "atomic mass unit", "atomic mass units", 1.660538921e-27, 0, 0, 1, 0, 0, 0, 0, []), + ("mol", None, "mole", "moles", 6.02214076e23, 0, 0, 0, 0, 0, 1, 0, smaller_magnitudes), + ("kgForce", None, "kg force", "kg force", 9.80665, 1, -2, 1, 0, 0, 0, 0, []), + ("C", None, "degree Celsius", "degrees Celsius", 1, 0, 0, 0, 0, 1, 0, 0, []), + ("miles", None, "mile", "miles", 1760*3*0.3048, 1, 0, 0, 0, 0, 0, 0, []), + ("yrd", None, "yard", "yards", 3*0.3048, 1, 0, 0, 0, 0, 0, 0, []), + ("ft", None, "foot", "feet", 0.3048, 1, 0, 0, 0, 0, 0, 0, []), + ("in", None, "inch", "inches", 0.0254, 1, 0, 0, 0, 0, 0, 0, []), + ("lb", None, "pound", "pounds", 0.45359237, 0, 0, 1, 0, 0, 0, 0, []), + ("lbf", None, "pound force", "pounds force", 4.448222, 1, -2, 1, 0, 0, 0, 0, []), + ("oz", None, "ounce", "ounces", 0.45359237/16, 0, 0, 1, 0, 0, 0, 0, []), + ("psi", None, "pound force per square inch", "pounds force per square inch", 4.448222/(0.0254**2), -1, -2, 1, 0, 0, 0, 0, []), +] + +non_si_dimensionless_units: list[tuple[str, str | None, str, str, float, int, int, int, int, int, int, int, list]] = [ + ("none", None, "none", "none", 1, 0, 0, 0, 0, 0, 0, 0, []), + ("percent", "%", "percent", "percent", 0.01, 0, 0, 0, 0, 0, 0, 0, []) +] + +non_si_units = non_si_dimensioned_units + non_si_dimensionless_units + +# TODO: +# Add Hartree? Rydberg? Bohrs? +# Add CGS + +# Two stages of aliases, to make sure units don't get lost + +aliases_1 = { + "A": ["Amps", "amps"], + "C": ["Coulombs", "coulombs"] +} + +aliases_2 = { + "y": ["yr", "year"], + "d": ["day"], + "h": ["hr", "hour"], + "Ang": ["A", "Å"], + "au": ["amu"], + "percent": ["%"], + "deg": ["degr", "Deg", "degrees", "Degrees"], + "none": ["Counts", "counts", "cnts", "Cnts", "a.u.", "fraction", "Fraction"], + "K": ["C"] # Ugh, cansas +} + + + +all_units = base_si_units + derived_si_units + non_si_units + +encoding = "utf-8" + +def format_name(name: str): + return name.lower().replace(" ", "_") + +with open("units.py", 'w', encoding=encoding) as fid: + + # Write warning header + fid.write('"""'+(warning_text%"_build_tables.py, _units_base.py")+'"""') + + # Write in class definitions + fid.write("\n\n" + "#\n" + "# Included from _units_base.py\n" + "#\n\n") + + with open("_units_base.py", 'r') as base: + for line in base: + fid.write(line) + + # Write in unit definitions + fid.write("\n\n" + "#\n" + "# Specific units \n" + "#\n\n") + + symbol_lookup = {} + unit_types_temp = defaultdict(list) # Keep track of unit types + unit_types = defaultdict(list) + + for unit_def in all_units: + + try: + symbol, special_symbol, singular, plural, scale, length, time, \ + mass, current, temperature, moles_hint, angle_hint, magnitudes = unit_def + except Exception as e: + print(unit_def) + raise e + + formatted_plural = format_name(plural) + formatted_singular = format_name(singular) + + dimensions = Dimensions(length, time, mass, current, temperature, moles_hint, angle_hint) + fid.write(f"{formatted_plural} = NamedUnit({scale}, Dimensions({length}, {time}, {mass}, {current}, {temperature}, {moles_hint}, {angle_hint})," + f"name='{formatted_plural}'," + f"ascii_symbol='{symbol}'," + f"symbol='{symbol if special_symbol is None else special_symbol}')\n") + + symbol_lookup[symbol] = formatted_plural + if special_symbol is not None: + symbol_lookup[special_symbol] = formatted_plural + + unit_types_temp[hash(dimensions)].append( + (symbol, special_symbol, formatted_singular, formatted_plural, scale, dimensions)) + + unit_types[hash(dimensions)].append(formatted_plural) + + for mag_symbol, mag_special_symbol, name, mag_scale in magnitudes: + + # Work out the combined symbol, accounts for unicode or not + combined_special_symbol = (mag_symbol if mag_special_symbol is None else mag_special_symbol) + \ + (symbol if special_symbol is None else special_symbol) + + combined_symbol = mag_symbol + symbol + + # Combined unit name + combined_name_singular = f"{name}{formatted_singular}" + combined_name_plural = f"{name}{formatted_plural}" + + combined_scale = scale * mag_scale + + # Units + dimensions = Dimensions(length, time, mass, current, temperature, moles_hint, angle_hint) + fid.write(f"{combined_name_plural} = NamedUnit({combined_scale}, " + f"Dimensions({length}, {time}, {mass}, {current}, {temperature}, {moles_hint}, {angle_hint})," + f"name='{combined_name_plural}'," + f"ascii_symbol='{combined_symbol}'," + f"symbol='{combined_special_symbol}')\n") + + symbol_lookup[combined_symbol] = combined_name_plural + symbol_lookup[combined_special_symbol] = combined_name_plural + + unit_types_temp[hash(dimensions)].append( + (combined_symbol, combined_special_symbol, combined_name_singular, + combined_name_plural, combined_scale, dimensions)) + + unit_types[hash(dimensions)].append(combined_name_plural) + + # + # Higher dimensioned types + # + + length_units = unit_types_temp[hash(Dimensions(length=1))] + time_units = unit_types_temp[hash(Dimensions(time=1))] + mass_units = unit_types_temp[hash(Dimensions(mass=1))] + amount_units = unit_types_temp[hash(Dimensions(moles_hint=1))] + + # Length based + for symbol, special_symbol, singular, plural, scale, _ in length_units: + for prefix, power, name, unicode_suffix in [ + ("square_", 2, plural, '²'), + ("cubic_", 3, plural, '³'), + ("per_", -1, singular, '⁻¹'), + ("per_square_", -2, singular,'⁻²'), + ("per_cubic_", -3, singular,'⁻³')]: + + dimensions = Dimensions(length=power) + unit_name = prefix + name + unit_special_symbol = (symbol if special_symbol is None else special_symbol) + unicode_suffix + unit_symbol = symbol + f"^{power}" + fid.write(f"{unit_name} = NamedUnit({scale**power}, Dimensions(length={power}), " + f"name='{unit_name}', " + f"ascii_symbol='{unit_symbol}', " + f"symbol='{unit_special_symbol}')\n") + + unit_types[hash(dimensions)].append(unit_name) + + # Speed and acceleration + for length_symbol, length_special_symbol, _, length_name, length_scale, _ in length_units: + for time_symbol, time_special_symbol, time_name, _, time_scale, _ in time_units: + speed_name = length_name + "_per_" + time_name + accel_name = length_name + "_per_square_" + time_name + + speed_dimensions = Dimensions(length=1, time=-1) + accel_dimensions = Dimensions(length=1, time=-2) + + length_special = length_special_symbol if length_special_symbol is not None else length_symbol + time_special = time_special_symbol if time_special_symbol is not None else time_symbol + + fid.write(f"{speed_name} " + f"= NamedUnit({length_scale / time_scale}, " + f"Dimensions(length=1, time=-1), " + f"name='{speed_name}', " + f"ascii_symbol='{length_symbol}/{time_symbol}', " + f"symbol='{length_special}{time_special}⁻¹')\n") + + fid.write(f"{accel_name} = NamedUnit({length_scale / time_scale**2}, " + f"Dimensions(length=1, time=-2), " + f"name='{accel_name}', " + f"ascii_symbol='{length_symbol}/{time_symbol}^2', " + f"symbol='{length_special}{time_special}⁻²')\n") + + unit_types[hash(speed_dimensions)].append(speed_name) + unit_types[hash(accel_dimensions)].append(accel_name) + + # Density + for length_symbol, length_special_symbol, length_name, _, length_scale, _ in length_units: + for mass_symbol, mass_special_symbol, _, mass_name, mass_scale, _ in mass_units: + + name = mass_name + "_per_cubic_" + length_name + + dimensions = Dimensions(length=-3, mass=1) + + mass_special = mass_symbol if mass_special_symbol is None else mass_special_symbol + length_special = length_symbol if length_special_symbol is None else length_special_symbol + + fid.write(f"{name} " + f"= NamedUnit({mass_scale / length_scale**3}, " + f"Dimensions(length=-3, mass=1), " + f"name='{name}', " + f"ascii_symbol='{mass_symbol} {length_symbol}^-3', " + f"symbol='{mass_special}{length_special}⁻³')\n") + + unit_types[hash(dimensions)].append(name) + + # Concentration + for length_symbol, length_special_symbol, length_name, _, length_scale, _ in length_units: + for amount_symbol, amount_special_symbol, _, amount_name, amount_scale, _ in amount_units: + + name = amount_name + "_per_cubic_" + length_name + + dimensions = Dimensions(length=-3, moles_hint=1) + + length_special = length_symbol if length_special_symbol is None else length_special_symbol + amount_special = amount_symbol if amount_special_symbol is None else amount_special_symbol + + fid.write(f"{name} " + f"= NamedUnit({amount_scale / length_scale**3}, " + f"Dimensions(length=-3, moles_hint=1), " + f"name='{name}', " + f"ascii_symbol='{amount_symbol} {length_symbol}^-3', " + f"symbol='{amount_special}{length_special}⁻³')\n") + + unit_types[hash(dimensions)].append(name) + + # TODO: Torque, Momentum, Entropy + + # + # Add aliases to symbol lookup table + # + + # Apply the alias transforms sequentially + for aliases in [aliases_1, aliases_2]: + for base_name in aliases: + alias_list = aliases[base_name] + for alias in alias_list: + symbol_lookup[alias] = symbol_lookup[base_name] + + # + # Write out the symbol lookup table + # + fid.write("\n#\n# Lookup table from symbols to units\n#\n\n") + fid.write("symbol_lookup = {\n") + for k in symbol_lookup: + if k != "none": + fid.write(f' "{k}": {symbol_lookup[k]},\n') + fid.write("}\n\n") + + # + # Collections of units by type + # + + dimension_names = [ + ("length", Dimensions(length=1)), + ("area", Dimensions(length=2)), + ("volume", Dimensions(length=3)), + ("inverse_length", Dimensions(length=-1)), + ("inverse_area", Dimensions(length=-2)), + ("inverse_volume", Dimensions(length=-3)), + ("time", Dimensions(time=1)), + ("rate", Dimensions(time=-1)), + ("speed", Dimensions(length=1, time=-1)), + ("acceleration", Dimensions(length=1, time=-2)), + ("density", Dimensions(length=-3, mass=1)), + ("force", Dimensions(1, -2, 1, 0, 0)), + ("pressure", Dimensions(-1, -2, 1, 0, 0)), + ("energy", Dimensions(2, -2, 1, 0, 0)), + ("power", Dimensions(2, -3, 1, 0, 0)), + ("charge", Dimensions(0, 1, 0, 1, 0)), + ("potential", Dimensions(2, -3, 1, -1, 0)), + ("resistance", Dimensions(2, -3, 1, -2, 0)), + ("capacitance", Dimensions(-2, 4, -1, 2, 0)), + ("conductance", Dimensions(-2, 3, -1, 2, 0)), + ("magnetic_flux", Dimensions(2, -2, 1, -1, 0)), + ("magnetic_flux_density", Dimensions(0, -2, 1, -1, 0)), + ("inductance", Dimensions(2, -2, 1, -2, 0)), + ("temperature", Dimensions(temperature=1)), + ("dimensionless", Dimensions()), + ("angle", Dimensions(angle_hint=1)), + ("solid_angle", Dimensions(angle_hint=2)), + ("amount", Dimensions(moles_hint=1)), + ("concentration", Dimensions(length=-3, moles_hint=1)), + ] + + fid.write("\n#\n# Units by type \n#\n\n") + + for dimension_name, dimensions in dimension_names: + + + fid.write(f"\n" + f"{dimension_name} = UnitGroup(\n" + f" name = '{dimension_name}', \n" + f" units = [\n") + + for unit_name in unit_types[hash(dimensions)]: + fid.write(" " + unit_name + ",\n") + + fid.write("])\n") + + + # List of dimensions + fid.write("\n\n") + fid.write("unit_group_names = [\n") + for dimension_name, _ in dimension_names: + fid.write(f" '{dimension_name}',\n") + fid.write("]\n\n") + + fid.write("unit_groups = {\n") + for dimension_name, _ in dimension_names: + fid.write(f" '{dimension_name}': {dimension_name},\n") + fid.write("}\n\n") + + +with open("accessors.py", 'w', encoding=encoding) as fid: + + + fid.write('"""'+(warning_text%"_build_tables.py, _accessor_base.py")+'"""\n\n') + + with open("_accessor_base.py", 'r') as base: + for line in base: + fid.write(line) + + for dimension_name, dimensions in dimension_names: + + accessor_name = dimension_name.capitalize().replace("_", "") + "Accessor" + + fid.write(f"\n" + f"class {accessor_name}[T](QuantityAccessor[T]):\n" + f" dimension_name = '{dimension_name}'\n" + f" \n") + + for unit_name in unit_types[hash(dimensions)]: + fid.write(f" @property\n" + f" def {unit_name}(self) -> T:\n" + f" quantity = self.quantity\n" + f" if quantity is None:\n" + f" return None\n" + f" else:\n" + f" return quantity.in_units_of(units.{unit_name})\n" + f"\n") + + fid.write("\n") + +with open("si.py", 'w') as fid: + + fid.write('"""'+(warning_text%"_build_tables.py")+'"""\n\n') + si_unit_names = [values[3] for values in base_si_units + derived_si_units if values[3] != "grams"] + ["kilograms"] + + for name in si_unit_names: + + fid.write(f"from sasdata.quantities.units import {name}\n") + + fid.write("\nall_si = [\n") + for name in si_unit_names: + fid.write(f" {name},\n") + fid.write("]\n") \ No newline at end of file diff --git a/sasdata/quantities/_units_base.py b/sasdata/quantities/_units_base.py new file mode 100644 index 0000000..5a990ea --- /dev/null +++ b/sasdata/quantities/_units_base.py @@ -0,0 +1,341 @@ +from dataclasses import dataclass +from typing import Sequence, Self, TypeVar +from fractions import Fraction + +import numpy as np + +from sasdata.quantities.unicode_superscript import int_as_unicode_superscript + +class DimensionError(Exception): + pass + +class Dimensions: + """ + + Note that some SI Base units are not useful from the perspecive of the sasview project, and make things + behave badly. In particular: moles and angular measures are dimensionless, and candelas are really a weighted + measure of power. + + We do however track angle and amount, because its really useful for formatting units + + """ + def __init__(self, + length: int = 0, + time: int = 0, + mass: int = 0, + current: int = 0, + temperature: int = 0, + moles_hint: int = 0, + angle_hint: int = 0): + + self.length = length + self.time = time + self.mass = mass + self.current = current + self.temperature = temperature + self.moles_hint = moles_hint + self.angle_hint = angle_hint + + @property + def is_dimensionless(self): + """ Is this dimension dimensionless (ignores moles_hint and angle_hint) """ + return self.length == 0 and self.time == 0 and self.mass == 0 and self.current == 0 and self.temperature == 0 + + def __mul__(self: Self, other: Self): + + 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, + self.moles_hint + other.moles_hint, + self.angle_hint + other.angle_hint) + + def __truediv__(self: Self, other: Self): + + 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, + self.moles_hint - other.moles_hint, + self.angle_hint - other.angle_hint) + + def __pow__(self, power: int | float): + + if not isinstance(power, (int, float)): + return NotImplemented + + frac = Fraction(power).limit_denominator(500) # Probably way bigger than needed, 10 would probably be fine + denominator = frac.denominator + numerator = frac.numerator + + # Throw errors if dimension is not a multiple of the denominator + + if self.length % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with length dimensionality {self.length}") + + if self.time % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with time dimensionality {self.time}") + + if self.mass % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with mass dimensionality {self.mass}") + + if self.current % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with current dimensionality {self.current}") + + if self.temperature % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with temperature dimensionality {self.temperature}") + + if self.moles_hint % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with moles hint dimensionality of {self.moles_hint}") + + if self.angle_hint % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with angle hint dimensionality of {self.angle_hint}") + + return Dimensions( + (self.length * numerator) // denominator, + (self.time * numerator) // denominator, + (self.mass * numerator) // denominator, + (self.current * numerator) // denominator, + (self.temperature * numerator) // denominator, + (self.moles_hint * numerator) // denominator, + (self.angle_hint * numerator) // denominator) + + def __eq__(self: Self, other: Self): + if isinstance(other, Dimensions): + return (self.length == other.length and + self.time == other.time and + self.mass == other.mass and + self.current == other.current and + self.temperature == other.temperature and + self.moles_hint == other.moles_hint and + self.angle_hint == other.angle_hint) + + return NotImplemented + + def __hash__(self): + """ Unique representation of units using Godel like encoding""" + + two_powers = 0 + if self.length < 0: + two_powers += 1 + + if self.time < 0: + two_powers += 2 + + if self.mass < 0: + two_powers += 4 + + if self.current < 0: + two_powers += 8 + + if self.temperature < 0: + two_powers += 16 + + if self.moles_hint < 0: + two_powers += 32 + + if self.angle_hint < 0: + two_powers += 64 + + return 2**two_powers * 3**abs(self.length) * 5**abs(self.time) * \ + 7**abs(self.mass) * 11**abs(self.current) * 13**abs(self.temperature) * \ + 17**abs(self.moles_hint) * 19**abs(self.angle_hint) + + def __repr__(self): + tokens = [] + for name, size in [ + ("length", self.length), + ("time", self.time), + ("mass", self.mass), + ("current", self.current), + ("temperature", self.temperature), + ("amount", self.moles_hint), + ("angle", self.angle_hint)]: + + if size == 0: + pass + elif size == 1: + tokens.append(f"{name}") + else: + tokens.append(f"{name}{int_as_unicode_superscript(size)}") + + return ' '.join(tokens) + + def si_repr(self): + tokens = [] + for name, size in [ + ("kg", self.mass), + ("m", self.length), + ("s", self.time), + ("A", self.current), + ("K", self.temperature), + ("mol", self.moles_hint)]: + + if size == 0: + pass + elif size == 1: + tokens.append(f"{name}") + else: + tokens.append(f"{name}{int_as_unicode_superscript(size)}") + + match self.angle_hint: + case 0: + pass + case 2: + tokens.append("sr") + case -2: + tokens.append("sr" + int_as_unicode_superscript(-1)) + case _: + tokens.append("rad" + int_as_unicode_superscript(self.angle_hint)) + + return ''.join(tokens) + + +class Unit: + def __init__(self, + si_scaling_factor: float, + dimensions: Dimensions): + + self.scale = si_scaling_factor + self.dimensions = dimensions + + def _components(self, tokens: Sequence["UnitToken"]): + pass + + def __mul__(self: Self, other: "Unit"): + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale * other.scale, self.dimensions * other.dimensions) + + def __truediv__(self: Self, other: "Unit"): + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale / other.scale, self.dimensions / other.dimensions) + + def __rtruediv__(self: Self, other: "Unit"): + if isinstance(other, Unit): + return Unit(other.scale / self.scale, other.dimensions / self.dimensions) + elif isinstance(other, (int, float)): + return Unit(other / self.scale, self.dimensions ** -1) + else: + return NotImplemented + + def __pow__(self, power: int | float): + if not isinstance(power, int | float): + return NotImplemented + + return Unit(self.scale**power, self.dimensions**power) + + + def equivalent(self: Self, other: "Unit"): + return self.dimensions == other.dimensions + + def __eq__(self: Self, other: "Unit"): + return self.equivalent(other) and np.abs(np.log(self.scale/other.scale)) < 1e-5 + + def si_equivalent(self): + """ Get the SI unit corresponding to this unit""" + return Unit(1, self.dimensions) + + def _format_unit(self, format_process: list["UnitFormatProcessor"]): + for processor in format_process: + pass + + def __repr__(self): + if self.scale == 1: + # We're in SI + return self.dimensions.si_repr() + + else: + return f"Unit[{self.scale}, {self.dimensions}]" + + @staticmethod + def parse(unit_string: str) -> "Unit": + pass + +class NamedUnit(Unit): + """ Units, but they have a name, and a symbol + + :si_scaling_factor: Number of these units per SI equivalent + :param dimensions: Dimensions object representing the dimensionality of these units + :param name: Name of unit - string without unicode + :param ascii_symbol: Symbol for unit without unicode + :param symbol: Unicode symbol + """ + def __init__(self, + si_scaling_factor: float, + dimensions: Dimensions, + name: str | None = None, + ascii_symbol: str | None = None, + symbol: str | None = None): + + super().__init__(si_scaling_factor, dimensions) + self.name = name + self.ascii_symbol = ascii_symbol + self.symbol = symbol + + def __repr__(self): + return self.name + +# +# Parsing plan: +# Require unknown amounts of units to be explicitly positive or negative? +# +# + + + +@dataclass +class ProcessedUnitToken: + """ Mid processing representation of formatted units """ + base_string: str + exponent_string: str + latex_exponent_string: str + exponent: int + +class UnitFormatProcessor: + """ Represents a step in the unit processing pipeline""" + def apply(self, scale, dimensions) -> tuple[ProcessedUnitToken, float, Dimensions]: + """ This will be called to deal with each processing stage""" + +class RequiredUnitFormatProcessor(UnitFormatProcessor): + """ This unit is required to exist in the formatting """ + def __init__(self, unit: Unit, power: int = 1): + self.unit = unit + self.power = power + def apply(self, scale, dimensions) -> tuple[float, Dimensions, ProcessedUnitToken]: + new_scale = scale / (self.unit.scale * self.power) + new_dimensions = self.unit.dimensions / (dimensions**self.power) + token = ProcessedUnitToken(self.unit, self.power) + + return new_scale, new_dimensions, token +class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): + """ This processor minimises the dimensionality of the unit by multiplying by as many + units of the specified type as needed """ + def __init__(self, unit: Unit): + self.unit = unit + + def apply(self, scale, dimensions) -> tuple[ProcessedUnitToken, float, Dimensions]: + pass + +class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): + pass + +class UnitGroup: + """ A group of units that all have the same dimensionality """ + def __init__(self, name: str, units: list[NamedUnit]): + self.name = name + self.units = sorted(units, key=lambda unit: unit.scale) + diff --git a/sasdata/quantities/absolute_temperature.py b/sasdata/quantities/absolute_temperature.py new file mode 100644 index 0000000..95c8982 --- /dev/null +++ b/sasdata/quantities/absolute_temperature.py @@ -0,0 +1,15 @@ +from typing import TypeVar + +from quantities.quantity import Quantity +from sasdata.quantities.accessors import TemperatureAccessor + + +DataType = TypeVar("DataType") +class AbsoluteTemperatureAccessor(TemperatureAccessor[DataType]): + """ Parsing for absolute temperatures """ + @property + def value(self) -> Quantity[DataType] | None: + if self._numerical_part() is None: + return None + else: + return Quantity.parse(self._numerical_part(), self._unit_part(), absolute_temperature=True) diff --git a/sasdata/quantities/accessors.py b/sasdata/quantities/accessors.py new file mode 100644 index 0000000..2f1f251 --- /dev/null +++ b/sasdata/quantities/accessors.py @@ -0,0 +1,10322 @@ +""" + +This file is autogenerated! + +Do not edit by hand, instead edit the files that build it (_build_tables.py, _accessor_base.py) + + + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + + + +""" + +from typing import TypeVar, Sequence + +from sasdata.quantities.quantity import Quantity +import sasdata.quantities.units as units +from sasdata.quantities.units import Dimensions, Unit +from sasdata.quantities.unit_parser import parse_unit, parse_unit_from_group + +from sasdata.data_backing import Group, Dataset + +import logging +# logger = logging.getLogger("Accessors") +class LoggerDummy: + def info(self, data): + print(data) +logger = LoggerDummy() + +DataType = TypeVar("DataType") +OutputType = TypeVar("OutputType") + + +class AccessorTarget: + def __init__(self, data: Group, verbose=False, prefix_tokens: tuple=()): + self._data = data + self.verbose = verbose + + self.prefix_tokens = list(prefix_tokens) + + def with_path_prefix(self, path_prexix: str): + """ Get an accessor that looks at a subtree of the metadata with the supplied prefix + + For example, accessors aiming at a.b, when the target it c.d will look at c.d.a.b + """ + return AccessorTarget(self._data, + verbose=self.verbose, + prefix_tokens=tuple(self.prefix_tokens + [path_prexix])) + + def get_value(self, path: str): + + tokens = self.prefix_tokens + path.split(".") + + if self.verbose: + logger.info(f"Finding: {path}") + logger.info(f"Full path: {tokens}") + + # Navigate the tree from the entry we need + + current_tree_position: Group | Dataset = self._data + + for token in tokens: + + options = token.split("|") + + if isinstance(current_tree_position, Group): + + found = False + for option in options: + if option in current_tree_position.children: + current_tree_position = current_tree_position.children[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on group {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.children])) + return None + + elif isinstance(current_tree_position, Dataset): + + found = False + for option in options: + if option in current_tree_position.attributes: + current_tree_position = current_tree_position.attributes[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on attribute {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.attributes])) + return None + + if self.verbose: + logger.info(f"Found value: {current_tree_position}") + + return current_tree_position.data + + + +class Accessor[DataType, OutputType]: + """ Base class """ + def __init__(self, target_object: AccessorTarget, value_target: str): + self.target_object = target_object + self.value_target = value_target + + @property + def value(self) -> OutputType | None: + return self.target_object.get_value(self.value_target) + +class StringAccessor(Accessor[str, str]): + """ String based fields """ + @property + def value(self) -> str | None: + return self.target_object.get_value(self.value_target) + +class FloatAccessor(Accessor[float, float]): + """ Float based fields """ + @property + def value(self) -> float | None: + return self.target_object.get_value(self.value_target) + + + + +class QuantityAccessor[DataType](Accessor[DataType, Quantity[DataType]]): + """ Base class for accessors that work with quantities that have units """ + def __init__(self, target_object: AccessorTarget, value_target: str, unit_target: str, default_unit=units.none): + super().__init__(target_object, value_target) + self._unit_target = unit_target + self.default_unit = default_unit + + def _numerical_part(self) -> DataType | None: + """ Numerical part of the data """ + return self.target_object.get_value(self.value_target) + + def _unit_part(self) -> str | None: + """ String form of units for the data """ + return self.target_object.get_value(self._unit_target) + + @property + def unit(self) -> Unit: + u = self._unit_part() + if u is None: + return self.default_unit + else: + return parse_unit(u) + + @property + def value(self) -> Quantity[DataType] | None: + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + @property + def quantity(self): + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + +class LengthAccessor[T](QuantityAccessor[T]): + dimension_name = 'length' + + @property + def meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters) + + @property + def exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters) + + @property + def petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters) + + @property + def terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters) + + @property + def gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters) + + @property + def megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters) + + @property + def kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers) + + @property + def millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters) + + @property + def micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers) + + @property + def nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers) + + @property + def picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers) + + @property + def femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers) + + @property + def attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers) + + @property + def decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters) + + @property + def centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters) + + @property + def angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms) + + @property + def miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles) + + @property + def yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards) + + @property + def feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet) + + @property + def inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches) + + + +class AreaAccessor[T](QuantityAccessor[T]): + dimension_name = 'area' + + @property + def square_meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_meters) + + @property + def square_exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_exameters) + + @property + def square_petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_petameters) + + @property + def square_terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_terameters) + + @property + def square_gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_gigameters) + + @property + def square_megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_megameters) + + @property + def square_kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_kilometers) + + @property + def square_millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_millimeters) + + @property + def square_micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_micrometers) + + @property + def square_nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_nanometers) + + @property + def square_picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_picometers) + + @property + def square_femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_femtometers) + + @property + def square_attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_attometers) + + @property + def square_decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_decimeters) + + @property + def square_centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_centimeters) + + @property + def square_angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_angstroms) + + @property + def square_miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_miles) + + @property + def square_yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_yards) + + @property + def square_feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_feet) + + @property + def square_inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_inches) + + + +class VolumeAccessor[T](QuantityAccessor[T]): + dimension_name = 'volume' + + @property + def litres(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.litres) + + @property + def cubic_meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_meters) + + @property + def cubic_exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_exameters) + + @property + def cubic_petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_petameters) + + @property + def cubic_terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_terameters) + + @property + def cubic_gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_gigameters) + + @property + def cubic_megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_megameters) + + @property + def cubic_kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_kilometers) + + @property + def cubic_millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_millimeters) + + @property + def cubic_micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_micrometers) + + @property + def cubic_nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_nanometers) + + @property + def cubic_picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_picometers) + + @property + def cubic_femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_femtometers) + + @property + def cubic_attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_attometers) + + @property + def cubic_decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_decimeters) + + @property + def cubic_centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_centimeters) + + @property + def cubic_angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_angstroms) + + @property + def cubic_miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_miles) + + @property + def cubic_yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_yards) + + @property + def cubic_feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_feet) + + @property + def cubic_inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_inches) + + + +class InverselengthAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_length' + + @property + def per_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_meter) + + @property + def per_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_exameter) + + @property + def per_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_petameter) + + @property + def per_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_terameter) + + @property + def per_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_gigameter) + + @property + def per_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_megameter) + + @property + def per_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_kilometer) + + @property + def per_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_millimeter) + + @property + def per_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_micrometer) + + @property + def per_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_nanometer) + + @property + def per_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_picometer) + + @property + def per_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_femtometer) + + @property + def per_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_attometer) + + @property + def per_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_decimeter) + + @property + def per_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_centimeter) + + @property + def per_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_angstrom) + + @property + def per_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_mile) + + @property + def per_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_yard) + + @property + def per_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_foot) + + @property + def per_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_inch) + + + +class InverseareaAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_area' + + @property + def per_square_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_meter) + + @property + def per_square_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_exameter) + + @property + def per_square_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_petameter) + + @property + def per_square_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_terameter) + + @property + def per_square_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_gigameter) + + @property + def per_square_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_megameter) + + @property + def per_square_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_kilometer) + + @property + def per_square_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_millimeter) + + @property + def per_square_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_micrometer) + + @property + def per_square_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_nanometer) + + @property + def per_square_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_picometer) + + @property + def per_square_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_femtometer) + + @property + def per_square_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_attometer) + + @property + def per_square_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_decimeter) + + @property + def per_square_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_centimeter) + + @property + def per_square_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_angstrom) + + @property + def per_square_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_mile) + + @property + def per_square_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_yard) + + @property + def per_square_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_foot) + + @property + def per_square_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_inch) + + + +class InversevolumeAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_volume' + + @property + def per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_meter) + + @property + def per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_exameter) + + @property + def per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_petameter) + + @property + def per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_terameter) + + @property + def per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_gigameter) + + @property + def per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_megameter) + + @property + def per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_kilometer) + + @property + def per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_millimeter) + + @property + def per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_micrometer) + + @property + def per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_nanometer) + + @property + def per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_picometer) + + @property + def per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_femtometer) + + @property + def per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_attometer) + + @property + def per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_decimeter) + + @property + def per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_centimeter) + + @property + def per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_angstrom) + + @property + def per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_mile) + + @property + def per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_yard) + + @property + def per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_foot) + + @property + def per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_inch) + + + +class TimeAccessor[T](QuantityAccessor[T]): + dimension_name = 'time' + + @property + def seconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.seconds) + + @property + def milliseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliseconds) + + @property + def microseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microseconds) + + @property + def nanoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoseconds) + + @property + def picoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoseconds) + + @property + def femtoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoseconds) + + @property + def attoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoseconds) + + @property + def minutes(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.minutes) + + @property + def hours(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.hours) + + @property + def days(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.days) + + @property + def years(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.years) + + + +class RateAccessor[T](QuantityAccessor[T]): + dimension_name = 'rate' + + @property + def hertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.hertz) + + @property + def exahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exahertz) + + @property + def petahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petahertz) + + @property + def terahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terahertz) + + @property + def gigahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigahertz) + + @property + def megahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megahertz) + + @property + def kilohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilohertz) + + @property + def millihertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millihertz) + + @property + def microhertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microhertz) + + @property + def nanohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanohertz) + + @property + def picohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picohertz) + + @property + def femtohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtohertz) + + @property + def attohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attohertz) + + + +class SpeedAccessor[T](QuantityAccessor[T]): + dimension_name = 'speed' + + @property + def meters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_second) + + @property + def meters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_millisecond) + + @property + def meters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_microsecond) + + @property + def meters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_nanosecond) + + @property + def meters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_picosecond) + + @property + def meters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_femtosecond) + + @property + def meters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_attosecond) + + @property + def meters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_minute) + + @property + def meters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_hour) + + @property + def meters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_day) + + @property + def meters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_year) + + @property + def exameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_second) + + @property + def exameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_millisecond) + + @property + def exameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_microsecond) + + @property + def exameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_nanosecond) + + @property + def exameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_picosecond) + + @property + def exameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_femtosecond) + + @property + def exameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_attosecond) + + @property + def exameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_minute) + + @property + def exameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_hour) + + @property + def exameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_day) + + @property + def exameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_year) + + @property + def petameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_second) + + @property + def petameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_millisecond) + + @property + def petameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_microsecond) + + @property + def petameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_nanosecond) + + @property + def petameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_picosecond) + + @property + def petameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_femtosecond) + + @property + def petameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_attosecond) + + @property + def petameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_minute) + + @property + def petameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_hour) + + @property + def petameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_day) + + @property + def petameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_year) + + @property + def terameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_second) + + @property + def terameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_millisecond) + + @property + def terameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_microsecond) + + @property + def terameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_nanosecond) + + @property + def terameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_picosecond) + + @property + def terameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_femtosecond) + + @property + def terameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_attosecond) + + @property + def terameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_minute) + + @property + def terameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_hour) + + @property + def terameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_day) + + @property + def terameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_year) + + @property + def gigameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_second) + + @property + def gigameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_millisecond) + + @property + def gigameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_microsecond) + + @property + def gigameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_nanosecond) + + @property + def gigameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_picosecond) + + @property + def gigameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_femtosecond) + + @property + def gigameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_attosecond) + + @property + def gigameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_minute) + + @property + def gigameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_hour) + + @property + def gigameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_day) + + @property + def gigameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_year) + + @property + def megameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_second) + + @property + def megameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_millisecond) + + @property + def megameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_microsecond) + + @property + def megameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_nanosecond) + + @property + def megameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_picosecond) + + @property + def megameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_femtosecond) + + @property + def megameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_attosecond) + + @property + def megameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_minute) + + @property + def megameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_hour) + + @property + def megameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_day) + + @property + def megameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_year) + + @property + def kilometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_second) + + @property + def kilometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_millisecond) + + @property + def kilometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_microsecond) + + @property + def kilometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_nanosecond) + + @property + def kilometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_picosecond) + + @property + def kilometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_femtosecond) + + @property + def kilometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_attosecond) + + @property + def kilometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_minute) + + @property + def kilometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_hour) + + @property + def kilometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_day) + + @property + def kilometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_year) + + @property + def millimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_second) + + @property + def millimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_millisecond) + + @property + def millimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_microsecond) + + @property + def millimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_nanosecond) + + @property + def millimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_picosecond) + + @property + def millimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_femtosecond) + + @property + def millimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_attosecond) + + @property + def millimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_minute) + + @property + def millimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_hour) + + @property + def millimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_day) + + @property + def millimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_year) + + @property + def micrometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_second) + + @property + def micrometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_millisecond) + + @property + def micrometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_microsecond) + + @property + def micrometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_nanosecond) + + @property + def micrometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_picosecond) + + @property + def micrometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_femtosecond) + + @property + def micrometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_attosecond) + + @property + def micrometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_minute) + + @property + def micrometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_hour) + + @property + def micrometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_day) + + @property + def micrometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_year) + + @property + def nanometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_second) + + @property + def nanometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_millisecond) + + @property + def nanometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_microsecond) + + @property + def nanometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_nanosecond) + + @property + def nanometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_picosecond) + + @property + def nanometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_femtosecond) + + @property + def nanometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_attosecond) + + @property + def nanometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_minute) + + @property + def nanometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_hour) + + @property + def nanometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_day) + + @property + def nanometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_year) + + @property + def picometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_second) + + @property + def picometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_millisecond) + + @property + def picometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_microsecond) + + @property + def picometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_nanosecond) + + @property + def picometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_picosecond) + + @property + def picometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_femtosecond) + + @property + def picometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_attosecond) + + @property + def picometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_minute) + + @property + def picometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_hour) + + @property + def picometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_day) + + @property + def picometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_year) + + @property + def femtometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_second) + + @property + def femtometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_millisecond) + + @property + def femtometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_microsecond) + + @property + def femtometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_nanosecond) + + @property + def femtometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_picosecond) + + @property + def femtometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_femtosecond) + + @property + def femtometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_attosecond) + + @property + def femtometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_minute) + + @property + def femtometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_hour) + + @property + def femtometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_day) + + @property + def femtometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_year) + + @property + def attometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_second) + + @property + def attometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_millisecond) + + @property + def attometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_microsecond) + + @property + def attometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_nanosecond) + + @property + def attometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_picosecond) + + @property + def attometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_femtosecond) + + @property + def attometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_attosecond) + + @property + def attometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_minute) + + @property + def attometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_hour) + + @property + def attometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_day) + + @property + def attometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_year) + + @property + def decimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_second) + + @property + def decimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_millisecond) + + @property + def decimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_microsecond) + + @property + def decimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_nanosecond) + + @property + def decimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_picosecond) + + @property + def decimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_femtosecond) + + @property + def decimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_attosecond) + + @property + def decimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_minute) + + @property + def decimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_hour) + + @property + def decimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_day) + + @property + def decimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_year) + + @property + def centimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_second) + + @property + def centimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_millisecond) + + @property + def centimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_microsecond) + + @property + def centimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_nanosecond) + + @property + def centimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_picosecond) + + @property + def centimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_femtosecond) + + @property + def centimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_attosecond) + + @property + def centimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_minute) + + @property + def centimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_hour) + + @property + def centimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_day) + + @property + def centimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_year) + + @property + def angstroms_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_second) + + @property + def angstroms_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_millisecond) + + @property + def angstroms_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_microsecond) + + @property + def angstroms_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_nanosecond) + + @property + def angstroms_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_picosecond) + + @property + def angstroms_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_femtosecond) + + @property + def angstroms_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_attosecond) + + @property + def angstroms_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_minute) + + @property + def angstroms_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_hour) + + @property + def angstroms_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_day) + + @property + def angstroms_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_year) + + @property + def miles_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_second) + + @property + def miles_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_millisecond) + + @property + def miles_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_microsecond) + + @property + def miles_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_nanosecond) + + @property + def miles_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_picosecond) + + @property + def miles_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_femtosecond) + + @property + def miles_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_attosecond) + + @property + def miles_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_minute) + + @property + def miles_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_hour) + + @property + def miles_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_day) + + @property + def miles_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_year) + + @property + def yards_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_second) + + @property + def yards_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_millisecond) + + @property + def yards_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_microsecond) + + @property + def yards_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_nanosecond) + + @property + def yards_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_picosecond) + + @property + def yards_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_femtosecond) + + @property + def yards_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_attosecond) + + @property + def yards_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_minute) + + @property + def yards_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_hour) + + @property + def yards_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_day) + + @property + def yards_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_year) + + @property + def feet_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_second) + + @property + def feet_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_millisecond) + + @property + def feet_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_microsecond) + + @property + def feet_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_nanosecond) + + @property + def feet_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_picosecond) + + @property + def feet_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_femtosecond) + + @property + def feet_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_attosecond) + + @property + def feet_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_minute) + + @property + def feet_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_hour) + + @property + def feet_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_day) + + @property + def feet_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_year) + + @property + def inches_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_second) + + @property + def inches_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_millisecond) + + @property + def inches_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_microsecond) + + @property + def inches_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_nanosecond) + + @property + def inches_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_picosecond) + + @property + def inches_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_femtosecond) + + @property + def inches_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_attosecond) + + @property + def inches_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_minute) + + @property + def inches_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_hour) + + @property + def inches_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_day) + + @property + def inches_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_year) + + + +class AccelerationAccessor[T](QuantityAccessor[T]): + dimension_name = 'acceleration' + + @property + def meters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_second) + + @property + def meters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_millisecond) + + @property + def meters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_microsecond) + + @property + def meters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_nanosecond) + + @property + def meters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_picosecond) + + @property + def meters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_femtosecond) + + @property + def meters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_attosecond) + + @property + def meters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_minute) + + @property + def meters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_hour) + + @property + def meters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_day) + + @property + def meters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_year) + + @property + def exameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_second) + + @property + def exameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_millisecond) + + @property + def exameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_microsecond) + + @property + def exameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_nanosecond) + + @property + def exameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_picosecond) + + @property + def exameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_femtosecond) + + @property + def exameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_attosecond) + + @property + def exameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_minute) + + @property + def exameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_hour) + + @property + def exameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_day) + + @property + def exameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_year) + + @property + def petameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_second) + + @property + def petameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_millisecond) + + @property + def petameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_microsecond) + + @property + def petameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_nanosecond) + + @property + def petameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_picosecond) + + @property + def petameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_femtosecond) + + @property + def petameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_attosecond) + + @property + def petameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_minute) + + @property + def petameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_hour) + + @property + def petameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_day) + + @property + def petameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_year) + + @property + def terameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_second) + + @property + def terameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_millisecond) + + @property + def terameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_microsecond) + + @property + def terameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_nanosecond) + + @property + def terameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_picosecond) + + @property + def terameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_femtosecond) + + @property + def terameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_attosecond) + + @property + def terameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_minute) + + @property + def terameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_hour) + + @property + def terameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_day) + + @property + def terameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_year) + + @property + def gigameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_second) + + @property + def gigameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_millisecond) + + @property + def gigameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_microsecond) + + @property + def gigameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_nanosecond) + + @property + def gigameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_picosecond) + + @property + def gigameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_femtosecond) + + @property + def gigameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_attosecond) + + @property + def gigameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_minute) + + @property + def gigameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_hour) + + @property + def gigameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_day) + + @property + def gigameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_year) + + @property + def megameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_second) + + @property + def megameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_millisecond) + + @property + def megameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_microsecond) + + @property + def megameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_nanosecond) + + @property + def megameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_picosecond) + + @property + def megameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_femtosecond) + + @property + def megameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_attosecond) + + @property + def megameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_minute) + + @property + def megameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_hour) + + @property + def megameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_day) + + @property + def megameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_year) + + @property + def kilometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_second) + + @property + def kilometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_millisecond) + + @property + def kilometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_microsecond) + + @property + def kilometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_nanosecond) + + @property + def kilometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_picosecond) + + @property + def kilometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_femtosecond) + + @property + def kilometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_attosecond) + + @property + def kilometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_minute) + + @property + def kilometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_hour) + + @property + def kilometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_day) + + @property + def kilometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_year) + + @property + def millimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_second) + + @property + def millimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_millisecond) + + @property + def millimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_microsecond) + + @property + def millimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_nanosecond) + + @property + def millimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_picosecond) + + @property + def millimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_femtosecond) + + @property + def millimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_attosecond) + + @property + def millimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_minute) + + @property + def millimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_hour) + + @property + def millimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_day) + + @property + def millimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_year) + + @property + def micrometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_second) + + @property + def micrometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_millisecond) + + @property + def micrometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_microsecond) + + @property + def micrometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_nanosecond) + + @property + def micrometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_picosecond) + + @property + def micrometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_femtosecond) + + @property + def micrometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_attosecond) + + @property + def micrometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_minute) + + @property + def micrometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_hour) + + @property + def micrometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_day) + + @property + def micrometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_year) + + @property + def nanometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_second) + + @property + def nanometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_millisecond) + + @property + def nanometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_microsecond) + + @property + def nanometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_nanosecond) + + @property + def nanometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_picosecond) + + @property + def nanometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_femtosecond) + + @property + def nanometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_attosecond) + + @property + def nanometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_minute) + + @property + def nanometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_hour) + + @property + def nanometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_day) + + @property + def nanometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_year) + + @property + def picometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_second) + + @property + def picometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_millisecond) + + @property + def picometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_microsecond) + + @property + def picometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_nanosecond) + + @property + def picometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_picosecond) + + @property + def picometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_femtosecond) + + @property + def picometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_attosecond) + + @property + def picometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_minute) + + @property + def picometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_hour) + + @property + def picometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_day) + + @property + def picometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_year) + + @property + def femtometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_second) + + @property + def femtometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_millisecond) + + @property + def femtometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_microsecond) + + @property + def femtometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_nanosecond) + + @property + def femtometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_picosecond) + + @property + def femtometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_femtosecond) + + @property + def femtometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_attosecond) + + @property + def femtometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_minute) + + @property + def femtometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_hour) + + @property + def femtometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_day) + + @property + def femtometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_year) + + @property + def attometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_second) + + @property + def attometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_millisecond) + + @property + def attometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_microsecond) + + @property + def attometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_nanosecond) + + @property + def attometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_picosecond) + + @property + def attometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_femtosecond) + + @property + def attometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_attosecond) + + @property + def attometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_minute) + + @property + def attometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_hour) + + @property + def attometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_day) + + @property + def attometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_year) + + @property + def decimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_second) + + @property + def decimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_millisecond) + + @property + def decimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_microsecond) + + @property + def decimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_nanosecond) + + @property + def decimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_picosecond) + + @property + def decimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_femtosecond) + + @property + def decimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_attosecond) + + @property + def decimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_minute) + + @property + def decimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_hour) + + @property + def decimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_day) + + @property + def decimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_year) + + @property + def centimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_second) + + @property + def centimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_millisecond) + + @property + def centimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_microsecond) + + @property + def centimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_nanosecond) + + @property + def centimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_picosecond) + + @property + def centimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_femtosecond) + + @property + def centimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_attosecond) + + @property + def centimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_minute) + + @property + def centimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_hour) + + @property + def centimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_day) + + @property + def centimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_year) + + @property + def angstroms_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_second) + + @property + def angstroms_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_millisecond) + + @property + def angstroms_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_microsecond) + + @property + def angstroms_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_nanosecond) + + @property + def angstroms_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_picosecond) + + @property + def angstroms_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_femtosecond) + + @property + def angstroms_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_attosecond) + + @property + def angstroms_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_minute) + + @property + def angstroms_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_hour) + + @property + def angstroms_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_day) + + @property + def angstroms_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_year) + + @property + def miles_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_second) + + @property + def miles_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_millisecond) + + @property + def miles_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_microsecond) + + @property + def miles_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_nanosecond) + + @property + def miles_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_picosecond) + + @property + def miles_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_femtosecond) + + @property + def miles_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_attosecond) + + @property + def miles_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_minute) + + @property + def miles_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_hour) + + @property + def miles_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_day) + + @property + def miles_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_year) + + @property + def yards_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_second) + + @property + def yards_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_millisecond) + + @property + def yards_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_microsecond) + + @property + def yards_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_nanosecond) + + @property + def yards_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_picosecond) + + @property + def yards_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_femtosecond) + + @property + def yards_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_attosecond) + + @property + def yards_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_minute) + + @property + def yards_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_hour) + + @property + def yards_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_day) + + @property + def yards_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_year) + + @property + def feet_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_second) + + @property + def feet_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_millisecond) + + @property + def feet_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_microsecond) + + @property + def feet_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_nanosecond) + + @property + def feet_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_picosecond) + + @property + def feet_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_femtosecond) + + @property + def feet_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_attosecond) + + @property + def feet_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_minute) + + @property + def feet_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_hour) + + @property + def feet_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_day) + + @property + def feet_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_year) + + @property + def inches_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_second) + + @property + def inches_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_millisecond) + + @property + def inches_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_microsecond) + + @property + def inches_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_nanosecond) + + @property + def inches_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_picosecond) + + @property + def inches_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_femtosecond) + + @property + def inches_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_attosecond) + + @property + def inches_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_minute) + + @property + def inches_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_hour) + + @property + def inches_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_day) + + @property + def inches_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_year) + + + +class DensityAccessor[T](QuantityAccessor[T]): + dimension_name = 'density' + + @property + def grams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_meter) + + @property + def exagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_meter) + + @property + def petagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_meter) + + @property + def teragrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_meter) + + @property + def gigagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_meter) + + @property + def megagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_meter) + + @property + def kilograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_meter) + + @property + def milligrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_meter) + + @property + def micrograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_meter) + + @property + def nanograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_meter) + + @property + def picograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_meter) + + @property + def femtograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_meter) + + @property + def attograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_meter) + + @property + def atomic_mass_units_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_meter) + + @property + def pounds_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_meter) + + @property + def ounces_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_meter) + + @property + def grams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_exameter) + + @property + def exagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_exameter) + + @property + def petagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_exameter) + + @property + def teragrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_exameter) + + @property + def gigagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_exameter) + + @property + def megagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_exameter) + + @property + def kilograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_exameter) + + @property + def milligrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_exameter) + + @property + def micrograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_exameter) + + @property + def nanograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_exameter) + + @property + def picograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_exameter) + + @property + def femtograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_exameter) + + @property + def attograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_exameter) + + @property + def atomic_mass_units_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_exameter) + + @property + def pounds_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_exameter) + + @property + def ounces_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_exameter) + + @property + def grams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_petameter) + + @property + def exagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_petameter) + + @property + def petagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_petameter) + + @property + def teragrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_petameter) + + @property + def gigagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_petameter) + + @property + def megagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_petameter) + + @property + def kilograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_petameter) + + @property + def milligrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_petameter) + + @property + def micrograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_petameter) + + @property + def nanograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_petameter) + + @property + def picograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_petameter) + + @property + def femtograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_petameter) + + @property + def attograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_petameter) + + @property + def atomic_mass_units_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_petameter) + + @property + def pounds_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_petameter) + + @property + def ounces_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_petameter) + + @property + def grams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_terameter) + + @property + def exagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_terameter) + + @property + def petagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_terameter) + + @property + def teragrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_terameter) + + @property + def gigagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_terameter) + + @property + def megagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_terameter) + + @property + def kilograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_terameter) + + @property + def milligrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_terameter) + + @property + def micrograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_terameter) + + @property + def nanograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_terameter) + + @property + def picograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_terameter) + + @property + def femtograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_terameter) + + @property + def attograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_terameter) + + @property + def atomic_mass_units_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_terameter) + + @property + def pounds_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_terameter) + + @property + def ounces_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_terameter) + + @property + def grams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_gigameter) + + @property + def exagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_gigameter) + + @property + def petagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_gigameter) + + @property + def teragrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_gigameter) + + @property + def gigagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_gigameter) + + @property + def megagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_gigameter) + + @property + def kilograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_gigameter) + + @property + def milligrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_gigameter) + + @property + def micrograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_gigameter) + + @property + def nanograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_gigameter) + + @property + def picograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_gigameter) + + @property + def femtograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_gigameter) + + @property + def attograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_gigameter) + + @property + def atomic_mass_units_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_gigameter) + + @property + def pounds_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_gigameter) + + @property + def ounces_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_gigameter) + + @property + def grams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_megameter) + + @property + def exagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_megameter) + + @property + def petagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_megameter) + + @property + def teragrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_megameter) + + @property + def gigagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_megameter) + + @property + def megagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_megameter) + + @property + def kilograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_megameter) + + @property + def milligrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_megameter) + + @property + def micrograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_megameter) + + @property + def nanograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_megameter) + + @property + def picograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_megameter) + + @property + def femtograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_megameter) + + @property + def attograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_megameter) + + @property + def atomic_mass_units_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_megameter) + + @property + def pounds_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_megameter) + + @property + def ounces_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_megameter) + + @property + def grams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_kilometer) + + @property + def exagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_kilometer) + + @property + def petagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_kilometer) + + @property + def teragrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_kilometer) + + @property + def gigagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_kilometer) + + @property + def megagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_kilometer) + + @property + def kilograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_kilometer) + + @property + def milligrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_kilometer) + + @property + def micrograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_kilometer) + + @property + def nanograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_kilometer) + + @property + def picograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_kilometer) + + @property + def femtograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_kilometer) + + @property + def attograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_kilometer) + + @property + def atomic_mass_units_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_kilometer) + + @property + def pounds_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_kilometer) + + @property + def ounces_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_kilometer) + + @property + def grams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_millimeter) + + @property + def exagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_millimeter) + + @property + def petagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_millimeter) + + @property + def teragrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_millimeter) + + @property + def gigagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_millimeter) + + @property + def megagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_millimeter) + + @property + def kilograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_millimeter) + + @property + def milligrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_millimeter) + + @property + def micrograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_millimeter) + + @property + def nanograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_millimeter) + + @property + def picograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_millimeter) + + @property + def femtograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_millimeter) + + @property + def attograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_millimeter) + + @property + def atomic_mass_units_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_millimeter) + + @property + def pounds_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_millimeter) + + @property + def ounces_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_millimeter) + + @property + def grams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_micrometer) + + @property + def exagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_micrometer) + + @property + def petagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_micrometer) + + @property + def teragrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_micrometer) + + @property + def gigagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_micrometer) + + @property + def megagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_micrometer) + + @property + def kilograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_micrometer) + + @property + def milligrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_micrometer) + + @property + def micrograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_micrometer) + + @property + def nanograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_micrometer) + + @property + def picograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_micrometer) + + @property + def femtograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_micrometer) + + @property + def attograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_micrometer) + + @property + def atomic_mass_units_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_micrometer) + + @property + def pounds_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_micrometer) + + @property + def ounces_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_micrometer) + + @property + def grams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_nanometer) + + @property + def exagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_nanometer) + + @property + def petagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_nanometer) + + @property + def teragrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_nanometer) + + @property + def gigagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_nanometer) + + @property + def megagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_nanometer) + + @property + def kilograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_nanometer) + + @property + def milligrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_nanometer) + + @property + def micrograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_nanometer) + + @property + def nanograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_nanometer) + + @property + def picograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_nanometer) + + @property + def femtograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_nanometer) + + @property + def attograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_nanometer) + + @property + def atomic_mass_units_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_nanometer) + + @property + def pounds_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_nanometer) + + @property + def ounces_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_nanometer) + + @property + def grams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_picometer) + + @property + def exagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_picometer) + + @property + def petagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_picometer) + + @property + def teragrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_picometer) + + @property + def gigagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_picometer) + + @property + def megagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_picometer) + + @property + def kilograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_picometer) + + @property + def milligrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_picometer) + + @property + def micrograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_picometer) + + @property + def nanograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_picometer) + + @property + def picograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_picometer) + + @property + def femtograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_picometer) + + @property + def attograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_picometer) + + @property + def atomic_mass_units_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_picometer) + + @property + def pounds_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_picometer) + + @property + def ounces_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_picometer) + + @property + def grams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_femtometer) + + @property + def exagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_femtometer) + + @property + def petagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_femtometer) + + @property + def teragrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_femtometer) + + @property + def gigagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_femtometer) + + @property + def megagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_femtometer) + + @property + def kilograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_femtometer) + + @property + def milligrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_femtometer) + + @property + def micrograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_femtometer) + + @property + def nanograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_femtometer) + + @property + def picograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_femtometer) + + @property + def femtograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_femtometer) + + @property + def attograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_femtometer) + + @property + def atomic_mass_units_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_femtometer) + + @property + def pounds_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_femtometer) + + @property + def ounces_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_femtometer) + + @property + def grams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_attometer) + + @property + def exagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_attometer) + + @property + def petagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_attometer) + + @property + def teragrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_attometer) + + @property + def gigagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_attometer) + + @property + def megagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_attometer) + + @property + def kilograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_attometer) + + @property + def milligrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_attometer) + + @property + def micrograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_attometer) + + @property + def nanograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_attometer) + + @property + def picograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_attometer) + + @property + def femtograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_attometer) + + @property + def attograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_attometer) + + @property + def atomic_mass_units_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_attometer) + + @property + def pounds_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_attometer) + + @property + def ounces_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_attometer) + + @property + def grams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_decimeter) + + @property + def exagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_decimeter) + + @property + def petagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_decimeter) + + @property + def teragrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_decimeter) + + @property + def gigagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_decimeter) + + @property + def megagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_decimeter) + + @property + def kilograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_decimeter) + + @property + def milligrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_decimeter) + + @property + def micrograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_decimeter) + + @property + def nanograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_decimeter) + + @property + def picograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_decimeter) + + @property + def femtograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_decimeter) + + @property + def attograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_decimeter) + + @property + def atomic_mass_units_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_decimeter) + + @property + def pounds_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_decimeter) + + @property + def ounces_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_decimeter) + + @property + def grams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_centimeter) + + @property + def exagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_centimeter) + + @property + def petagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_centimeter) + + @property + def teragrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_centimeter) + + @property + def gigagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_centimeter) + + @property + def megagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_centimeter) + + @property + def kilograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_centimeter) + + @property + def milligrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_centimeter) + + @property + def micrograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_centimeter) + + @property + def nanograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_centimeter) + + @property + def picograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_centimeter) + + @property + def femtograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_centimeter) + + @property + def attograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_centimeter) + + @property + def atomic_mass_units_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_centimeter) + + @property + def pounds_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_centimeter) + + @property + def ounces_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_centimeter) + + @property + def grams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_angstrom) + + @property + def exagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_angstrom) + + @property + def petagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_angstrom) + + @property + def teragrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_angstrom) + + @property + def gigagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_angstrom) + + @property + def megagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_angstrom) + + @property + def kilograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_angstrom) + + @property + def milligrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_angstrom) + + @property + def micrograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_angstrom) + + @property + def nanograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_angstrom) + + @property + def picograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_angstrom) + + @property + def femtograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_angstrom) + + @property + def attograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_angstrom) + + @property + def atomic_mass_units_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_angstrom) + + @property + def pounds_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_angstrom) + + @property + def ounces_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_angstrom) + + @property + def grams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_mile) + + @property + def exagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_mile) + + @property + def petagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_mile) + + @property + def teragrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_mile) + + @property + def gigagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_mile) + + @property + def megagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_mile) + + @property + def kilograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_mile) + + @property + def milligrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_mile) + + @property + def micrograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_mile) + + @property + def nanograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_mile) + + @property + def picograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_mile) + + @property + def femtograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_mile) + + @property + def attograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_mile) + + @property + def atomic_mass_units_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_mile) + + @property + def pounds_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_mile) + + @property + def ounces_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_mile) + + @property + def grams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_yard) + + @property + def exagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_yard) + + @property + def petagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_yard) + + @property + def teragrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_yard) + + @property + def gigagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_yard) + + @property + def megagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_yard) + + @property + def kilograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_yard) + + @property + def milligrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_yard) + + @property + def micrograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_yard) + + @property + def nanograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_yard) + + @property + def picograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_yard) + + @property + def femtograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_yard) + + @property + def attograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_yard) + + @property + def atomic_mass_units_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_yard) + + @property + def pounds_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_yard) + + @property + def ounces_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_yard) + + @property + def grams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_foot) + + @property + def exagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_foot) + + @property + def petagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_foot) + + @property + def teragrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_foot) + + @property + def gigagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_foot) + + @property + def megagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_foot) + + @property + def kilograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_foot) + + @property + def milligrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_foot) + + @property + def micrograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_foot) + + @property + def nanograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_foot) + + @property + def picograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_foot) + + @property + def femtograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_foot) + + @property + def attograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_foot) + + @property + def atomic_mass_units_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_foot) + + @property + def pounds_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_foot) + + @property + def ounces_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_foot) + + @property + def grams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_inch) + + @property + def exagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_inch) + + @property + def petagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_inch) + + @property + def teragrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_inch) + + @property + def gigagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_inch) + + @property + def megagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_inch) + + @property + def kilograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_inch) + + @property + def milligrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_inch) + + @property + def micrograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_inch) + + @property + def nanograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_inch) + + @property + def picograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_inch) + + @property + def femtograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_inch) + + @property + def attograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_inch) + + @property + def atomic_mass_units_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_inch) + + @property + def pounds_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_inch) + + @property + def ounces_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_inch) + + + +class ForceAccessor[T](QuantityAccessor[T]): + dimension_name = 'force' + + @property + def newtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.newtons) + + @property + def exanewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exanewtons) + + @property + def petanewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petanewtons) + + @property + def teranewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teranewtons) + + @property + def giganewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.giganewtons) + + @property + def meganewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meganewtons) + + @property + def kilonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilonewtons) + + @property + def millinewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millinewtons) + + @property + def micronewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micronewtons) + + @property + def nanonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanonewtons) + + @property + def piconewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.piconewtons) + + @property + def femtonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtonewtons) + + @property + def attonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attonewtons) + + @property + def kg_force(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kg_force) + + @property + def pounds_force(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_force) + + + +class PressureAccessor[T](QuantityAccessor[T]): + dimension_name = 'pressure' + + @property + def pascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pascals) + + @property + def exapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exapascals) + + @property + def petapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petapascals) + + @property + def terapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terapascals) + + @property + def gigapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigapascals) + + @property + def megapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megapascals) + + @property + def kilopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilopascals) + + @property + def millipascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millipascals) + + @property + def micropascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micropascals) + + @property + def nanopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanopascals) + + @property + def picopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picopascals) + + @property + def femtopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtopascals) + + @property + def attopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attopascals) + + @property + def pounds_force_per_square_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_force_per_square_inch) + + + +class EnergyAccessor[T](QuantityAccessor[T]): + dimension_name = 'energy' + + @property + def joules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.joules) + + @property + def exajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exajoules) + + @property + def petajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petajoules) + + @property + def terajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terajoules) + + @property + def gigajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigajoules) + + @property + def megajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megajoules) + + @property + def kilojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilojoules) + + @property + def millijoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millijoules) + + @property + def microjoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microjoules) + + @property + def nanojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanojoules) + + @property + def picojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picojoules) + + @property + def femtojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtojoules) + + @property + def attojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attojoules) + + @property + def electronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.electronvolts) + + @property + def exaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exaelectronvolts) + + @property + def petaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petaelectronvolts) + + @property + def teraelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teraelectronvolts) + + @property + def gigaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigaelectronvolts) + + @property + def megaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megaelectronvolts) + + @property + def kiloelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kiloelectronvolts) + + @property + def millielectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millielectronvolts) + + @property + def microelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microelectronvolts) + + @property + def nanoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoelectronvolts) + + @property + def picoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoelectronvolts) + + @property + def femtoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoelectronvolts) + + @property + def attoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoelectronvolts) + + + +class PowerAccessor[T](QuantityAccessor[T]): + dimension_name = 'power' + + @property + def watts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.watts) + + @property + def exawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exawatts) + + @property + def petawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petawatts) + + @property + def terawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terawatts) + + @property + def gigawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigawatts) + + @property + def megawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megawatts) + + @property + def kilowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilowatts) + + @property + def milliwatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliwatts) + + @property + def microwatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microwatts) + + @property + def nanowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanowatts) + + @property + def picowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picowatts) + + @property + def femtowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtowatts) + + @property + def attowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attowatts) + + + +class ChargeAccessor[T](QuantityAccessor[T]): + dimension_name = 'charge' + + @property + def coulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.coulombs) + + @property + def exacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exacoulombs) + + @property + def petacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petacoulombs) + + @property + def teracoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teracoulombs) + + @property + def gigacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigacoulombs) + + @property + def megacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megacoulombs) + + @property + def kilocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilocoulombs) + + @property + def millicoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millicoulombs) + + @property + def microcoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microcoulombs) + + @property + def nanocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanocoulombs) + + @property + def picocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picocoulombs) + + @property + def femtocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtocoulombs) + + @property + def attocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attocoulombs) + + + +class PotentialAccessor[T](QuantityAccessor[T]): + dimension_name = 'potential' + + @property + def volts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.volts) + + @property + def exavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exavolts) + + @property + def petavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petavolts) + + @property + def teravolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teravolts) + + @property + def gigavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigavolts) + + @property + def megavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megavolts) + + @property + def kilovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilovolts) + + @property + def millivolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millivolts) + + @property + def microvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microvolts) + + @property + def nanovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanovolts) + + @property + def picovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picovolts) + + @property + def femtovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtovolts) + + @property + def attovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attovolts) + + + +class ResistanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'resistance' + + @property + def ohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ohms) + + @property + def exaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exaohms) + + @property + def petaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petaohms) + + @property + def teraohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teraohms) + + @property + def gigaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigaohms) + + @property + def megaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megaohms) + + @property + def kiloohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kiloohms) + + @property + def milliohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliohms) + + @property + def microohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microohms) + + @property + def nanoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoohms) + + @property + def picoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoohms) + + @property + def femtoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoohms) + + @property + def attoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoohms) + + + +class CapacitanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'capacitance' + + @property + def farads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.farads) + + @property + def exafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exafarads) + + @property + def petafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petafarads) + + @property + def terafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terafarads) + + @property + def gigafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigafarads) + + @property + def megafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megafarads) + + @property + def kilofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilofarads) + + @property + def millifarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millifarads) + + @property + def microfarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microfarads) + + @property + def nanofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanofarads) + + @property + def picofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picofarads) + + @property + def femtofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtofarads) + + @property + def attofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attofarads) + + + +class ConductanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'conductance' + + @property + def siemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.siemens) + + @property + def exasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exasiemens) + + @property + def petasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petasiemens) + + @property + def terasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terasiemens) + + @property + def gigasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigasiemens) + + @property + def megasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megasiemens) + + @property + def kilosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilosiemens) + + @property + def millisiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millisiemens) + + @property + def microsiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microsiemens) + + @property + def nanosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanosiemens) + + @property + def picosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picosiemens) + + @property + def femtosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtosiemens) + + @property + def attosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attosiemens) + + + +class MagneticfluxAccessor[T](QuantityAccessor[T]): + dimension_name = 'magnetic_flux' + + @property + def webers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.webers) + + @property + def exawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exawebers) + + @property + def petawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petawebers) + + @property + def terawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terawebers) + + @property + def gigawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigawebers) + + @property + def megawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megawebers) + + @property + def kilowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilowebers) + + @property + def milliwebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliwebers) + + @property + def microwebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microwebers) + + @property + def nanowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanowebers) + + @property + def picowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picowebers) + + @property + def femtowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtowebers) + + @property + def attowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attowebers) + + + +class MagneticfluxdensityAccessor[T](QuantityAccessor[T]): + dimension_name = 'magnetic_flux_density' + + @property + def tesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.tesla) + + @property + def exatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exatesla) + + @property + def petatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petatesla) + + @property + def teratesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teratesla) + + @property + def gigatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigatesla) + + @property + def megatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megatesla) + + @property + def kilotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilotesla) + + @property + def millitesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millitesla) + + @property + def microtesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microtesla) + + @property + def nanotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanotesla) + + @property + def picotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picotesla) + + @property + def femtotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtotesla) + + @property + def attotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attotesla) + + + +class InductanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'inductance' + + @property + def henry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.henry) + + @property + def exahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exahenry) + + @property + def petahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petahenry) + + @property + def terahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terahenry) + + @property + def gigahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigahenry) + + @property + def megahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megahenry) + + @property + def kilohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilohenry) + + @property + def millihenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millihenry) + + @property + def microhenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microhenry) + + @property + def nanohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanohenry) + + @property + def picohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picohenry) + + @property + def femtohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtohenry) + + @property + def attohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attohenry) + + + +class TemperatureAccessor[T](QuantityAccessor[T]): + dimension_name = 'temperature' + + @property + def kelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kelvin) + + @property + def exakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exakelvin) + + @property + def petakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petakelvin) + + @property + def terakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terakelvin) + + @property + def gigakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigakelvin) + + @property + def megakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megakelvin) + + @property + def kilokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilokelvin) + + @property + def millikelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millikelvin) + + @property + def microkelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microkelvin) + + @property + def nanokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanokelvin) + + @property + def picokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picokelvin) + + @property + def femtokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtokelvin) + + @property + def attokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attokelvin) + + @property + def degrees_celsius(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.degrees_celsius) + + + +class DimensionlessAccessor[T](QuantityAccessor[T]): + dimension_name = 'dimensionless' + + @property + def none(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.none) + + @property + def percent(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.percent) + + + +class AngleAccessor[T](QuantityAccessor[T]): + dimension_name = 'angle' + + @property + def degrees(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.degrees) + + @property + def radians(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.radians) + + + +class SolidangleAccessor[T](QuantityAccessor[T]): + dimension_name = 'solid_angle' + + @property + def stradians(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.stradians) + + + +class AmountAccessor[T](QuantityAccessor[T]): + dimension_name = 'amount' + + @property + def moles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles) + + @property + def millimoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles) + + @property + def micromoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles) + + @property + def nanomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles) + + @property + def picomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles) + + @property + def femtomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles) + + @property + def attomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles) + + + +class ConcentrationAccessor[T](QuantityAccessor[T]): + dimension_name = 'concentration' + + @property + def moles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_meter) + + @property + def millimoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_meter) + + @property + def micromoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_meter) + + @property + def nanomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_meter) + + @property + def picomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_meter) + + @property + def femtomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_meter) + + @property + def attomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_meter) + + @property + def moles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_exameter) + + @property + def millimoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_exameter) + + @property + def micromoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_exameter) + + @property + def nanomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_exameter) + + @property + def picomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_exameter) + + @property + def femtomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_exameter) + + @property + def attomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_exameter) + + @property + def moles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_petameter) + + @property + def millimoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_petameter) + + @property + def micromoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_petameter) + + @property + def nanomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_petameter) + + @property + def picomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_petameter) + + @property + def femtomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_petameter) + + @property + def attomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_petameter) + + @property + def moles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_terameter) + + @property + def millimoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_terameter) + + @property + def micromoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_terameter) + + @property + def nanomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_terameter) + + @property + def picomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_terameter) + + @property + def femtomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_terameter) + + @property + def attomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_terameter) + + @property + def moles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_gigameter) + + @property + def millimoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_gigameter) + + @property + def micromoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_gigameter) + + @property + def nanomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_gigameter) + + @property + def picomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_gigameter) + + @property + def femtomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_gigameter) + + @property + def attomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_gigameter) + + @property + def moles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_megameter) + + @property + def millimoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_megameter) + + @property + def micromoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_megameter) + + @property + def nanomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_megameter) + + @property + def picomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_megameter) + + @property + def femtomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_megameter) + + @property + def attomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_megameter) + + @property + def moles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_kilometer) + + @property + def millimoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_kilometer) + + @property + def micromoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_kilometer) + + @property + def nanomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_kilometer) + + @property + def picomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_kilometer) + + @property + def femtomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_kilometer) + + @property + def attomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_kilometer) + + @property + def moles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_millimeter) + + @property + def millimoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_millimeter) + + @property + def micromoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_millimeter) + + @property + def nanomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_millimeter) + + @property + def picomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_millimeter) + + @property + def femtomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_millimeter) + + @property + def attomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_millimeter) + + @property + def moles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_micrometer) + + @property + def millimoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_micrometer) + + @property + def micromoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_micrometer) + + @property + def nanomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_micrometer) + + @property + def picomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_micrometer) + + @property + def femtomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_micrometer) + + @property + def attomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_micrometer) + + @property + def moles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_nanometer) + + @property + def millimoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_nanometer) + + @property + def micromoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_nanometer) + + @property + def nanomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_nanometer) + + @property + def picomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_nanometer) + + @property + def femtomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_nanometer) + + @property + def attomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_nanometer) + + @property + def moles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_picometer) + + @property + def millimoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_picometer) + + @property + def micromoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_picometer) + + @property + def nanomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_picometer) + + @property + def picomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_picometer) + + @property + def femtomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_picometer) + + @property + def attomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_picometer) + + @property + def moles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_femtometer) + + @property + def millimoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_femtometer) + + @property + def micromoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_femtometer) + + @property + def nanomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_femtometer) + + @property + def picomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_femtometer) + + @property + def femtomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_femtometer) + + @property + def attomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_femtometer) + + @property + def moles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_attometer) + + @property + def millimoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_attometer) + + @property + def micromoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_attometer) + + @property + def nanomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_attometer) + + @property + def picomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_attometer) + + @property + def femtomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_attometer) + + @property + def attomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_attometer) + + @property + def moles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_decimeter) + + @property + def millimoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_decimeter) + + @property + def micromoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_decimeter) + + @property + def nanomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_decimeter) + + @property + def picomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_decimeter) + + @property + def femtomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_decimeter) + + @property + def attomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_decimeter) + + @property + def moles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_centimeter) + + @property + def millimoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_centimeter) + + @property + def micromoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_centimeter) + + @property + def nanomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_centimeter) + + @property + def picomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_centimeter) + + @property + def femtomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_centimeter) + + @property + def attomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_centimeter) + + @property + def moles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_angstrom) + + @property + def millimoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_angstrom) + + @property + def micromoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_angstrom) + + @property + def nanomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_angstrom) + + @property + def picomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_angstrom) + + @property + def femtomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_angstrom) + + @property + def attomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_angstrom) + + @property + def moles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_mile) + + @property + def millimoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_mile) + + @property + def micromoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_mile) + + @property + def nanomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_mile) + + @property + def picomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_mile) + + @property + def femtomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_mile) + + @property + def attomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_mile) + + @property + def moles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_yard) + + @property + def millimoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_yard) + + @property + def micromoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_yard) + + @property + def nanomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_yard) + + @property + def picomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_yard) + + @property + def femtomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_yard) + + @property + def attomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_yard) + + @property + def moles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_foot) + + @property + def millimoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_foot) + + @property + def micromoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_foot) + + @property + def nanomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_foot) + + @property + def picomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_foot) + + @property + def femtomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_foot) + + @property + def attomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_foot) + + @property + def moles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_inch) + + @property + def millimoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_inch) + + @property + def micromoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_inch) + + @property + def nanomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_inch) + + @property + def picomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_inch) + + @property + def femtomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_inch) + + @property + def attomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_inch) + + diff --git a/sasdata/quantities/constants.py b/sasdata/quantities/constants.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/quantities/math_operations_test.py b/sasdata/quantities/math_operations_test.py new file mode 100644 index 0000000..5bda5a2 --- /dev/null +++ b/sasdata/quantities/math_operations_test.py @@ -0,0 +1,152 @@ +""" Tests for math operations """ + +import pytest + +import numpy as np +from sasdata.quantities.quantity import NamedQuantity, tensordot, transpose +from sasdata.quantities import units + +order_list = [ + [0, 1, 2, 3], + [0, 2, 1], + [1, 0], + [0, 1], + [2, 0, 1], + [3, 1, 2, 0] +] + +@pytest.mark.parametrize("order", order_list) +def test_transpose_raw(order: list[int]): + """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" + + input_shape = tuple([i+1 for i in range(len(order))]) + expected_shape = tuple([i+1 for i in order]) + + input_mat = np.zeros(input_shape) + + measured_mat = transpose(input_mat, axes=tuple(order)) + + assert measured_mat.shape == expected_shape + + +@pytest.mark.parametrize("order", order_list) +def test_transpose_raw(order: list[int]): + """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" + input_shape = tuple([i + 1 for i in range(len(order))]) + expected_shape = tuple([i + 1 for i in order]) + + input_mat = NamedQuantity("testmat", np.zeros(input_shape), units=units.none) + + measured_mat = transpose(input_mat, axes=tuple(order)) + + assert measured_mat.value.shape == expected_shape + + +rng_seed = 1979 +tensor_product_with_identity_sizes = (4,6,5) + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_quantities(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (quantity, quantity)""" + np.random.seed(rng_seed) + + x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units=units.meters) + y = NamedQuantity("y", np.eye(size), units.seconds) + + z = tensordot(x, y, index, 0) + + # Check units + assert z.units == units.meters * units.seconds + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x.in_si() + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) + + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_quantity_matrix(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (quantity, matrix)""" + np.random.seed(rng_seed) + + x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units.meters) + y = np.eye(size) + + z = tensordot(x, y, index, 0) + + assert z.units == units.meters + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x.in_si() + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) + + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_matrix_quantity(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (matrix, quantity)""" + np.random.seed(rng_seed) + + x = np.random.rand(*tensor_product_with_identity_sizes) + y = NamedQuantity("y", np.eye(size), units.seconds) + + z = tensordot(x, y, index, 0) + + assert z.units == units.seconds + + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) diff --git a/sasdata/quantities/notes.rst b/sasdata/quantities/notes.rst new file mode 100644 index 0000000..9c4f47c --- /dev/null +++ b/sasdata/quantities/notes.rst @@ -0,0 +1,23 @@ +Mutability +---------- + +DataSets: Immutable +Quantities: Immutable +Units: Hard coded + +Quantity methods +---------------- + +in_* methods return numbers/arrays in a given unit system +to_* converts to different units + + +Identifying of Quantities +-------------------- + +There are two choices when it comes to keeping track of quantities for error propagation. +Either we give them names, in which case we risk collisions, or we use hashes, which can potentially +have issues with things not being identified correctly. + +The decision here is to use hashes of the data, not names, because it would be too easy to +give different things the same name. \ No newline at end of file diff --git a/sasdata/quantities/numerical_encoding.py b/sasdata/quantities/numerical_encoding.py new file mode 100644 index 0000000..879880a --- /dev/null +++ b/sasdata/quantities/numerical_encoding.py @@ -0,0 +1,72 @@ +import numpy as np +from scipy.sparse import coo_matrix, csr_matrix, csc_matrix, coo_array, csr_array, csc_array + +import base64 +import struct + + +def numerical_encode(obj: int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array): + + if isinstance(obj, int): + return {"type": "int", + "value": obj} + + elif isinstance(obj, float): + return {"type": "float", + "value": base64.b64encode(bytearray(struct.pack('d', obj)))} + + elif isinstance(obj, np.ndarray): + return { + "type": "numpy", + "value": base64.b64encode(obj.tobytes()), + "dtype": obj.dtype.str, + "shape": list(obj.shape) + } + + elif isinstance(obj, (coo_matrix, coo_array, csr_matrix, csr_array, csc_matrix, csc_array)): + + output = { + "type": obj.__class__.__name__, # not robust to name changes, but more concise + "dtype": obj.dtype.str, + "shape": list(obj.shape) + } + + if isinstance(obj, (coo_array, coo_matrix)): + + output["data"] = numerical_encode(obj.data) + output["coords"] = [numerical_encode(coord) for coord in obj.coords] + + + elif isinstance(obj, (csr_array, csr_matrix)): + pass + + + elif isinstance(obj, (csc_array, csc_matrix)): + + pass + + + return output + + else: + raise TypeError(f"Cannot serialise object of type: {type(obj)}") + +def numerical_decode(data: dict[str, str | int | list[int]]) -> int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array: + obj_type = data["type"] + + match obj_type: + case "int": + return int(data["value"]) + + case "float": + return struct.unpack('d', base64.b64decode(data["value"]))[0] + + case "numpy": + value = base64.b64decode(data["value"]) + dtype = np.dtype(data["dtype"]) + shape = tuple(data["shape"]) + return np.frombuffer(value, dtype=dtype).reshape(*shape) + + case _: + raise ValueError(f"Cannot decode objects of type '{obj_type}'") + diff --git a/sasdata/quantities/operations_examples.py b/sasdata/quantities/operations_examples.py new file mode 100644 index 0000000..e2e2566 --- /dev/null +++ b/sasdata/quantities/operations_examples.py @@ -0,0 +1,11 @@ +from sasdata.quantities.quantity import Variable, Mul + +x = Variable("x") +y = Variable("y") +z = Variable("z") +f = Mul(Mul(x, y), z) + + +dfdx = f.derivative(x).derivative(y).derivative(z) + +print(dfdx.summary()) diff --git a/sasdata/quantities/operations_test.py b/sasdata/quantities/operations_test.py new file mode 100644 index 0000000..6767e32 --- /dev/null +++ b/sasdata/quantities/operations_test.py @@ -0,0 +1,68 @@ +import pytest + +from sasdata.quantities.quantity import Operation, \ + Neg, Inv, \ + Add, Sub, Mul, Div, Pow, \ + Variable, Constant, AdditiveIdentity, MultiplicativeIdentity + +operation_with_everything = \ + Div( + Pow( + Mul( + Sub( + Add( + Neg(Inv(MultiplicativeIdentity())), + Variable("x")), + Constant(7)), + AdditiveIdentity()), + 2), + Variable("y")) + +def test_serialise_deserialise(): + print(operation_with_everything._serialise_json()) + + serialised = operation_with_everything.serialise() + deserialised = Operation.deserialise(serialised) + reserialised = deserialised.serialise() + + assert serialised == reserialised + + +@pytest.mark.parametrize("op, a, b, result", [ + (Add, 1, 1, 2), + (Add, 7, 8, 15), + (Sub, 1, 1, 0), + (Sub, 7, 8, -1), + (Mul, 1, 1, 1), + (Mul, 7, 8, 56), + (Div, 1, 1, 1), + (Div, 7, 8, 7/8), + (Pow, 1, 1, 1), + (Pow, 7, 2, 49)]) +def test_binary_evaluation(op, a, b, result): + f = op(Constant(a), b if op == Pow else Constant(b)) + assert f.evaluate({}) == result + +x = Variable("x") +y = Variable("y") +z = Variable("z") +@pytest.mark.parametrize("x_over_x", [ + Div(x,x), + Mul(Inv(x), x), + Mul(x, Inv(x)), +]) +def test_dx_over_x_by_dx_should_be_zero(x_over_x): + + + dfdx = x_over_x.derivative(x) + + print(dfdx.summary()) + + assert dfdx == AdditiveIdentity() + + +def test_d_xyz_by_components_should_be_1(): + f = Mul(Mul(x, y), z) + assert f.derivative(x).derivative(y).derivative(z) == MultiplicativeIdentity() + + diff --git a/sasdata/quantities/plotting.py b/sasdata/quantities/plotting.py new file mode 100644 index 0000000..854e23f --- /dev/null +++ b/sasdata/quantities/plotting.py @@ -0,0 +1,23 @@ +import matplotlib.pyplot as plt +from numpy.typing import ArrayLike + +from sasdata.quantities.quantity import Quantity, NamedQuantity + + +def quantity_plot(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): + plt.plot(x.value, y.value, *args, **kwargs) + + x_name = x.name if isinstance(x, NamedQuantity) else "x" + y_name = y.name if isinstance(y, NamedQuantity) else "y" + + plt.xlabel(f"{x_name} / {x.units}") + plt.ylabel(f"{y_name} / {y.units}") + +def quantity_scatter(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): + plt.scatter(x.value, y.value, *args, **kwargs) + + x_name = x.name if isinstance(x, NamedQuantity) else "x" + y_name = y.name if isinstance(y, NamedQuantity) else "y" + + plt.xlabel(f"{x_name} / {x.units}") + plt.ylabel(f"{y_name} / {y.units}") diff --git a/sasdata/quantities/quantities_tests.py b/sasdata/quantities/quantities_tests.py new file mode 100644 index 0000000..8ab0a41 --- /dev/null +++ b/sasdata/quantities/quantities_tests.py @@ -0,0 +1,124 @@ +import numpy as np + +from sasdata.quantities.quantity import Quantity, UnitError +import sasdata.quantities.units as units +import sasdata.quantities.si as si +import pytest +def test_in_units_of_calculation(): + """ Just a couple of unit conversions """ + assert Quantity(1, units.meters).in_units_of(units.kilometers) == 1e-3 + assert Quantity(10, units.minutes).in_units_of(units.seconds) == 600 + assert Quantity(7, units.kilonewtons).in_units_of(units.kg_force) == pytest.approx(7000 / 9.81, abs=1) + assert Quantity(0, units.meters).in_units_of(units.exameters) == 0 + + +def test_unit_compounding_pow(): + """ Test units compound correctly when __pow__ is used""" + assert (Quantity(1, units.millimeters) ** 2).in_units_of(units.square_meters) == 1e-6 + assert (Quantity(1, units.minutes) ** 3).in_units_of(units.seconds ** 3) == 60 ** 3 + +def test_pow_scaling(): + q2 = Quantity(1000, units.millimeters)**2 + assert q2.units.scale == 1e-6 + assert q2.value == 1e6 + + +def test_unit_compounding_mul(): + """ Test units compound correctly when __mul__ is used""" + assert (Quantity(4, units.minutes) * Quantity(0.25, units.hertz)).in_units_of(units.none) == 60 + assert (Quantity(250, units.volts) * Quantity(8, units.amperes)).in_units_of(units.kilowatts) == 2 + +def test_unit_compounding_div(): + """ Test units compound correctly when __truediv__ is used""" + assert (Quantity(10, units.kilometers) / Quantity(2, units.minutes) + ).in_units_of(units.meters_per_second) == pytest.approx(250/3, abs=1e-6) + + assert (Quantity(1, units.nanowebers) / (Quantity(1, units.millimeters) ** 2)).in_units_of(units.millitesla) == 1 + +def test_value_mul(): + """ Test value part of quantities multiply correctly""" + assert (Quantity(1j, units.seconds) * Quantity(1j, units.watts)).in_units_of(units.joules) == -1 + +def test_scalar_mul(): + assert (Quantity(1, units.seconds) * 10).in_units_of(units.seconds) == 10 + assert (10 * Quantity(1, units.seconds)).in_units_of(units.seconds) == 10 + assert (1000 * Quantity(1, units.milliseconds)).in_units_of(units.seconds) == 1 + +def test_scalar_div(): + + assert (Quantity(1, units.seconds) / 10).in_units_of(units.seconds) == 0.1 + assert (10 / Quantity(1, units.seconds)).in_units_of(units.hertz) == 10 + assert (0.001 / Quantity(1, units.milliseconds)).in_units_of(units.hertz) == 1 + +def test_good_add_sub(): + """ Test that adding and subtracting units works """ + assert (Quantity(1, units.seconds) + Quantity(1, units.milliseconds)).in_units_of(units.seconds) == 1.001 + assert (Quantity(1, units.seconds) - Quantity(1, units.milliseconds)).in_units_of(units.seconds) == 0.999 + + assert (Quantity(1, units.inches) + Quantity(1, units.feet)).in_units_of(units.inches) == pytest.approx(13, abs=1e-8) + +@pytest.mark.parametrize("unit_in, power, unit_out", [ + (units.meters**2, 1/2, units.meters), + (units.meters**3, 1/3, units.meters), + (units.meters**3, 2/3, units.meters**2), + (units.meters**3, -5/3, units.meters**-5), + (units.none, 1/10, units.none), + (units.none, 19/17, units.none), + (units.none, np.pi, units.none) +]) +def test_good_non_integer_unit_powers(unit_in, power, unit_out): + """ Check that we can do various square and cube root stuff if we need to, + If dimensionless, we should be able to do arbitrary powers + """ + assert unit_in**power == unit_out + +@pytest.mark.parametrize("unit, power", [ + (units.meters, 1/2), + (units.milliohms, 1/3), + (units.meters, 3/2), + (units.meters**2, 2/3) +]) +def test_bad_non_integer_unit_powers(unit, power): + """ Check that we get an error if we try and do something silly with powers""" + with pytest.raises(units.DimensionError): + x = unit**power + + +@pytest.mark.parametrize("unit_1", si.all_si) +@pytest.mark.parametrize("unit_2", si.all_si) +def test_mixed_quantity_add_sub(unit_1, unit_2): + if unit_1.equivalent(unit_2): + assert (Quantity(0, unit_1) + Quantity(0, unit_2)).in_units_of(unit_1) == 0 + + else: + with pytest.raises(UnitError): + Quantity(1, unit_1) + Quantity(1, unit_2) + +def assert_unit_ratio(u1: units.Unit, u2: units.Unit, value: float, abs=1e-9): + """ Helper function for testing units that are multiples of each other """ + + assert u1.equivalent(u2), "Units should be compatible for this test" + assert (Quantity(1, u1) / Quantity(1, u2)).in_units_of(units.none) == pytest.approx(value, abs=abs) + + +def test_american_units(): + assert_unit_ratio(units.feet, units.inches, 12) + assert_unit_ratio(units.yards, units.inches, 36) + assert_unit_ratio(units.miles, units.inches, 63360) + assert_unit_ratio(units.pounds_force_per_square_inch, units.pounds_force / (units.inches**2), 1, abs=1e-5) + +def test_percent(): + assert Quantity(5, units.percent).in_units_of(units.none) == pytest.approx(0.05, 1e-10) + +@pytest.mark.parametrize("unit_1", si.all_si) +@pytest.mark.parametrize("unit_2", si.all_si) +def test_conversion_errors(unit_1, unit_2): + """ Test conversion errors are thrown when units are not compatible """ + + if unit_1 == unit_2: + assert Quantity(1, unit_1).in_units_of(unit_2) == 1 + + else: + with pytest.raises(UnitError): + Quantity(1, units.seconds).in_units_of(units.meters) + diff --git a/sasdata/quantities/quantity.py b/sasdata/quantities/quantity.py new file mode 100644 index 0000000..584f3cf --- /dev/null +++ b/sasdata/quantities/quantity.py @@ -0,0 +1,1443 @@ +from typing import Self + +import numpy as np +from numpy._typing import ArrayLike + +from sasdata.quantities import units +from sasdata.quantities.numerical_encoding import numerical_decode, numerical_encode +from sasdata.quantities.units import Unit, NamedUnit + +import hashlib + +from typing import Any, TypeVar, Union + +import json + +T = TypeVar("T") + + + + + +################### Quantity based operations, need to be here to avoid cyclic dependencies ##################### + +def transpose(a: Union["Quantity[ArrayLike]", ArrayLike], axes: tuple | None = None): + """ Transpose an array or an array based quantity, can also do reordering of axes""" + if isinstance(a, Quantity): + + if axes is None: + return DerivedQuantity(value=np.transpose(a.value, axes=axes), + units=a.units, + history=QuantityHistory.apply_operation(Transpose, a.history)) + + else: + return DerivedQuantity(value=np.transpose(a.value, axes=axes), + units=a.units, + history=QuantityHistory.apply_operation(Transpose, a.history, axes=axes)) + + else: + return np.transpose(a, axes=axes) + + +def dot(a: Union["Quantity[ArrayLike]", ArrayLike], b: Union["Quantity[ArrayLike]", ArrayLike]): + """ Dot product of two arrays or two array based quantities """ + a_is_quantity = isinstance(a, Quantity) + b_is_quantity = isinstance(b, Quantity) + + if a_is_quantity or b_is_quantity: + + # If its only one of them that is a quantity, convert the other one + + if not a_is_quantity: + a = Quantity(a, units.none) + + if not b_is_quantity: + b = Quantity(b, units.none) + + return DerivedQuantity( + value=np.dot(a.value, b.value), + units=a.units * b.units, + history=QuantityHistory.apply_operation(Dot, a.history, b.history)) + + else: + return np.dot(a, b) + +def tensordot(a: Union["Quantity[ArrayLike]", ArrayLike] | ArrayLike, b: Union["Quantity[ArrayLike]", ArrayLike], a_index: int, b_index: int): + """ Tensor dot product - equivalent to contracting two tensors, such as + + A_{i0, i1, i2, i3...} and B_{j0, j1, j2...} + + e.g. if a_index is 1 and b_index is zero, it will be the sum + + C_{i0, i2, i3 ..., j1, j2 ...} = sum_k A_{i0, k, i2, i3 ...} B_{k, j1, j2 ...} + + (I think, have to check what happens with indices TODO!) + + """ + + a_is_quantity = isinstance(a, Quantity) + b_is_quantity = isinstance(b, Quantity) + + if a_is_quantity or b_is_quantity: + + # If its only one of them that is a quantity, convert the other one + + if not a_is_quantity: + a = Quantity(a, units.none) + + if not b_is_quantity: + b = Quantity(b, units.none) + + return DerivedQuantity( + value=np.tensordot(a.value, b.value, axes=(a_index, b_index)), + units=a.units * b.units, + history=QuantityHistory.apply_operation( + TensorDot, + a.history, + b.history, + a_index=a_index, + b_index=b_index)) + + else: + return np.tensordot(a, b, axes=(a_index, b_index)) + + +################### Operation Definitions ####################################### + +def hash_and_name(hash_or_name: int | str): + """ Infer the name of a variable from a hash, or the hash from the name + + Note: hash_and_name(hash_and_name(number)[1]) is not the identity + however: hash_and_name(hash_and_name(number)) is + """ + + if isinstance(hash_or_name, str): + hash_value = hash(hash_or_name) + name = hash_or_name + + return hash_value, name + + elif isinstance(hash_or_name, int): + hash_value = hash_or_name + name = f"#{hash_or_name}" + + return hash_value, name + + elif isinstance(hash_or_name, tuple): + return hash_or_name + + else: + raise TypeError("Variable name_or_hash_value must be either str or int") + +class Operation: + + serialisation_name = "unknown" + def summary(self, indent_amount: int = 0, indent: str=" "): + """ Summary of the operation tree""" + + s = f"{indent_amount*indent}{self._summary_open()}(\n" + + for chunk in self._summary_components(): + s += chunk.summary(indent_amount+1, indent) + "\n" + + s += f"{indent_amount*indent})" + + return s + def _summary_open(self): + """ First line of summary """ + + def _summary_components(self) -> list["Operation"]: + return [] + def evaluate(self, variables: dict[int, T]) -> T: + + """ Evaluate this operation """ + + def _derivative(self, hash_value: int) -> "Operation": + """ Get the derivative of this operation """ + + def _clean(self): + """ Clean up this operation - i.e. remove silly things like 1*x """ + return self + + def derivative(self, variable: Union[str, int, "Variable"], simplify=True): + if isinstance(variable, Variable): + hash_value = variable.hash_value + else: + hash_value, _ = hash_and_name(variable) + + derivative = self._derivative(hash_value) + + if not simplify: + return derivative + + derivative_string = derivative.serialise() + + # print("---------------") + # print("Base") + # print("---------------") + # print(derivative.summary()) + + # Inefficient way of doing repeated simplification, but it will work + for i in range(100): # set max iterations + + derivative = derivative._clean() + # + # print("-------------------") + # print("Iteration", i+1) + # print("-------------------") + # print(derivative.summary()) + # print("-------------------") + + new_derivative_string = derivative.serialise() + + if derivative_string == new_derivative_string: + break + + derivative_string = new_derivative_string + + return derivative + + @staticmethod + def deserialise(data: str) -> "Operation": + json_data = json.loads(data) + return Operation.deserialise_json(json_data) + + @staticmethod + def deserialise_json(json_data: dict) -> "Operation": + + operation = json_data["operation"] + parameters = json_data["parameters"] + cls = _serialisation_lookup[operation] + + try: + return cls._deserialise(parameters) + + except NotImplementedError: + raise NotImplementedError(f"No method to deserialise {operation} with {parameters} (cls={cls})") + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + raise NotImplementedError(f"Deserialise not implemented for this class") + + def serialise(self) -> str: + return json.dumps(self._serialise_json()) + + def _serialise_json(self) -> dict[str, Any]: + return {"operation": self.serialisation_name, + "parameters": self._serialise_parameters()} + + def _serialise_parameters(self) -> dict[str, Any]: + raise NotImplementedError("_serialise_parameters not implemented") + + def __eq__(self, other: "Operation"): + return NotImplemented + +class ConstantBase(Operation): + pass + +class AdditiveIdentity(ConstantBase): + + serialisation_name = "zero" + def evaluate(self, variables: dict[int, T]) -> T: + return 0 + + def _derivative(self, hash_value: int) -> Operation: + return AdditiveIdentity() + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return AdditiveIdentity() + + def _serialise_parameters(self) -> dict[str, Any]: + return {} + + def summary(self, indent_amount: int=0, indent=" "): + return f"{indent_amount*indent}0 [Add.Id.]" + + def __eq__(self, other): + if isinstance(other, AdditiveIdentity): + return True + elif isinstance(other, Constant): + if other.value == 0: + return True + + return False + + + +class MultiplicativeIdentity(ConstantBase): + + serialisation_name = "one" + + def evaluate(self, variables: dict[int, T]) -> T: + return 1 + + def _derivative(self, hash_value: int): + return AdditiveIdentity() + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return MultiplicativeIdentity() + + + def _serialise_parameters(self) -> dict[str, Any]: + return {} + + + def summary(self, indent_amount: int=0, indent=" "): + return f"{indent_amount*indent}1 [Mul.Id.]" + + def __eq__(self, other): + if isinstance(other, MultiplicativeIdentity): + return True + elif isinstance(other, Constant): + if other.value == 1: + return True + + return False + + +class Constant(ConstantBase): + + serialisation_name = "constant" + def __init__(self, value): + self.value = value + + def summary(self, indent_amount: int = 0, indent: str=" "): + return repr(self.value) + + def evaluate(self, variables: dict[int, T]) -> T: + return self.value + + def _derivative(self, hash_value: int): + return AdditiveIdentity() + + def _clean(self): + + if self.value == 0: + return AdditiveIdentity() + + elif self.value == 1: + return MultiplicativeIdentity() + + else: + return self + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + value = numerical_decode(parameters["value"]) + return Constant(value) + + + def _serialise_parameters(self) -> dict[str, Any]: + return {"value": numerical_encode(self.value)} + + def summary(self, indent_amount: int=0, indent=" "): + return f"{indent_amount*indent}{self.value}" + + def __eq__(self, other): + if isinstance(other, AdditiveIdentity): + return self.value == 0 + + elif isinstance(other, MultiplicativeIdentity): + return self.value == 1 + + elif isinstance(other, Constant): + if other.value == self.value: + return True + + return False + + +class Variable(Operation): + + serialisation_name = "variable" + def __init__(self, name_or_hash_value: int | str | tuple[int, str]): + self.hash_value, self.name = hash_and_name(name_or_hash_value) + + def evaluate(self, variables: dict[int, T]) -> T: + try: + return variables[self.hash_value] + except KeyError: + raise ValueError(f"Variable dictionary didn't have an entry for {self.name} (hash={self.hash_value})") + + def _derivative(self, hash_value: int) -> Operation: + if hash_value == self.hash_value: + return MultiplicativeIdentity() + else: + return AdditiveIdentity() + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + hash_value = parameters["hash_value"] + name = parameters["name"] + + return Variable((hash_value, name)) + + def _serialise_parameters(self) -> dict[str, Any]: + return {"hash_value": self.hash_value, + "name": self.name} + + def summary(self, indent_amount: int = 0, indent: str=" "): + return f"{indent_amount*indent}{self.name}" + + def __eq__(self, other): + if isinstance(other, Variable): + return self.hash_value == other.hash_value + + return False + +class UnaryOperation(Operation): + + def __init__(self, a: Operation): + self.a = a + + def _serialise_parameters(self) -> dict[str, Any]: + return {"a": self.a._serialise_json()} + + def _summary_components(self) -> list["Operation"]: + return [self.a] + + + + +class Neg(UnaryOperation): + + serialisation_name = "neg" + def evaluate(self, variables: dict[int, T]) -> T: + return -self.a.evaluate(variables) + + def _derivative(self, hash_value: int): + return Neg(self.a._derivative(hash_value)) + + def _clean(self): + + clean_a = self.a._clean() + + if isinstance(clean_a, Neg): + # Removes double negations + return clean_a.a + + elif isinstance(clean_a, Constant): + return Constant(-clean_a.value)._clean() + + else: + return Neg(clean_a) + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Neg(Operation.deserialise_json(parameters["a"])) + + + def _summary_open(self): + return "Neg" + + def __eq__(self, other): + if isinstance(other, Neg): + return other.a == self.a + + +class Inv(UnaryOperation): + + serialisation_name = "reciprocal" + + def evaluate(self, variables: dict[int, T]) -> T: + return 1/self.a.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Neg(Div(self.a._derivative(hash_value), Mul(self.a, self.a))) + + def _clean(self): + clean_a = self.a._clean() + + if isinstance(clean_a, Inv): + # Removes double negations + return clean_a.a + + elif isinstance(clean_a, Neg): + # cannonicalise 1/-a to -(1/a) + # over multiple iterations this should have the effect of ordering and gathering Neg and Inv + return Neg(Inv(clean_a.a)) + + elif isinstance(clean_a, Constant): + return Constant(1/clean_a.value)._clean() + + else: + return Inv(clean_a) + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Inv(Operation.deserialise_json(parameters["a"])) + + def _summary_open(self): + return "Inv" + + + def __eq__(self, other): + if isinstance(other, Inv): + return other.a == self.a + +class BinaryOperation(Operation): + def __init__(self, a: Operation, b: Operation): + self.a = a + self.b = b + + def _clean(self): + return self._clean_ab(self.a._clean(), self.b._clean()) + + def _clean_ab(self, a, b): + raise NotImplementedError("_clean_ab not implemented") + + def _serialise_parameters(self) -> dict[str, Any]: + return {"a": self.a._serialise_json(), + "b": self.b._serialise_json()} + + @staticmethod + def _deserialise_ab(parameters) -> tuple[Operation, Operation]: + return (Operation.deserialise_json(parameters["a"]), + Operation.deserialise_json(parameters["b"])) + + + def _summary_components(self) -> list["Operation"]: + return [self.a, self.b] + + def _self_cls(self) -> type: + """ Own class""" + def __eq__(self, other): + if isinstance(other, self._self_cls()): + return other.a == self.a and self.b == other.b + +class Add(BinaryOperation): + + serialisation_name = "add" + + def _self_cls(self) -> type: + return Add + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) + self.b.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Add(self.a._derivative(hash_value), self.b._derivative(hash_value)) + + def _clean_ab(self, a, b): + + if isinstance(a, AdditiveIdentity): + # Convert 0 + b to b + return b + + elif isinstance(b, AdditiveIdentity): + # Convert a + 0 to a + return a + + elif isinstance(a, ConstantBase) and isinstance(b, ConstantBase): + # Convert constant "a"+"b" to "a+b" + return Constant(a.evaluate({}) + b.evaluate({}))._clean() + + elif isinstance(a, Neg): + if isinstance(b, Neg): + # Convert (-a)+(-b) to -(a+b) + return Neg(Add(a.a, b.a)) + else: + # Convert (-a) + b to b-a + return Sub(b, a.a) + + elif isinstance(b, Neg): + # Convert a+(-b) to a-b + return Sub(a, b.a) + + elif a == b: + return Mul(Constant(2), a) + + else: + return Add(a, b) + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Add(*BinaryOperation._deserialise_ab(parameters)) + + def _summary_open(self): + return "Add" + +class Sub(BinaryOperation): + + serialisation_name = "sub" + + + def _self_cls(self) -> type: + return Sub + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) - self.b.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Sub(self.a._derivative(hash_value), self.b._derivative(hash_value)) + + def _clean_ab(self, a, b): + if isinstance(a, AdditiveIdentity): + # Convert 0 - b to -b + return Neg(b) + + elif isinstance(b, AdditiveIdentity): + # Convert a - 0 to a + return a + + elif isinstance(a, ConstantBase) and isinstance(b, ConstantBase): + # Convert constant pair "a" - "b" to "a-b" + return Constant(a.evaluate({}) - b.evaluate({}))._clean() + + elif isinstance(a, Neg): + if isinstance(b, Neg): + # Convert (-a)-(-b) to b-a + return Sub(b.a, a.a) + else: + # Convert (-a)-b to -(a+b) + return Neg(Add(a.a, b)) + + elif isinstance(b, Neg): + # Convert a-(-b) to a+b + return Add(a, b.a) + + elif a == b: + return AdditiveIdentity() + + else: + return Sub(a, b) + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Sub(*BinaryOperation._deserialise_ab(parameters)) + + + def _summary_open(self): + return "Sub" + +class Mul(BinaryOperation): + + serialisation_name = "mul" + + + def _self_cls(self) -> type: + return Mul + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) * self.b.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Add(Mul(self.a, self.b._derivative(hash_value)), Mul(self.a._derivative(hash_value), self.b)) + + def _clean_ab(self, a, b): + + if isinstance(a, AdditiveIdentity) or isinstance(b, AdditiveIdentity): + # Convert 0*b or a*0 to 0 + return AdditiveIdentity() + + elif isinstance(a, MultiplicativeIdentity): + # Convert 1*b to b + return b + + elif isinstance(b, MultiplicativeIdentity): + # Convert a*1 to a + return a + + elif isinstance(a, ConstantBase) and isinstance(b, ConstantBase): + # Convert constant "a"*"b" to "a*b" + return Constant(a.evaluate({}) * b.evaluate({}))._clean() + + elif isinstance(a, Inv) and isinstance(b, Inv): + return Inv(Mul(a.a, b.a)) + + elif isinstance(a, Inv) and not isinstance(b, Inv): + return Div(b, a.a) + + elif not isinstance(a, Inv) and isinstance(b, Inv): + return Div(a, b.a) + + elif isinstance(a, Neg): + return Neg(Mul(a.a, b)) + + elif isinstance(b, Neg): + return Neg(Mul(a, b.a)) + + elif a == b: + return Pow(a, 2) + + elif isinstance(a, Pow) and a.a == b: + return Pow(b, a.power + 1) + + elif isinstance(b, Pow) and b.a == a: + return Pow(a, b.power + 1) + + elif isinstance(a, Pow) and isinstance(b, Pow) and a.a == b.a: + return Pow(a.a, a.power + b.power) + + else: + return Mul(a, b) + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Mul(*BinaryOperation._deserialise_ab(parameters)) + + + def _summary_open(self): + return "Mul" + +class Div(BinaryOperation): + + serialisation_name = "div" + + + def _self_cls(self) -> type: + return Div + + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) / self.b.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Sub(Div(self.a.derivative(hash_value), self.b), + Div(Mul(self.a, self.b.derivative(hash_value)), Mul(self.b, self.b))) + + def _clean_ab(self, a, b): + if isinstance(a, AdditiveIdentity): + # Convert 0/b to 0 + return AdditiveIdentity() + + elif isinstance(a, MultiplicativeIdentity): + # Convert 1/b to inverse of b + return Inv(b) + + elif isinstance(b, MultiplicativeIdentity): + # Convert a/1 to a + return a + + elif isinstance(a, ConstantBase) and isinstance(b, ConstantBase): + # Convert constants "a"/"b" to "a/b" + return Constant(self.a.evaluate({}) / self.b.evaluate({}))._clean() + + + elif isinstance(a, Inv) and isinstance(b, Inv): + return Div(b.a, a.a) + + elif isinstance(a, Inv) and not isinstance(b, Inv): + return Inv(Mul(a.a, b)) + + elif not isinstance(a, Inv) and isinstance(b, Inv): + return Mul(a, b.a) + + elif a == b: + return MultiplicativeIdentity() + + elif isinstance(a, Pow) and a.a == b: + return Pow(b, a.power - 1) + + elif isinstance(b, Pow) and b.a == a: + return Pow(a, 1 - b.power) + + elif isinstance(a, Pow) and isinstance(b, Pow) and a.a == b.a: + return Pow(a.a, a.power - b.power) + + else: + return Div(a, b) + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Div(*BinaryOperation._deserialise_ab(parameters)) + + def _summary_open(self): + return "Div" + +class Pow(Operation): + + serialisation_name = "pow" + + def __init__(self, a: Operation, power: float): + self.a = a + self.power = power + + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) ** self.power + + def _derivative(self, hash_value: int) -> Operation: + if self.power == 0: + return AdditiveIdentity() + + elif self.power == 1: + return self.a._derivative(hash_value) + + else: + return Mul(Constant(self.power), Mul(Pow(self.a, self.power-1), self.a._derivative(hash_value))) + + def _clean(self) -> Operation: + a = self.a._clean() + + if self.power == 1: + return a + + elif self.power == 0: + return MultiplicativeIdentity() + + elif self.power == -1: + return Inv(a) + + else: + return Pow(a, self.power) + + + def _serialise_parameters(self) -> dict[str, Any]: + return {"a": Operation._serialise_json(self.a), + "power": self.power} + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Pow(Operation.deserialise_json(parameters["a"]), parameters["power"]) + + def summary(self, indent_amount: int=0, indent=" "): + return (f"{indent_amount*indent}Pow\n" + + self.a.summary(indent_amount+1, indent) + "\n" + + f"{(indent_amount+1)*indent}{self.power}\n" + + f"{indent_amount*indent})") + + def __eq__(self, other): + if isinstance(other, Pow): + return self.a == other.a and self.power == other.power + + + +# +# Matrix operations +# + +class Transpose(Operation): + """ Transpose operation - as per numpy""" + + serialisation_name = "transpose" + + def __init__(self, a: Operation, axes: tuple[int] | None = None): + self.a = a + self.axes = axes + + def evaluate(self, variables: dict[int, T]) -> T: + return np.transpose(self.a.evaluate(variables)) + + def _derivative(self, hash_value: int) -> Operation: + return Transpose(self.a.derivative(hash_value)) # TODO: Check! + + def _clean(self): + clean_a = self.a._clean() + return Transpose(clean_a) + + + def _serialise_parameters(self) -> dict[str, Any]: + if self.axes is None: + return { "a": self.a._serialise_json() } + else: + return { + "a": self.a._serialise_json(), + "axes": list(self.axes) + } + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + if "axes" in parameters: + return Transpose( + a=Operation.deserialise_json(parameters["a"]), + axes=tuple(parameters["axes"])) + else: + return Transpose( + a=Operation.deserialise_json(parameters["a"])) + + + def _summary_open(self): + return "Transpose" + + def __eq__(self, other): + if isinstance(other, Transpose): + return other.a == self.a + + +class Dot(BinaryOperation): + """ Dot product - backed by numpy's dot method""" + + serialisation_name = "dot" + + def evaluate(self, variables: dict[int, T]) -> T: + return dot(self.a.evaluate(variables), self.b.evaluate(variables)) + + def _derivative(self, hash_value: int) -> Operation: + return Add( + Dot(self.a, + self.b._derivative(hash_value)), + Dot(self.a._derivative(hash_value), + self.b)) + + def _clean_ab(self, a, b): + return Dot(a, b) # Do nothing for now + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return Dot(*BinaryOperation._deserialise_ab(parameters)) + + def _summary_open(self): + return "Dot" + + +# TODO: Add to base operation class, and to quantities +class MatMul(BinaryOperation): + """ Matrix multiplication, using __matmul__ dunder""" + + serialisation_name = "matmul" + + def evaluate(self, variables: dict[int, T]) -> T: + return self.a.evaluate(variables) @ self.b.evaluate(variables) + + def _derivative(self, hash_value: int) -> Operation: + return Add( + MatMul(self.a, + self.b._derivative(hash_value)), + MatMul(self.a._derivative(hash_value), + self.b)) + + def _clean_ab(self, a, b): + + if isinstance(a, AdditiveIdentity) or isinstance(b, AdditiveIdentity): + # Convert 0*b or a*0 to 0 + return AdditiveIdentity() + + elif isinstance(a, ConstantBase) and isinstance(b, ConstantBase): + # Convert constant "a"@"b" to "a@b" + return Constant(a.evaluate({}) @ b.evaluate({}))._clean() + + elif isinstance(a, Neg): + return Neg(Mul(a.a, b)) + + elif isinstance(b, Neg): + return Neg(Mul(a, b.a)) + + return MatMul(a, b) + + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return MatMul(*BinaryOperation._deserialise_ab(parameters)) + + def _summary_open(self): + return "MatMul" + +class TensorDot(Operation): + serialisation_name = "tensor_product" + + def __init__(self, a: Operation, b: Operation, a_index: int, b_index: int): + self.a = a + self.b = b + self.a_index = a_index + self.b_index = b_index + + def evaluate(self, variables: dict[int, T]) -> T: + return tensordot(self.a, self.b, self.a_index, self.b_index) + + + def _serialise_parameters(self) -> dict[str, Any]: + return { + "a": self.a._serialise_json(), + "b": self.b._serialise_json(), + "a_index": self.a_index, + "b_index": self.b_index } + + @staticmethod + def _deserialise(parameters: dict) -> "Operation": + return TensorDot(a = Operation.deserialise_json(parameters["a"]), + b = Operation.deserialise_json(parameters["b"]), + a_index=int(parameters["a_index"]), + b_index=int(parameters["b_index"])) + + def _summary_open(self): + return "TensorProduct" + + +_serialisable_classes = [AdditiveIdentity, MultiplicativeIdentity, Constant, + Variable, + Neg, Inv, + Add, Sub, Mul, Div, Pow, + Transpose, Dot, MatMul, TensorDot] + +_serialisation_lookup = {cls.serialisation_name: cls for cls in _serialisable_classes} + + +class UnitError(Exception): + """ Errors caused by unit specification not being correct """ + +def hash_data_via_numpy(*data: ArrayLike): + + md5_hash = hashlib.md5() + + for datum in data: + data_bytes = np.array(datum).tobytes() + md5_hash.update(data_bytes) + + # Hash function returns a hex string, we want an int + return int(md5_hash.hexdigest(), 16) + + + +##################################### +# # +# # +# # +# Quantities begin here # +# # +# # +# # +##################################### + + + +QuantityType = TypeVar("QuantityType") + + +class QuantityHistory: + """ Class that holds the information for keeping track of operations done on quantities """ + + def __init__(self, operation_tree: Operation, references: dict[int, "Quantity"]): + self.operation_tree = operation_tree + self.references = references + + self.reference_key_list = [key for key in self.references] + self.si_reference_values = {key: self.references[key].in_si() for key in self.references} + + def jacobian(self) -> list[Operation]: + """ Derivative of this quantity's operation history with respect to each of the references """ + + # Use the hash value to specify the variable of differentiation + return [self.operation_tree.derivative(key) for key in self.reference_key_list] + + def _recalculate(self): + """ Recalculate the value of this object - primary use case is for testing """ + return self.operation_tree.evaluate(self.references) + + def variance_propagate(self, quantity_units: Unit, covariances: dict[tuple[int, int]: "Quantity"] = {}): + """ Do standard error propagation to calculate the uncertainties associated with this quantity + + :param quantity_units: units in which the output should be calculated + :param covariances: off diagonal entries for the covariance matrix + """ + + if covariances: + raise NotImplementedError("User specified covariances not currently implemented") + + jacobian = self.jacobian() + + evaluated_jacobian = [entry.evaluate(self.references) for entry in jacobian] + + hash_values = [key for key in self.references] + output = None + + for hash_value, jac_component in zip(hash_values, evaluated_jacobian): + if output is None: + output = jac_component * (self.references[hash_value].variance * jac_component) + else: + output += jac_component * (self.references[hash_value].variance * jac_component) + + return output + + + @staticmethod + def variable(quantity: "Quantity"): + """ Create a history that starts with the provided data """ + return QuantityHistory(Variable(quantity.hash_value), {quantity.hash_value: quantity}) + + @staticmethod + def apply_operation(operation: type[Operation], *histories: "QuantityHistory", **extra_parameters) -> "QuantityHistory": + """ Apply an operation to the history + + This is slightly unsafe as it is possible to attempt to apply an n-ary operation to a number of trees other + than n, but it is relatively concise. Because it is concise we'll go with this for now and see if it causes + any problems down the line. It is a private static method to discourage misuse. + + """ + + # Copy references over, even though it overrides on collision, + # this should behave because only data based variables should be represented. + # Should not be a problem any more than losing histories + references = {} + for history in histories: + references.update(history.references) + + return QuantityHistory( + operation(*[history.operation_tree for history in histories], **extra_parameters), + references) + + def has_variance(self): + for key in self.references: + if self.references[key].has_variance: + return True + + return False + + def summary(self): + + variable_strings = [self.references[key].string_repr for key in self.references] + + s = "Variables: "+",".join(variable_strings) + s += "\n" + s += self.operation_tree.summary() + + return s + + +class Quantity[QuantityType]: + + + def __init__(self, + value: QuantityType, + units: Unit, + standard_error: QuantityType | None = None, + hash_seed = ""): + + self.value = value + """ Numerical value of this data, in the specified units""" + + self.units = units + """ Units of this data """ + + self._hash_seed = hash_seed + """ Retain this for copying operations""" + + self.hash_value = -1 + """ Hash based on value and uncertainty for data, -1 if it is a derived hash value """ + + self._variance = None + """ Contains the variance if it is data driven """ + + if standard_error is None: + self.hash_value = hash_data_via_numpy(hash_seed, value) + else: + self._variance = standard_error ** 2 + self.hash_value = hash_data_via_numpy(hash_seed, value, standard_error) + + self.history = QuantityHistory.variable(self) + + @property + def has_variance(self): + return self._variance is not None + + @property + def variance(self) -> "Quantity": + """ Get the variance of this object""" + if self._variance is None: + return Quantity(np.zeros_like(self.value), self.units**2) + else: + return Quantity(self._variance, self.units**2) + + def standard_deviation(self) -> "Quantity": + return self.variance ** 0.5 + + def in_units_of(self, units: Unit) -> QuantityType: + """ Get this quantity in other units """ + if self.units.equivalent(units): + return (self.units.scale / units.scale) * self.value + else: + raise UnitError(f"Target units ({units}) not compatible with existing units ({self.units}).") + + def to_units_of(self, new_units: Unit) -> "Quantity[QuantityType]": + new_value, new_error = self.in_units_of_with_standard_error(new_units) + return Quantity(value=new_value, + units=new_units, + standard_error=new_error, + hash_seed=self._hash_seed) + + def variance_in_units_of(self, units: Unit) -> QuantityType: + """ Get the variance of quantity in other units """ + variance = self.variance + if variance.units.equivalent(units): + return (variance.units.scale / units.scale) * variance + else: + raise UnitError(f"Target units ({units}) not compatible with existing units ({variance.units}).") + + def in_si(self): + si_units = self.units.si_equivalent() + return self.in_units_of(si_units) + + def in_units_of_with_standard_error(self, units): + variance = self.variance + units_squared = units**2 + + if variance.units.equivalent(units_squared): + + return self.in_units_of(units), np.sqrt(self.variance.in_units_of(units_squared)) + else: + raise UnitError(f"Target units ({units}) not compatible with existing units ({variance.units}).") + + def in_si_with_standard_error(self): + if self.has_variance: + return self.in_units_of_with_standard_error(self.units.si_equivalent()) + else: + return self.in_si(), None + + def __mul__(self: Self, other: ArrayLike | Self ) -> Self: + if isinstance(other, Quantity): + return DerivedQuantity( + self.value * other.value, + self.units * other.units, + history=QuantityHistory.apply_operation(Mul, self.history, other.history)) + + else: + return DerivedQuantity(self.value * other, self.units, + QuantityHistory( + Mul( + self.history.operation_tree, + Constant(other)), + self.history.references)) + + def __rmul__(self: Self, other: ArrayLike | Self): + if isinstance(other, Quantity): + return DerivedQuantity( + other.value * self.value, + other.units * self.units, + history=QuantityHistory.apply_operation( + Mul, + other.history, + self.history)) + + else: + return DerivedQuantity(other * self.value, self.units, + QuantityHistory( + Mul( + Constant(other), + self.history.operation_tree), + self.history.references)) + + + def __matmul__(self, other: ArrayLike | Self): + if isinstance(other, Quantity): + return DerivedQuantity( + self.value @ other.value, + self.units * other.units, + history=QuantityHistory.apply_operation( + MatMul, + self.history, + other.history)) + else: + return DerivedQuantity( + self.value @ other, + self.units, + QuantityHistory( + MatMul( + self.history.operation_tree, + Constant(other)), + self.history.references)) + + def __rmatmul__(self, other: ArrayLike | Self): + if isinstance(other, Quantity): + return DerivedQuantity( + other.value @ self.value, + other.units * self.units, + history=QuantityHistory.apply_operation( + MatMul, + other.history, + self.history)) + + else: + return DerivedQuantity(other @ self.value, self.units, + QuantityHistory( + MatMul( + Constant(other), + self.history.operation_tree), + self.history.references)) + + + def __truediv__(self: Self, other: float | Self) -> Self: + if isinstance(other, Quantity): + return DerivedQuantity( + self.value / other.value, + self.units / other.units, + history=QuantityHistory.apply_operation( + Div, + self.history, + other.history)) + + else: + return DerivedQuantity(self.value / other, self.units, + QuantityHistory( + Div( + Constant(other), + self.history.operation_tree), + self.history.references)) + + def __rtruediv__(self: Self, other: float | Self) -> Self: + if isinstance(other, Quantity): + return DerivedQuantity( + other.value / self.value, + other.units / self.units, + history=QuantityHistory.apply_operation( + Div, + other.history, + self.history + )) + + else: + return DerivedQuantity( + other / self.value, + self.units ** -1, + QuantityHistory( + Div( + Constant(other), + self.history.operation_tree), + self.history.references)) + + def __add__(self: Self, other: Self | ArrayLike) -> Self: + if isinstance(other, Quantity): + if self.units.equivalent(other.units): + return DerivedQuantity( + self.value + (other.value * other.units.scale) / self.units.scale, + self.units, + QuantityHistory.apply_operation( + Add, + self.history, + other.history)) + else: + raise UnitError(f"Units do not have the same dimensionality: {self.units} vs {other.units}") + + else: + raise UnitError(f"Cannot perform addition/subtraction non-quantity {type(other)} with quantity") + + # Don't need __radd__ because only quantity/quantity operations should be allowed + + def __neg__(self): + return DerivedQuantity(-self.value, self.units, + QuantityHistory.apply_operation( + Neg, + self.history + )) + + def __sub__(self: Self, other: Self | ArrayLike) -> Self: + return self + (-other) + + def __rsub__(self: Self, other: Self | ArrayLike) -> Self: + return (-self) + other + + def __pow__(self: Self, other: int | float): + return DerivedQuantity(self.value ** other, + self.units ** other, + QuantityHistory( + Pow( + self.history.operation_tree, + other), + self.history.references)) + + @staticmethod + def _array_repr_format(arr: np.ndarray): + """ Format the array """ + order = len(arr.shape) + reshaped = arr.reshape(-1) + if len(reshaped) <= 2: + numbers = ",".join([f"{n}" for n in reshaped]) + else: + numbers = f"{reshaped[0]} ... {reshaped[-1]}" + + # if len(reshaped) <= 4: + # numbers = ",".join([f"{n}" for n in reshaped]) + # else: + # numbers = f"{reshaped[0]}, {reshaped[1]} ... {reshaped[-2]}, {reshaped[-1]}" + + return "["*order + numbers + "]"*order + + def __repr__(self): + + if isinstance(self.units, NamedUnit): + + value = self.value + error = self.standard_deviation().in_units_of(self.units) + unit_string = self.units.symbol + + else: + value, error = self.in_si_with_standard_error() + unit_string = self.units.dimensions.si_repr() + + if isinstance(self.value, np.ndarray): + # Get the array in short form + numeric_string = self._array_repr_format(value) + + if self.has_variance: + numeric_string += " ± " + self._array_repr_format(error) + + else: + numeric_string = f"{value}" + if self.has_variance: + numeric_string += f" ± {error}" + + return numeric_string + " " + unit_string + + @staticmethod + def parse(number_or_string: str | ArrayLike, unit: str, absolute_temperature: False): + pass + + @property + def string_repr(self): + return str(self.hash_value) + + +class NamedQuantity[QuantityType](Quantity[QuantityType]): + def __init__(self, + name: str, + value: QuantityType, + units: Unit, + standard_error: QuantityType | None = None): + + super().__init__(value, units, standard_error=standard_error, hash_seed=name) + self.name = name + + def __repr__(self): + return f"[{self.name}] " + super().__repr__() + + def to_units_of(self, new_units: Unit) -> "NamedQuantity[QuantityType]": + new_value, new_error = self.in_units_of_with_standard_error(new_units) + return NamedQuantity(value=new_value, + units=new_units, + standard_error=new_error, + name=self.name) + + def with_standard_error(self, standard_error: Quantity): + if standard_error.units.equivalent(self.units): + return NamedQuantity( + value=self.value, + units=self.units, + standard_error=standard_error.in_units_of(self.units), + name=self.name) + + else: + raise UnitError(f"Standard error units ({standard_error.units}) " + f"are not compatible with value units ({self.units})") + + + @property + def string_repr(self): + return self.name + +class DerivedQuantity[QuantityType](Quantity[QuantityType]): + def __init__(self, value: QuantityType, units: Unit, history: QuantityHistory): + super().__init__(value, units, standard_error=None) + + self.history = history + self._variance_cache = None + self._has_variance = history.has_variance() + + + def to_units_of(self, new_units: Unit) -> "Quantity[QuantityType]": + # TODO: Lots of tests needed for this + return DerivedQuantity( + value=self.in_units_of(new_units), + units=new_units, + history=self.history) + + @property + def has_variance(self): + return self._has_variance + + @property + def variance(self) -> Quantity: + if self._variance_cache is None: + self._variance_cache = self.history.variance_propagate(self.units) + + return self._variance_cache diff --git a/sasdata/quantities/quantity_error_tests.py b/sasdata/quantities/quantity_error_tests.py new file mode 100644 index 0000000..e8e9378 --- /dev/null +++ b/sasdata/quantities/quantity_error_tests.py @@ -0,0 +1,154 @@ +from sasdata.quantities import units +from sasdata.quantities.quantity import NamedQuantity +import pytest +import numpy as np + +@pytest.mark.parametrize("x_err, y_err, x_units, y_units", + [(1, 1, units.meters, units.meters), + (1, 1, units.centimeters, units.centimeters), + (1, 2, units.meters, units.millimeters)]) +def test_addition_propagation(x_err, y_err, x_units, y_units): + """ Test that errors in addition of independent variables works with different units in the mix""" + + expected_err = np.sqrt((x_err*x_units.scale)**2 + (y_err*y_units.scale)**2) + + x = NamedQuantity("x", 0, x_units, standard_error=x_err) + y = NamedQuantity("y", 0, y_units, standard_error=y_err) + + _, err = (x + y).in_si_with_standard_error() + + assert err == pytest.approx(expected_err, abs=1e-8) + +@pytest.mark.parametrize("x_val, y_val, x_units, y_units", + [(1, 1, units.meters, units.meters), + (1, 1, units.centimeters, units.centimeters), + (2, 2, units.meters, units.meters), + (1, 2, units.centimeters, units.centimeters), + (1, 2, units.meters, units.millimeters), + (3, 4, units.milliseconds, units.microseconds), + (0, 1, units.meters, units.meters)]) +def test_asymmetry_propagation(x_val, y_val, x_units, y_units): + + x = NamedQuantity("x", x_val, x_units, standard_error=np.sqrt(x_val)) + y = NamedQuantity("y", y_val, y_units, standard_error=np.sqrt(y_val)) + + x_si, x_err = x.in_si_with_standard_error() + y_si, y_err = y.in_si_with_standard_error() + + numerator = x-y + denominator = x+y + a = numerator/denominator + + # Check numerator and denominator + expected_error = np.sqrt(x_err ** 2 + y_err ** 2) + + value, error = numerator.in_si_with_standard_error() + assert error == pytest.approx(expected_error, rel=1e-6) + + value, error = denominator.in_si_with_standard_error() + assert error == pytest.approx(expected_error, rel=1e-6) + + # check whole thing + value, error = a.in_si_with_standard_error() + expected_error = (2 / (x_si + y_si)**2) * np.sqrt((x_err*y_si)**2 + (y_err*x_si)**2) + assert error == pytest.approx(expected_error, rel=1e-6) + +@pytest.mark.parametrize("x_val, y_val, x_units, y_units", + [(1, 1, units.meters, units.meters), + (1, 1, units.centimeters, units.centimeters), + (2, 2, units.meters, units.meters), + (1, 2, units.centimeters, units.centimeters), + (1, 2, units.meters, units.millimeters), + (3, 4, units.milliseconds, units.microseconds), + (0, 1, units.meters, units.meters)]) +def test_power_propagation(x_val, y_val, x_units, y_units): + + x = NamedQuantity("x", x_val, x_units, standard_error=np.sqrt(x_val)) + y = NamedQuantity("y", y_val, y_units, standard_error=np.sqrt(y_val)) + + x_si, x_err = x.in_si_with_standard_error() + y_si, y_err = y.in_si_with_standard_error() + + x_var = x_err ** 2 + y_var = y_err ** 2 + + z = (x*y)**3 + + # check whole thing + value, error = z.in_si_with_standard_error() + expected_variance = 9*((x_si*y_si)**4)*(x_var*y_si*y_si + x_si*x_si*y_var) + assert error == pytest.approx(np.sqrt(expected_variance), rel=1e-6) + +@pytest.mark.parametrize("k", [0.1, 0.5, 1, 2, 10]) +@pytest.mark.parametrize("x_val, y_val, x_units, y_units", + [(1, 1, units.meters, units.meters), + (1, 1, units.centimeters, units.centimeters), + (2, 2, units.meters, units.meters), + (1, 2, units.centimeters, units.centimeters), + (1, 2, units.meters, units.millimeters), + (3, 4, units.milliseconds, units.microseconds), + (0, 1, units.meters, units.meters), + (0, 0, units.meters, units.meters)]) +def test_complex_power_propagation(x_val, y_val, x_units, y_units, k): + + x = NamedQuantity("x", x_val, x_units, standard_error=np.sqrt(k*x_val)) + y = NamedQuantity("y", y_val, y_units, standard_error=np.sqrt(k*y_val)) + + x_si, x_err = x.in_si_with_standard_error() + y_si, y_err = y.in_si_with_standard_error() + + x_var = x_err ** 2 + y_var = y_err ** 2 + + z = (x+y)**3 + x**3 + y**3 + + value, error = z.in_si_with_standard_error() + expected_variance = \ + 9*x_var*(x_si**2 + (x_si+y_si)**2)**2 + \ + 9*y_var*(y_si**2 + (x_si+y_si)**2)**2 + + assert error == pytest.approx(np.sqrt(expected_variance), rel=1e-6) + +@pytest.mark.parametrize("k_x", [0.1, 0.5, 1, 2, 10]) +@pytest.mark.parametrize("k_y", [0.1, 0.5, 1, 2, 10]) +@pytest.mark.parametrize("x_val, y_val, x_units, y_units", + [(1, 1, units.meters, units.meters), + (1, 1, units.centimeters, units.centimeters), + (2, 2, units.meters, units.meters), + (1, 2, units.centimeters, units.centimeters), + (1, 2, units.meters, units.millimeters), + (3, 4, units.milliseconds, units.microseconds), + (0, 1, units.meters, units.meters), + (0, 0, units.meters, units.meters)]) +def test_complex_propagation(x_val, y_val, x_units, y_units, k_x, k_y): + + x = NamedQuantity("x", x_val, x_units, standard_error=np.sqrt(k_x*x_val)) + y = NamedQuantity("y", y_val, y_units, standard_error=np.sqrt(k_y*y_val)) + + cx = NamedQuantity("cx", 1.7, x_units) + cy = NamedQuantity("cy", 1.2, y_units) + c0 = 4*NamedQuantity("c0", value=7, units=units.none) + + cx_si = cx.in_si() + cy_si = cy.in_si() + + c0_si = c0.in_si() + + x_si, x_err = x.in_si_with_standard_error() + y_si, y_err = y.in_si_with_standard_error() + + x_var = x_err ** 2 + y_var = y_err ** 2 + + z = (((x-cx)**4 + (y-cy)**4)**(1/4)) + c0*(-x-y) + + value, error = z.in_si_with_standard_error() + + denom_factor = ((x_si - cx_si)**4 + (y_si - cy_si)**4)**(-3/4) + x_num = (cx_si - x_si)**3 + y_num = (cy_si - y_si)**3 + + expected_variance = x_var*(c0_si + x_num*denom_factor)**2 + y_var*(c0_si + y_num*denom_factor)**2 + + assert error == pytest.approx(np.sqrt(expected_variance), rel=1e-8) + diff --git a/sasdata/quantities/quantity_examples.py b/sasdata/quantities/quantity_examples.py new file mode 100644 index 0000000..8c505e5 --- /dev/null +++ b/sasdata/quantities/quantity_examples.py @@ -0,0 +1,8 @@ +from sasdata.quantities.quantity import Quantity, NamedQuantity +from sasdata.quantities import units + +x = NamedQuantity("x", 1, units.meters, standard_error=1) +y = NamedQuantity("y", 1, units.decimeters, standard_error=1) + +print(x+y) +print((x+y).to_units_of(units.centimeters)) \ No newline at end of file diff --git a/sasdata/quantities/si.py b/sasdata/quantities/si.py new file mode 100644 index 0000000..871b6ee --- /dev/null +++ b/sasdata/quantities/si.py @@ -0,0 +1,119 @@ +""" + +This file is autogenerated! + +Do not edit by hand, instead edit the files that build it (_build_tables.py) + + + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + + + +""" + +from sasdata.quantities.units import meters +from sasdata.quantities.units import seconds +from sasdata.quantities.units import amperes +from sasdata.quantities.units import kelvin +from sasdata.quantities.units import hertz +from sasdata.quantities.units import newtons +from sasdata.quantities.units import pascals +from sasdata.quantities.units import joules +from sasdata.quantities.units import watts +from sasdata.quantities.units import coulombs +from sasdata.quantities.units import volts +from sasdata.quantities.units import ohms +from sasdata.quantities.units import farads +from sasdata.quantities.units import siemens +from sasdata.quantities.units import webers +from sasdata.quantities.units import tesla +from sasdata.quantities.units import henry +from sasdata.quantities.units import kilograms + +all_si = [ + meters, + seconds, + amperes, + kelvin, + hertz, + newtons, + pascals, + joules, + watts, + coulombs, + volts, + ohms, + farads, + siemens, + webers, + tesla, + henry, + kilograms, +] diff --git a/sasdata/quantities/test_numerical_encoding.py b/sasdata/quantities/test_numerical_encoding.py new file mode 100644 index 0000000..80cfbad --- /dev/null +++ b/sasdata/quantities/test_numerical_encoding.py @@ -0,0 +1,68 @@ +""" Tests for the encoding and decoding of numerical data""" + +import numpy as np +import pytest + +from sasdata.quantities.numerical_encoding import numerical_encode, numerical_decode + + +@pytest.mark.parametrize("value", [-100.0, -10.0, -1.0, 0.0, 0.5, 1.0, 10.0, 100.0, 1e100]) +def test_float_encode_decode(value: float): + + assert isinstance(value, float) # Make sure we have the right inputs + + encoded = numerical_encode(value) + decoded = numerical_decode(encoded) + + assert isinstance(decoded, float) + assert value == decoded + +@pytest.mark.parametrize("value", [-100, -10, -1, 0, 1, 10, 100, 1000000000000000000000000000000000]) +def test_int_encode_decode(value: int): + + assert isinstance(value, int) # Make sure we have the right inputs + + encoded = numerical_encode(value) + decoded = numerical_decode(encoded) + + assert isinstance(decoded, int) + assert value == decoded + +@pytest.mark.parametrize("shape", [ + (2,3,4), + (1,2), + (10,5,10), + (1,), + (4,), + (0, ) ]) +def test_numpy_float_encode_decode(shape): + np.random.seed(1776) + test_matrix = np.random.rand(*shape) + + encoded = numerical_encode(test_matrix) + decoded = numerical_decode(encoded) + + assert decoded.dtype == test_matrix.dtype + assert decoded.shape == test_matrix.shape + assert np.all(decoded == test_matrix) + +@pytest.mark.parametrize("dtype", [int, float, complex]) +def test_numpy_dtypes_encode_decode(dtype): + test_matrix = np.zeros((3,3), dtype=dtype) + + encoded = numerical_encode(test_matrix) + decoded = numerical_decode(encoded) + + assert decoded.dtype == test_matrix.dtype + +@pytest.mark.parametrize("dtype", [int, float, complex]) +@pytest.mark.parametrize("shape, n, m", [ + ((8, 8), (1,3,5),(2,5,7)), + ((6, 8), (1,0,5),(0,5,0)), + ((6, 1), (1, 0, 5), (0, 0, 0)), +]) +def test_coo_matrix_encode_decode(shape, n, m, dtype): + + i_indices = + + values = np.arange(10) \ No newline at end of file diff --git a/sasdata/quantities/unicode_superscript.py b/sasdata/quantities/unicode_superscript.py new file mode 100644 index 0000000..81f90f2 --- /dev/null +++ b/sasdata/quantities/unicode_superscript.py @@ -0,0 +1,12 @@ + +_ascii_version = "0123456789-" +_unicode_version = "⁰¹²³⁴⁵⁶⁷⁸⁹⁻" + +def int_as_unicode_superscript(number: int): + string = str(number) + + for old, new in zip(_ascii_version, _unicode_version): + string = string.replace(old, new) + + return string + diff --git a/sasdata/quantities/unit_formatting.py b/sasdata/quantities/unit_formatting.py new file mode 100644 index 0000000..59aa3bc --- /dev/null +++ b/sasdata/quantities/unit_formatting.py @@ -0,0 +1,12 @@ + +import numpy as np + +def solve_contributions(target: float, scales: list[float], max_power: int=4, tol=1e-5): + log_target = np.log10(target) + log_scale_pairs = sorted([(i, np.log10(scale)) for i, scale in enumerate(scales)], key=lambda x: x[1]) + + ordering = [i for i, _ in log_scale_pairs] + log_scale = [l for _, l in log_scale_pairs] + + powers = [0 for _ in scales] + diff --git a/sasdata/quantities/unit_parser.py b/sasdata/quantities/unit_parser.py new file mode 100644 index 0000000..082e6e3 --- /dev/null +++ b/sasdata/quantities/unit_parser.py @@ -0,0 +1,179 @@ +from sasdata.quantities.units import Dimensions, NamedUnit, Unit, symbol_lookup, unit_groups, UnitGroup +from re import findall, fullmatch + +# TODO: This shouldn't be in this file but I don't want to edit Lucas' code before he is finished. + +all_units_groups = [group.units for group in unit_groups.values()] +unit_groups_by_dimension_hash = {hash(group.units[0].dimensions): group for group in unit_groups.values()} +all_units: list[NamedUnit] = [] +for group in all_units_groups: + all_units.extend(group) + +def split_unit_str(unit_str: str) -> list[str]: + """Separate the letters from the numbers in unit_str""" + return findall(r'[A-Za-zΩ%Å]+|[-\d]+|/', unit_str) + +def validate_unit_str(unit_str: str) -> bool: + """Validate whether unit_str is valid. This doesn't mean that the unit specified in unit_str exists but rather it + only consists of letters, and numbers as a unit string should.""" + return not fullmatch(r'[A-Za-zΩ%Å^1-9\-\+/\ \.]+', unit_str) is None + +def parse_single_unit(unit_str: str, unit_group: UnitGroup | None = None, longest_unit: bool = True) -> tuple[Unit | None, str]: + """Attempts to find a single unit for unit_str. Return this unit, and the remaining string in a tuple. If a unit + cannot be parsed, the unit will be None, and the remaining string will be the entire unit_str. + + The shortest_unit parameter specifies how to resolve ambiguities. If it is true, then it will parse the longest unit + available. Otherwise, it will stop parsing as soon as it has found any unit. + + If unit_group is set, it will only try to parse units within that group. This is useful for resolving ambiguities. + """ + current_unit = '' + string_pos = 0 + if unit_group is None: + lookup_dict = symbol_lookup + else: + lookup_dict = dict([(name, unit) for name, unit in symbol_lookup.items() if unit in unit_group.units]) + for next_char in unit_str: + potential_unit_str = current_unit + next_char + potential_symbols = [symbol for symbol in lookup_dict.keys() if symbol.startswith(potential_unit_str)] + if len(potential_symbols) == 0: + break + string_pos += 1 + current_unit = potential_unit_str + if not longest_unit and current_unit in lookup_dict.keys(): + break + if current_unit == '': + return None, unit_str + remaining_str = unit_str[string_pos::] + return lookup_dict[current_unit], remaining_str + +def parse_unit_strs(unit_str: str, current_units: list[Unit] | None=None, longest_unit: bool = True) -> list[Unit]: + """Recursively parse units from unit_str until no more characters are present.""" + if current_units is None: + current_units = [] + if unit_str == '': + return current_units + parsed_unit, remaining_str = parse_single_unit(unit_str, longest_unit=longest_unit) + if parsed_unit is not None: + current_units += [parsed_unit] + return parse_unit_strs(remaining_str, current_units, longest_unit) + else: + raise ValueError(f'Could not interpret {remaining_str}') + +# Its probably useful to work out the unit first, and then later work out if a named unit exists for it. Hence why there +# are two functions. + +def parse_unit_stack(unit_str: str, longest_unit: bool = True) -> list[Unit]: + """Split unit_str into a stack of parsed units.""" + unit_stack: list[Unit] = [] + split_str = split_unit_str(unit_str) + inverse_next_unit = False + for token in split_str: + try: + if token == '/': + inverse_next_unit = True + continue + power = int(token) + to_modify = unit_stack[-1] + modified = to_modify ** power + # modified = unit_power(to_modify, power) + unit_stack[-1] = modified + except ValueError: + new_units = parse_unit_strs(token, None, longest_unit) + if inverse_next_unit: + # TODO: Assume the power is going to be -1. This might not be true. + power = -1 + new_units[0] = new_units[0] ** power + # new_units[0] = unit_power(new_units[0], power) + unit_stack += new_units + # This error will happen if it tries to read a modifier but there are no units on the stack. We will just have + # to ignore it. Strings being parsed shouldn't really have it anyway (e.g. -1m). + except IndexError: + pass + return unit_stack + +def parse_unit(unit_str: str, longest_unit: bool = True) -> Unit: + """Parse unit_str into a unit.""" + try: + if not validate_unit_str(unit_str): + raise ValueError('unit_str contains forbidden characters.') + parsed_unit = Unit(1, Dimensions()) + unit_stack = parse_unit_stack(unit_str, longest_unit) + for unit in unit_stack: + # parsed_unit = combine_units(parsed_unit, unit) + parsed_unit *= unit + return parsed_unit + except KeyError: + raise ValueError('Unit string contains an unrecognised pattern.') + +def parse_unit_from_group(unit_str: str, from_group: UnitGroup) -> Unit | None: + """Tries to use the given unit group to resolve ambiguities. Parse a unit twice with different options, and returns + whatever conforms to the unit group.""" + longest_parsed_unit = parse_unit(unit_str, True) + shortest_parsed_unit = parse_unit(unit_str, False) + if longest_parsed_unit in from_group.units: + return longest_parsed_unit + elif shortest_parsed_unit in from_group.units: + return shortest_parsed_unit + else: + return None + +def parse_named_unit(unit_string: str, rtol: float=1e-14) -> NamedUnit: + """Parses unit into a named unit. Parses unit into a Unit if it is not already, and then finds an equivaelent named + unit. Please note that this might not be the expected unit from the string itself. E.g. 'kgm/2' will become + newtons. + + :param unit_string: string describing the units, e.g. km/s + :param rtol: relative tolerance for matching scale factors + """ + unit = parse_unit(unit_string) + named_unit = find_named_unit(unit) + if named_unit is None: + raise ValueError(f"We don't have a for this unit: '{unit}'") + else: + return named_unit + +def find_named_unit(unit: Unit, rtol: float=1e-14) -> NamedUnit | None: + """ Find a named unit matching the one provided """ + dimension_hash = hash(unit.dimensions) + if dimension_hash in unit_groups_by_dimension_hash: + unit_group = unit_groups_by_dimension_hash[hash(unit.dimensions)] + + for named_unit in unit_group.units: + if abs(named_unit.scale - unit.scale) < rtol*named_unit.scale: + return named_unit + + return None + + +def parse_named_unit_from_group(unit_str: str, from_group: UnitGroup) -> NamedUnit: + """Parses unit_str into a named unit. The named unit found must be part of from_group. If two units are found, the + unit that is present in from_group is returned. This is useful in cases of ambiguities.""" + parsed_unit = parse_unit_from_group(unit_str, from_group) + if parsed_unit is None: + raise ValueError('That unit cannot be parsed from the specified group.') + return find_named_unit(parsed_unit) + +def parse(string: str, + name_lookup: bool = True, + longest_unit: bool = True, + lookup_rtol: float = 1e-14): + + unit = parse_unit(string, longest_unit=longest_unit) + if name_lookup: + named = find_named_unit(unit, rtol=lookup_rtol) + if named is not None: + return named + + return unit + + +if __name__ == "__main__": + to_parse = input('Enter a unit to parse: ') + try: + generic_unit = parse_unit(to_parse) + print(f'Generic Unit: {generic_unit}') + named_unit = find_named_unit(generic_unit) + print(f'Named Unit: {named_unit}') + except ValueError: + print('There is no named unit available.') diff --git a/sasdata/quantities/units.py b/sasdata/quantities/units.py new file mode 100644 index 0000000..d496e41 --- /dev/null +++ b/sasdata/quantities/units.py @@ -0,0 +1,3495 @@ +""" + +This file is autogenerated! + +Do not edit by hand, instead edit the files that build it (_build_tables.py, _units_base.py) + + + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + + + +""" + +# +# Included from _units_base.py +# + +from dataclasses import dataclass +from typing import Sequence, Self, TypeVar +from fractions import Fraction + +import numpy as np + +from sasdata.quantities.unicode_superscript import int_as_unicode_superscript + +class DimensionError(Exception): + pass + +class Dimensions: + """ + + Note that some SI Base units are not useful from the perspecive of the sasview project, and make things + behave badly. In particular: moles and angular measures are dimensionless, and candelas are really a weighted + measure of power. + + We do however track angle and amount, because its really useful for formatting units + + """ + def __init__(self, + length: int = 0, + time: int = 0, + mass: int = 0, + current: int = 0, + temperature: int = 0, + moles_hint: int = 0, + angle_hint: int = 0): + + self.length = length + self.time = time + self.mass = mass + self.current = current + self.temperature = temperature + self.moles_hint = moles_hint + self.angle_hint = angle_hint + + @property + def is_dimensionless(self): + """ Is this dimension dimensionless (ignores moles_hint and angle_hint) """ + return self.length == 0 and self.time == 0 and self.mass == 0 and self.current == 0 and self.temperature == 0 + + def __mul__(self: Self, other: Self): + + 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, + self.moles_hint + other.moles_hint, + self.angle_hint + other.angle_hint) + + def __truediv__(self: Self, other: Self): + + 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, + self.moles_hint - other.moles_hint, + self.angle_hint - other.angle_hint) + + def __pow__(self, power: int | float): + + if not isinstance(power, (int, float)): + return NotImplemented + + frac = Fraction(power).limit_denominator(500) # Probably way bigger than needed, 10 would probably be fine + denominator = frac.denominator + numerator = frac.numerator + + # Throw errors if dimension is not a multiple of the denominator + + if self.length % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with length dimensionality {self.length}") + + if self.time % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with time dimensionality {self.time}") + + if self.mass % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with mass dimensionality {self.mass}") + + if self.current % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with current dimensionality {self.current}") + + if self.temperature % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with temperature dimensionality {self.temperature}") + + if self.moles_hint % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with moles hint dimensionality of {self.moles_hint}") + + if self.angle_hint % denominator != 0: + raise DimensionError(f"Cannot apply power of {frac} to unit with angle hint dimensionality of {self.angle_hint}") + + return Dimensions( + (self.length * numerator) // denominator, + (self.time * numerator) // denominator, + (self.mass * numerator) // denominator, + (self.current * numerator) // denominator, + (self.temperature * numerator) // denominator, + (self.moles_hint * numerator) // denominator, + (self.angle_hint * numerator) // denominator) + + def __eq__(self: Self, other: Self): + if isinstance(other, Dimensions): + return (self.length == other.length and + self.time == other.time and + self.mass == other.mass and + self.current == other.current and + self.temperature == other.temperature and + self.moles_hint == other.moles_hint and + self.angle_hint == other.angle_hint) + + return NotImplemented + + def __hash__(self): + """ Unique representation of units using Godel like encoding""" + + two_powers = 0 + if self.length < 0: + two_powers += 1 + + if self.time < 0: + two_powers += 2 + + if self.mass < 0: + two_powers += 4 + + if self.current < 0: + two_powers += 8 + + if self.temperature < 0: + two_powers += 16 + + if self.moles_hint < 0: + two_powers += 32 + + if self.angle_hint < 0: + two_powers += 64 + + return 2**two_powers * 3**abs(self.length) * 5**abs(self.time) * \ + 7**abs(self.mass) * 11**abs(self.current) * 13**abs(self.temperature) * \ + 17**abs(self.moles_hint) * 19**abs(self.angle_hint) + + def __repr__(self): + tokens = [] + for name, size in [ + ("length", self.length), + ("time", self.time), + ("mass", self.mass), + ("current", self.current), + ("temperature", self.temperature), + ("amount", self.moles_hint), + ("angle", self.angle_hint)]: + + if size == 0: + pass + elif size == 1: + tokens.append(f"{name}") + else: + tokens.append(f"{name}{int_as_unicode_superscript(size)}") + + return ' '.join(tokens) + + def si_repr(self): + tokens = [] + for name, size in [ + ("kg", self.mass), + ("m", self.length), + ("s", self.time), + ("A", self.current), + ("K", self.temperature), + ("mol", self.moles_hint)]: + + if size == 0: + pass + elif size == 1: + tokens.append(f"{name}") + else: + tokens.append(f"{name}{int_as_unicode_superscript(size)}") + + match self.angle_hint: + case 0: + pass + case 2: + tokens.append("sr") + case -2: + tokens.append("sr" + int_as_unicode_superscript(-1)) + case _: + tokens.append("rad" + int_as_unicode_superscript(self.angle_hint)) + + return ''.join(tokens) + + +class Unit: + def __init__(self, + si_scaling_factor: float, + dimensions: Dimensions): + + self.scale = si_scaling_factor + self.dimensions = dimensions + + def _components(self, tokens: Sequence["UnitToken"]): + pass + + def __mul__(self: Self, other: "Unit"): + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale * other.scale, self.dimensions * other.dimensions) + + def __truediv__(self: Self, other: "Unit"): + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale / other.scale, self.dimensions / other.dimensions) + + def __rtruediv__(self: Self, other: "Unit"): + if isinstance(other, Unit): + return Unit(other.scale / self.scale, other.dimensions / self.dimensions) + elif isinstance(other, (int, float)): + return Unit(other / self.scale, self.dimensions ** -1) + else: + return NotImplemented + + def __pow__(self, power: int | float): + if not isinstance(power, int | float): + return NotImplemented + + return Unit(self.scale**power, self.dimensions**power) + + + def equivalent(self: Self, other: "Unit"): + return self.dimensions == other.dimensions + + def __eq__(self: Self, other: "Unit"): + return self.equivalent(other) and np.abs(np.log(self.scale/other.scale)) < 1e-5 + + def si_equivalent(self): + """ Get the SI unit corresponding to this unit""" + return Unit(1, self.dimensions) + + def _format_unit(self, format_process: list["UnitFormatProcessor"]): + for processor in format_process: + pass + + def __repr__(self): + if self.scale == 1: + # We're in SI + return self.dimensions.si_repr() + + else: + return f"Unit[{self.scale}, {self.dimensions}]" + + @staticmethod + def parse(unit_string: str) -> "Unit": + pass + +class NamedUnit(Unit): + """ Units, but they have a name, and a symbol + + :si_scaling_factor: Number of these units per SI equivalent + :param dimensions: Dimensions object representing the dimensionality of these units + :param name: Name of unit - string without unicode + :param ascii_symbol: Symbol for unit without unicode + :param symbol: Unicode symbol + """ + def __init__(self, + si_scaling_factor: float, + dimensions: Dimensions, + name: str | None = None, + ascii_symbol: str | None = None, + symbol: str | None = None): + + super().__init__(si_scaling_factor, dimensions) + self.name = name + self.ascii_symbol = ascii_symbol + self.symbol = symbol + + def __repr__(self): + return self.name + +# +# Parsing plan: +# Require unknown amounts of units to be explicitly positive or negative? +# +# + + + +@dataclass +class ProcessedUnitToken: + """ Mid processing representation of formatted units """ + base_string: str + exponent_string: str + latex_exponent_string: str + exponent: int + +class UnitFormatProcessor: + """ Represents a step in the unit processing pipeline""" + def apply(self, scale, dimensions) -> tuple[ProcessedUnitToken, float, Dimensions]: + """ This will be called to deal with each processing stage""" + +class RequiredUnitFormatProcessor(UnitFormatProcessor): + """ This unit is required to exist in the formatting """ + def __init__(self, unit: Unit, power: int = 1): + self.unit = unit + self.power = power + def apply(self, scale, dimensions) -> tuple[float, Dimensions, ProcessedUnitToken]: + new_scale = scale / (self.unit.scale * self.power) + new_dimensions = self.unit.dimensions / (dimensions**self.power) + token = ProcessedUnitToken(self.unit, self.power) + + return new_scale, new_dimensions, token +class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): + """ This processor minimises the dimensionality of the unit by multiplying by as many + units of the specified type as needed """ + def __init__(self, unit: Unit): + self.unit = unit + + def apply(self, scale, dimensions) -> tuple[ProcessedUnitToken, float, Dimensions]: + pass + +class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): + pass + +class UnitGroup: + """ A group of units that all have the same dimensionality """ + def __init__(self, name: str, units: list[NamedUnit]): + self.name = name + self.units = sorted(units, key=lambda unit: unit.scale) + + + +# +# Specific units +# + +meters = NamedUnit(1, Dimensions(1, 0, 0, 0, 0, 0, 0),name='meters',ascii_symbol='m',symbol='m') +exameters = NamedUnit(1e+18, Dimensions(1, 0, 0, 0, 0, 0, 0),name='exameters',ascii_symbol='Em',symbol='Em') +petameters = NamedUnit(1000000000000000.0, Dimensions(1, 0, 0, 0, 0, 0, 0),name='petameters',ascii_symbol='Pm',symbol='Pm') +terameters = NamedUnit(1000000000000.0, Dimensions(1, 0, 0, 0, 0, 0, 0),name='terameters',ascii_symbol='Tm',symbol='Tm') +gigameters = NamedUnit(1000000000.0, Dimensions(1, 0, 0, 0, 0, 0, 0),name='gigameters',ascii_symbol='Gm',symbol='Gm') +megameters = NamedUnit(1000000.0, Dimensions(1, 0, 0, 0, 0, 0, 0),name='megameters',ascii_symbol='Mm',symbol='Mm') +kilometers = NamedUnit(1000.0, Dimensions(1, 0, 0, 0, 0, 0, 0),name='kilometers',ascii_symbol='km',symbol='km') +millimeters = NamedUnit(0.001, Dimensions(1, 0, 0, 0, 0, 0, 0),name='millimeters',ascii_symbol='mm',symbol='mm') +micrometers = NamedUnit(1e-06, Dimensions(1, 0, 0, 0, 0, 0, 0),name='micrometers',ascii_symbol='um',symbol='µm') +nanometers = NamedUnit(1e-09, Dimensions(1, 0, 0, 0, 0, 0, 0),name='nanometers',ascii_symbol='nm',symbol='nm') +picometers = NamedUnit(1e-12, Dimensions(1, 0, 0, 0, 0, 0, 0),name='picometers',ascii_symbol='pm',symbol='pm') +femtometers = NamedUnit(1e-15, Dimensions(1, 0, 0, 0, 0, 0, 0),name='femtometers',ascii_symbol='fm',symbol='fm') +attometers = NamedUnit(1e-18, Dimensions(1, 0, 0, 0, 0, 0, 0),name='attometers',ascii_symbol='am',symbol='am') +decimeters = NamedUnit(0.1, Dimensions(1, 0, 0, 0, 0, 0, 0),name='decimeters',ascii_symbol='dm',symbol='dm') +centimeters = NamedUnit(0.01, Dimensions(1, 0, 0, 0, 0, 0, 0),name='centimeters',ascii_symbol='cm',symbol='cm') +seconds = NamedUnit(1, Dimensions(0, 1, 0, 0, 0, 0, 0),name='seconds',ascii_symbol='s',symbol='s') +milliseconds = NamedUnit(0.001, Dimensions(0, 1, 0, 0, 0, 0, 0),name='milliseconds',ascii_symbol='ms',symbol='ms') +microseconds = NamedUnit(1e-06, Dimensions(0, 1, 0, 0, 0, 0, 0),name='microseconds',ascii_symbol='us',symbol='µs') +nanoseconds = NamedUnit(1e-09, Dimensions(0, 1, 0, 0, 0, 0, 0),name='nanoseconds',ascii_symbol='ns',symbol='ns') +picoseconds = NamedUnit(1e-12, Dimensions(0, 1, 0, 0, 0, 0, 0),name='picoseconds',ascii_symbol='ps',symbol='ps') +femtoseconds = NamedUnit(1e-15, Dimensions(0, 1, 0, 0, 0, 0, 0),name='femtoseconds',ascii_symbol='fs',symbol='fs') +attoseconds = NamedUnit(1e-18, Dimensions(0, 1, 0, 0, 0, 0, 0),name='attoseconds',ascii_symbol='as',symbol='as') +grams = NamedUnit(0.001, Dimensions(0, 0, 1, 0, 0, 0, 0),name='grams',ascii_symbol='g',symbol='g') +exagrams = NamedUnit(1000000000000000.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='exagrams',ascii_symbol='Eg',symbol='Eg') +petagrams = NamedUnit(1000000000000.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='petagrams',ascii_symbol='Pg',symbol='Pg') +teragrams = NamedUnit(1000000000.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='teragrams',ascii_symbol='Tg',symbol='Tg') +gigagrams = NamedUnit(1000000.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='gigagrams',ascii_symbol='Gg',symbol='Gg') +megagrams = NamedUnit(1000.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='megagrams',ascii_symbol='Mg',symbol='Mg') +kilograms = NamedUnit(1.0, Dimensions(0, 0, 1, 0, 0, 0, 0),name='kilograms',ascii_symbol='kg',symbol='kg') +milligrams = NamedUnit(1e-06, Dimensions(0, 0, 1, 0, 0, 0, 0),name='milligrams',ascii_symbol='mg',symbol='mg') +micrograms = NamedUnit(1e-09, Dimensions(0, 0, 1, 0, 0, 0, 0),name='micrograms',ascii_symbol='ug',symbol='µg') +nanograms = NamedUnit(1.0000000000000002e-12, Dimensions(0, 0, 1, 0, 0, 0, 0),name='nanograms',ascii_symbol='ng',symbol='ng') +picograms = NamedUnit(1e-15, Dimensions(0, 0, 1, 0, 0, 0, 0),name='picograms',ascii_symbol='pg',symbol='pg') +femtograms = NamedUnit(1e-18, Dimensions(0, 0, 1, 0, 0, 0, 0),name='femtograms',ascii_symbol='fg',symbol='fg') +attograms = NamedUnit(1.0000000000000001e-21, Dimensions(0, 0, 1, 0, 0, 0, 0),name='attograms',ascii_symbol='ag',symbol='ag') +amperes = NamedUnit(1, Dimensions(0, 0, 0, 1, 0, 0, 0),name='amperes',ascii_symbol='A',symbol='A') +exaamperes = NamedUnit(1e+18, Dimensions(0, 0, 0, 1, 0, 0, 0),name='exaamperes',ascii_symbol='EA',symbol='EA') +petaamperes = NamedUnit(1000000000000000.0, Dimensions(0, 0, 0, 1, 0, 0, 0),name='petaamperes',ascii_symbol='PA',symbol='PA') +teraamperes = NamedUnit(1000000000000.0, Dimensions(0, 0, 0, 1, 0, 0, 0),name='teraamperes',ascii_symbol='TA',symbol='TA') +gigaamperes = NamedUnit(1000000000.0, Dimensions(0, 0, 0, 1, 0, 0, 0),name='gigaamperes',ascii_symbol='GA',symbol='GA') +megaamperes = NamedUnit(1000000.0, Dimensions(0, 0, 0, 1, 0, 0, 0),name='megaamperes',ascii_symbol='MA',symbol='MA') +kiloamperes = NamedUnit(1000.0, Dimensions(0, 0, 0, 1, 0, 0, 0),name='kiloamperes',ascii_symbol='kA',symbol='kA') +milliamperes = NamedUnit(0.001, Dimensions(0, 0, 0, 1, 0, 0, 0),name='milliamperes',ascii_symbol='mA',symbol='mA') +microamperes = NamedUnit(1e-06, Dimensions(0, 0, 0, 1, 0, 0, 0),name='microamperes',ascii_symbol='uA',symbol='µA') +nanoamperes = NamedUnit(1e-09, Dimensions(0, 0, 0, 1, 0, 0, 0),name='nanoamperes',ascii_symbol='nA',symbol='nA') +picoamperes = NamedUnit(1e-12, Dimensions(0, 0, 0, 1, 0, 0, 0),name='picoamperes',ascii_symbol='pA',symbol='pA') +femtoamperes = NamedUnit(1e-15, Dimensions(0, 0, 0, 1, 0, 0, 0),name='femtoamperes',ascii_symbol='fA',symbol='fA') +attoamperes = NamedUnit(1e-18, Dimensions(0, 0, 0, 1, 0, 0, 0),name='attoamperes',ascii_symbol='aA',symbol='aA') +kelvin = NamedUnit(1, Dimensions(0, 0, 0, 0, 1, 0, 0),name='kelvin',ascii_symbol='K',symbol='K') +exakelvin = NamedUnit(1e+18, Dimensions(0, 0, 0, 0, 1, 0, 0),name='exakelvin',ascii_symbol='EK',symbol='EK') +petakelvin = NamedUnit(1000000000000000.0, Dimensions(0, 0, 0, 0, 1, 0, 0),name='petakelvin',ascii_symbol='PK',symbol='PK') +terakelvin = NamedUnit(1000000000000.0, Dimensions(0, 0, 0, 0, 1, 0, 0),name='terakelvin',ascii_symbol='TK',symbol='TK') +gigakelvin = NamedUnit(1000000000.0, Dimensions(0, 0, 0, 0, 1, 0, 0),name='gigakelvin',ascii_symbol='GK',symbol='GK') +megakelvin = NamedUnit(1000000.0, Dimensions(0, 0, 0, 0, 1, 0, 0),name='megakelvin',ascii_symbol='MK',symbol='MK') +kilokelvin = NamedUnit(1000.0, Dimensions(0, 0, 0, 0, 1, 0, 0),name='kilokelvin',ascii_symbol='kK',symbol='kK') +millikelvin = NamedUnit(0.001, Dimensions(0, 0, 0, 0, 1, 0, 0),name='millikelvin',ascii_symbol='mK',symbol='mK') +microkelvin = NamedUnit(1e-06, Dimensions(0, 0, 0, 0, 1, 0, 0),name='microkelvin',ascii_symbol='uK',symbol='µK') +nanokelvin = NamedUnit(1e-09, Dimensions(0, 0, 0, 0, 1, 0, 0),name='nanokelvin',ascii_symbol='nK',symbol='nK') +picokelvin = NamedUnit(1e-12, Dimensions(0, 0, 0, 0, 1, 0, 0),name='picokelvin',ascii_symbol='pK',symbol='pK') +femtokelvin = NamedUnit(1e-15, Dimensions(0, 0, 0, 0, 1, 0, 0),name='femtokelvin',ascii_symbol='fK',symbol='fK') +attokelvin = NamedUnit(1e-18, Dimensions(0, 0, 0, 0, 1, 0, 0),name='attokelvin',ascii_symbol='aK',symbol='aK') +hertz = NamedUnit(1, Dimensions(0, -1, 0, 0, 0, 0, 0),name='hertz',ascii_symbol='Hz',symbol='Hz') +exahertz = NamedUnit(1e+18, Dimensions(0, -1, 0, 0, 0, 0, 0),name='exahertz',ascii_symbol='EHz',symbol='EHz') +petahertz = NamedUnit(1000000000000000.0, Dimensions(0, -1, 0, 0, 0, 0, 0),name='petahertz',ascii_symbol='PHz',symbol='PHz') +terahertz = NamedUnit(1000000000000.0, Dimensions(0, -1, 0, 0, 0, 0, 0),name='terahertz',ascii_symbol='THz',symbol='THz') +gigahertz = NamedUnit(1000000000.0, Dimensions(0, -1, 0, 0, 0, 0, 0),name='gigahertz',ascii_symbol='GHz',symbol='GHz') +megahertz = NamedUnit(1000000.0, Dimensions(0, -1, 0, 0, 0, 0, 0),name='megahertz',ascii_symbol='MHz',symbol='MHz') +kilohertz = NamedUnit(1000.0, Dimensions(0, -1, 0, 0, 0, 0, 0),name='kilohertz',ascii_symbol='kHz',symbol='kHz') +millihertz = NamedUnit(0.001, Dimensions(0, -1, 0, 0, 0, 0, 0),name='millihertz',ascii_symbol='mHz',symbol='mHz') +microhertz = NamedUnit(1e-06, Dimensions(0, -1, 0, 0, 0, 0, 0),name='microhertz',ascii_symbol='uHz',symbol='µHz') +nanohertz = NamedUnit(1e-09, Dimensions(0, -1, 0, 0, 0, 0, 0),name='nanohertz',ascii_symbol='nHz',symbol='nHz') +picohertz = NamedUnit(1e-12, Dimensions(0, -1, 0, 0, 0, 0, 0),name='picohertz',ascii_symbol='pHz',symbol='pHz') +femtohertz = NamedUnit(1e-15, Dimensions(0, -1, 0, 0, 0, 0, 0),name='femtohertz',ascii_symbol='fHz',symbol='fHz') +attohertz = NamedUnit(1e-18, Dimensions(0, -1, 0, 0, 0, 0, 0),name='attohertz',ascii_symbol='aHz',symbol='aHz') +newtons = NamedUnit(1, Dimensions(1, -2, 1, 0, 0, 0, 0),name='newtons',ascii_symbol='N',symbol='N') +exanewtons = NamedUnit(1e+18, Dimensions(1, -2, 1, 0, 0, 0, 0),name='exanewtons',ascii_symbol='EN',symbol='EN') +petanewtons = NamedUnit(1000000000000000.0, Dimensions(1, -2, 1, 0, 0, 0, 0),name='petanewtons',ascii_symbol='PN',symbol='PN') +teranewtons = NamedUnit(1000000000000.0, Dimensions(1, -2, 1, 0, 0, 0, 0),name='teranewtons',ascii_symbol='TN',symbol='TN') +giganewtons = NamedUnit(1000000000.0, Dimensions(1, -2, 1, 0, 0, 0, 0),name='giganewtons',ascii_symbol='GN',symbol='GN') +meganewtons = NamedUnit(1000000.0, Dimensions(1, -2, 1, 0, 0, 0, 0),name='meganewtons',ascii_symbol='MN',symbol='MN') +kilonewtons = NamedUnit(1000.0, Dimensions(1, -2, 1, 0, 0, 0, 0),name='kilonewtons',ascii_symbol='kN',symbol='kN') +millinewtons = NamedUnit(0.001, Dimensions(1, -2, 1, 0, 0, 0, 0),name='millinewtons',ascii_symbol='mN',symbol='mN') +micronewtons = NamedUnit(1e-06, Dimensions(1, -2, 1, 0, 0, 0, 0),name='micronewtons',ascii_symbol='uN',symbol='µN') +nanonewtons = NamedUnit(1e-09, Dimensions(1, -2, 1, 0, 0, 0, 0),name='nanonewtons',ascii_symbol='nN',symbol='nN') +piconewtons = NamedUnit(1e-12, Dimensions(1, -2, 1, 0, 0, 0, 0),name='piconewtons',ascii_symbol='pN',symbol='pN') +femtonewtons = NamedUnit(1e-15, Dimensions(1, -2, 1, 0, 0, 0, 0),name='femtonewtons',ascii_symbol='fN',symbol='fN') +attonewtons = NamedUnit(1e-18, Dimensions(1, -2, 1, 0, 0, 0, 0),name='attonewtons',ascii_symbol='aN',symbol='aN') +pascals = NamedUnit(1, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='pascals',ascii_symbol='Pa',symbol='Pa') +exapascals = NamedUnit(1e+18, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='exapascals',ascii_symbol='EPa',symbol='EPa') +petapascals = NamedUnit(1000000000000000.0, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='petapascals',ascii_symbol='PPa',symbol='PPa') +terapascals = NamedUnit(1000000000000.0, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='terapascals',ascii_symbol='TPa',symbol='TPa') +gigapascals = NamedUnit(1000000000.0, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='gigapascals',ascii_symbol='GPa',symbol='GPa') +megapascals = NamedUnit(1000000.0, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='megapascals',ascii_symbol='MPa',symbol='MPa') +kilopascals = NamedUnit(1000.0, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='kilopascals',ascii_symbol='kPa',symbol='kPa') +millipascals = NamedUnit(0.001, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='millipascals',ascii_symbol='mPa',symbol='mPa') +micropascals = NamedUnit(1e-06, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='micropascals',ascii_symbol='uPa',symbol='µPa') +nanopascals = NamedUnit(1e-09, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='nanopascals',ascii_symbol='nPa',symbol='nPa') +picopascals = NamedUnit(1e-12, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='picopascals',ascii_symbol='pPa',symbol='pPa') +femtopascals = NamedUnit(1e-15, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='femtopascals',ascii_symbol='fPa',symbol='fPa') +attopascals = NamedUnit(1e-18, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='attopascals',ascii_symbol='aPa',symbol='aPa') +joules = NamedUnit(1, Dimensions(2, -2, 1, 0, 0, 0, 0),name='joules',ascii_symbol='J',symbol='J') +exajoules = NamedUnit(1e+18, Dimensions(2, -2, 1, 0, 0, 0, 0),name='exajoules',ascii_symbol='EJ',symbol='EJ') +petajoules = NamedUnit(1000000000000000.0, Dimensions(2, -2, 1, 0, 0, 0, 0),name='petajoules',ascii_symbol='PJ',symbol='PJ') +terajoules = NamedUnit(1000000000000.0, Dimensions(2, -2, 1, 0, 0, 0, 0),name='terajoules',ascii_symbol='TJ',symbol='TJ') +gigajoules = NamedUnit(1000000000.0, Dimensions(2, -2, 1, 0, 0, 0, 0),name='gigajoules',ascii_symbol='GJ',symbol='GJ') +megajoules = NamedUnit(1000000.0, Dimensions(2, -2, 1, 0, 0, 0, 0),name='megajoules',ascii_symbol='MJ',symbol='MJ') +kilojoules = NamedUnit(1000.0, Dimensions(2, -2, 1, 0, 0, 0, 0),name='kilojoules',ascii_symbol='kJ',symbol='kJ') +millijoules = NamedUnit(0.001, Dimensions(2, -2, 1, 0, 0, 0, 0),name='millijoules',ascii_symbol='mJ',symbol='mJ') +microjoules = NamedUnit(1e-06, Dimensions(2, -2, 1, 0, 0, 0, 0),name='microjoules',ascii_symbol='uJ',symbol='µJ') +nanojoules = NamedUnit(1e-09, Dimensions(2, -2, 1, 0, 0, 0, 0),name='nanojoules',ascii_symbol='nJ',symbol='nJ') +picojoules = NamedUnit(1e-12, Dimensions(2, -2, 1, 0, 0, 0, 0),name='picojoules',ascii_symbol='pJ',symbol='pJ') +femtojoules = NamedUnit(1e-15, Dimensions(2, -2, 1, 0, 0, 0, 0),name='femtojoules',ascii_symbol='fJ',symbol='fJ') +attojoules = NamedUnit(1e-18, Dimensions(2, -2, 1, 0, 0, 0, 0),name='attojoules',ascii_symbol='aJ',symbol='aJ') +watts = NamedUnit(1, Dimensions(2, -3, 1, 0, 0, 0, 0),name='watts',ascii_symbol='W',symbol='W') +exawatts = NamedUnit(1e+18, Dimensions(2, -3, 1, 0, 0, 0, 0),name='exawatts',ascii_symbol='EW',symbol='EW') +petawatts = NamedUnit(1000000000000000.0, Dimensions(2, -3, 1, 0, 0, 0, 0),name='petawatts',ascii_symbol='PW',symbol='PW') +terawatts = NamedUnit(1000000000000.0, Dimensions(2, -3, 1, 0, 0, 0, 0),name='terawatts',ascii_symbol='TW',symbol='TW') +gigawatts = NamedUnit(1000000000.0, Dimensions(2, -3, 1, 0, 0, 0, 0),name='gigawatts',ascii_symbol='GW',symbol='GW') +megawatts = NamedUnit(1000000.0, Dimensions(2, -3, 1, 0, 0, 0, 0),name='megawatts',ascii_symbol='MW',symbol='MW') +kilowatts = NamedUnit(1000.0, Dimensions(2, -3, 1, 0, 0, 0, 0),name='kilowatts',ascii_symbol='kW',symbol='kW') +milliwatts = NamedUnit(0.001, Dimensions(2, -3, 1, 0, 0, 0, 0),name='milliwatts',ascii_symbol='mW',symbol='mW') +microwatts = NamedUnit(1e-06, Dimensions(2, -3, 1, 0, 0, 0, 0),name='microwatts',ascii_symbol='uW',symbol='µW') +nanowatts = NamedUnit(1e-09, Dimensions(2, -3, 1, 0, 0, 0, 0),name='nanowatts',ascii_symbol='nW',symbol='nW') +picowatts = NamedUnit(1e-12, Dimensions(2, -3, 1, 0, 0, 0, 0),name='picowatts',ascii_symbol='pW',symbol='pW') +femtowatts = NamedUnit(1e-15, Dimensions(2, -3, 1, 0, 0, 0, 0),name='femtowatts',ascii_symbol='fW',symbol='fW') +attowatts = NamedUnit(1e-18, Dimensions(2, -3, 1, 0, 0, 0, 0),name='attowatts',ascii_symbol='aW',symbol='aW') +coulombs = NamedUnit(1, Dimensions(0, 1, 0, 1, 0, 0, 0),name='coulombs',ascii_symbol='C',symbol='C') +exacoulombs = NamedUnit(1e+18, Dimensions(0, 1, 0, 1, 0, 0, 0),name='exacoulombs',ascii_symbol='EC',symbol='EC') +petacoulombs = NamedUnit(1000000000000000.0, Dimensions(0, 1, 0, 1, 0, 0, 0),name='petacoulombs',ascii_symbol='PC',symbol='PC') +teracoulombs = NamedUnit(1000000000000.0, Dimensions(0, 1, 0, 1, 0, 0, 0),name='teracoulombs',ascii_symbol='TC',symbol='TC') +gigacoulombs = NamedUnit(1000000000.0, Dimensions(0, 1, 0, 1, 0, 0, 0),name='gigacoulombs',ascii_symbol='GC',symbol='GC') +megacoulombs = NamedUnit(1000000.0, Dimensions(0, 1, 0, 1, 0, 0, 0),name='megacoulombs',ascii_symbol='MC',symbol='MC') +kilocoulombs = NamedUnit(1000.0, Dimensions(0, 1, 0, 1, 0, 0, 0),name='kilocoulombs',ascii_symbol='kC',symbol='kC') +millicoulombs = NamedUnit(0.001, Dimensions(0, 1, 0, 1, 0, 0, 0),name='millicoulombs',ascii_symbol='mC',symbol='mC') +microcoulombs = NamedUnit(1e-06, Dimensions(0, 1, 0, 1, 0, 0, 0),name='microcoulombs',ascii_symbol='uC',symbol='µC') +nanocoulombs = NamedUnit(1e-09, Dimensions(0, 1, 0, 1, 0, 0, 0),name='nanocoulombs',ascii_symbol='nC',symbol='nC') +picocoulombs = NamedUnit(1e-12, Dimensions(0, 1, 0, 1, 0, 0, 0),name='picocoulombs',ascii_symbol='pC',symbol='pC') +femtocoulombs = NamedUnit(1e-15, Dimensions(0, 1, 0, 1, 0, 0, 0),name='femtocoulombs',ascii_symbol='fC',symbol='fC') +attocoulombs = NamedUnit(1e-18, Dimensions(0, 1, 0, 1, 0, 0, 0),name='attocoulombs',ascii_symbol='aC',symbol='aC') +volts = NamedUnit(1, Dimensions(2, -3, 1, -1, 0, 0, 0),name='volts',ascii_symbol='V',symbol='V') +exavolts = NamedUnit(1e+18, Dimensions(2, -3, 1, -1, 0, 0, 0),name='exavolts',ascii_symbol='EV',symbol='EV') +petavolts = NamedUnit(1000000000000000.0, Dimensions(2, -3, 1, -1, 0, 0, 0),name='petavolts',ascii_symbol='PV',symbol='PV') +teravolts = NamedUnit(1000000000000.0, Dimensions(2, -3, 1, -1, 0, 0, 0),name='teravolts',ascii_symbol='TV',symbol='TV') +gigavolts = NamedUnit(1000000000.0, Dimensions(2, -3, 1, -1, 0, 0, 0),name='gigavolts',ascii_symbol='GV',symbol='GV') +megavolts = NamedUnit(1000000.0, Dimensions(2, -3, 1, -1, 0, 0, 0),name='megavolts',ascii_symbol='MV',symbol='MV') +kilovolts = NamedUnit(1000.0, Dimensions(2, -3, 1, -1, 0, 0, 0),name='kilovolts',ascii_symbol='kV',symbol='kV') +millivolts = NamedUnit(0.001, Dimensions(2, -3, 1, -1, 0, 0, 0),name='millivolts',ascii_symbol='mV',symbol='mV') +microvolts = NamedUnit(1e-06, Dimensions(2, -3, 1, -1, 0, 0, 0),name='microvolts',ascii_symbol='uV',symbol='µV') +nanovolts = NamedUnit(1e-09, Dimensions(2, -3, 1, -1, 0, 0, 0),name='nanovolts',ascii_symbol='nV',symbol='nV') +picovolts = NamedUnit(1e-12, Dimensions(2, -3, 1, -1, 0, 0, 0),name='picovolts',ascii_symbol='pV',symbol='pV') +femtovolts = NamedUnit(1e-15, Dimensions(2, -3, 1, -1, 0, 0, 0),name='femtovolts',ascii_symbol='fV',symbol='fV') +attovolts = NamedUnit(1e-18, Dimensions(2, -3, 1, -1, 0, 0, 0),name='attovolts',ascii_symbol='aV',symbol='aV') +ohms = NamedUnit(1, Dimensions(2, -3, 1, -2, 0, 0, 0),name='ohms',ascii_symbol='Ohm',symbol='Ω') +exaohms = NamedUnit(1e+18, Dimensions(2, -3, 1, -2, 0, 0, 0),name='exaohms',ascii_symbol='EOhm',symbol='EΩ') +petaohms = NamedUnit(1000000000000000.0, Dimensions(2, -3, 1, -2, 0, 0, 0),name='petaohms',ascii_symbol='POhm',symbol='PΩ') +teraohms = NamedUnit(1000000000000.0, Dimensions(2, -3, 1, -2, 0, 0, 0),name='teraohms',ascii_symbol='TOhm',symbol='TΩ') +gigaohms = NamedUnit(1000000000.0, Dimensions(2, -3, 1, -2, 0, 0, 0),name='gigaohms',ascii_symbol='GOhm',symbol='GΩ') +megaohms = NamedUnit(1000000.0, Dimensions(2, -3, 1, -2, 0, 0, 0),name='megaohms',ascii_symbol='MOhm',symbol='MΩ') +kiloohms = NamedUnit(1000.0, Dimensions(2, -3, 1, -2, 0, 0, 0),name='kiloohms',ascii_symbol='kOhm',symbol='kΩ') +milliohms = NamedUnit(0.001, Dimensions(2, -3, 1, -2, 0, 0, 0),name='milliohms',ascii_symbol='mOhm',symbol='mΩ') +microohms = NamedUnit(1e-06, Dimensions(2, -3, 1, -2, 0, 0, 0),name='microohms',ascii_symbol='uOhm',symbol='µΩ') +nanoohms = NamedUnit(1e-09, Dimensions(2, -3, 1, -2, 0, 0, 0),name='nanoohms',ascii_symbol='nOhm',symbol='nΩ') +picoohms = NamedUnit(1e-12, Dimensions(2, -3, 1, -2, 0, 0, 0),name='picoohms',ascii_symbol='pOhm',symbol='pΩ') +femtoohms = NamedUnit(1e-15, Dimensions(2, -3, 1, -2, 0, 0, 0),name='femtoohms',ascii_symbol='fOhm',symbol='fΩ') +attoohms = NamedUnit(1e-18, Dimensions(2, -3, 1, -2, 0, 0, 0),name='attoohms',ascii_symbol='aOhm',symbol='aΩ') +farads = NamedUnit(1, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='farads',ascii_symbol='F',symbol='F') +exafarads = NamedUnit(1e+18, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='exafarads',ascii_symbol='EF',symbol='EF') +petafarads = NamedUnit(1000000000000000.0, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='petafarads',ascii_symbol='PF',symbol='PF') +terafarads = NamedUnit(1000000000000.0, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='terafarads',ascii_symbol='TF',symbol='TF') +gigafarads = NamedUnit(1000000000.0, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='gigafarads',ascii_symbol='GF',symbol='GF') +megafarads = NamedUnit(1000000.0, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='megafarads',ascii_symbol='MF',symbol='MF') +kilofarads = NamedUnit(1000.0, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='kilofarads',ascii_symbol='kF',symbol='kF') +millifarads = NamedUnit(0.001, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='millifarads',ascii_symbol='mF',symbol='mF') +microfarads = NamedUnit(1e-06, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='microfarads',ascii_symbol='uF',symbol='µF') +nanofarads = NamedUnit(1e-09, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='nanofarads',ascii_symbol='nF',symbol='nF') +picofarads = NamedUnit(1e-12, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='picofarads',ascii_symbol='pF',symbol='pF') +femtofarads = NamedUnit(1e-15, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='femtofarads',ascii_symbol='fF',symbol='fF') +attofarads = NamedUnit(1e-18, Dimensions(-2, 4, -1, 2, 0, 0, 0),name='attofarads',ascii_symbol='aF',symbol='aF') +siemens = NamedUnit(1, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='siemens',ascii_symbol='S',symbol='S') +exasiemens = NamedUnit(1e+18, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='exasiemens',ascii_symbol='ES',symbol='ES') +petasiemens = NamedUnit(1000000000000000.0, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='petasiemens',ascii_symbol='PS',symbol='PS') +terasiemens = NamedUnit(1000000000000.0, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='terasiemens',ascii_symbol='TS',symbol='TS') +gigasiemens = NamedUnit(1000000000.0, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='gigasiemens',ascii_symbol='GS',symbol='GS') +megasiemens = NamedUnit(1000000.0, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='megasiemens',ascii_symbol='MS',symbol='MS') +kilosiemens = NamedUnit(1000.0, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='kilosiemens',ascii_symbol='kS',symbol='kS') +millisiemens = NamedUnit(0.001, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='millisiemens',ascii_symbol='mS',symbol='mS') +microsiemens = NamedUnit(1e-06, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='microsiemens',ascii_symbol='uS',symbol='µS') +nanosiemens = NamedUnit(1e-09, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='nanosiemens',ascii_symbol='nS',symbol='nS') +picosiemens = NamedUnit(1e-12, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='picosiemens',ascii_symbol='pS',symbol='pS') +femtosiemens = NamedUnit(1e-15, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='femtosiemens',ascii_symbol='fS',symbol='fS') +attosiemens = NamedUnit(1e-18, Dimensions(-2, 3, -1, 2, 0, 0, 0),name='attosiemens',ascii_symbol='aS',symbol='aS') +webers = NamedUnit(1, Dimensions(2, -2, 1, -1, 0, 0, 0),name='webers',ascii_symbol='Wb',symbol='Wb') +exawebers = NamedUnit(1e+18, Dimensions(2, -2, 1, -1, 0, 0, 0),name='exawebers',ascii_symbol='EWb',symbol='EWb') +petawebers = NamedUnit(1000000000000000.0, Dimensions(2, -2, 1, -1, 0, 0, 0),name='petawebers',ascii_symbol='PWb',symbol='PWb') +terawebers = NamedUnit(1000000000000.0, Dimensions(2, -2, 1, -1, 0, 0, 0),name='terawebers',ascii_symbol='TWb',symbol='TWb') +gigawebers = NamedUnit(1000000000.0, Dimensions(2, -2, 1, -1, 0, 0, 0),name='gigawebers',ascii_symbol='GWb',symbol='GWb') +megawebers = NamedUnit(1000000.0, Dimensions(2, -2, 1, -1, 0, 0, 0),name='megawebers',ascii_symbol='MWb',symbol='MWb') +kilowebers = NamedUnit(1000.0, Dimensions(2, -2, 1, -1, 0, 0, 0),name='kilowebers',ascii_symbol='kWb',symbol='kWb') +milliwebers = NamedUnit(0.001, Dimensions(2, -2, 1, -1, 0, 0, 0),name='milliwebers',ascii_symbol='mWb',symbol='mWb') +microwebers = NamedUnit(1e-06, Dimensions(2, -2, 1, -1, 0, 0, 0),name='microwebers',ascii_symbol='uWb',symbol='µWb') +nanowebers = NamedUnit(1e-09, Dimensions(2, -2, 1, -1, 0, 0, 0),name='nanowebers',ascii_symbol='nWb',symbol='nWb') +picowebers = NamedUnit(1e-12, Dimensions(2, -2, 1, -1, 0, 0, 0),name='picowebers',ascii_symbol='pWb',symbol='pWb') +femtowebers = NamedUnit(1e-15, Dimensions(2, -2, 1, -1, 0, 0, 0),name='femtowebers',ascii_symbol='fWb',symbol='fWb') +attowebers = NamedUnit(1e-18, Dimensions(2, -2, 1, -1, 0, 0, 0),name='attowebers',ascii_symbol='aWb',symbol='aWb') +tesla = NamedUnit(1, Dimensions(0, -2, 1, -1, 0, 0, 0),name='tesla',ascii_symbol='T',symbol='T') +exatesla = NamedUnit(1e+18, Dimensions(0, -2, 1, -1, 0, 0, 0),name='exatesla',ascii_symbol='ET',symbol='ET') +petatesla = NamedUnit(1000000000000000.0, Dimensions(0, -2, 1, -1, 0, 0, 0),name='petatesla',ascii_symbol='PT',symbol='PT') +teratesla = NamedUnit(1000000000000.0, Dimensions(0, -2, 1, -1, 0, 0, 0),name='teratesla',ascii_symbol='TT',symbol='TT') +gigatesla = NamedUnit(1000000000.0, Dimensions(0, -2, 1, -1, 0, 0, 0),name='gigatesla',ascii_symbol='GT',symbol='GT') +megatesla = NamedUnit(1000000.0, Dimensions(0, -2, 1, -1, 0, 0, 0),name='megatesla',ascii_symbol='MT',symbol='MT') +kilotesla = NamedUnit(1000.0, Dimensions(0, -2, 1, -1, 0, 0, 0),name='kilotesla',ascii_symbol='kT',symbol='kT') +millitesla = NamedUnit(0.001, Dimensions(0, -2, 1, -1, 0, 0, 0),name='millitesla',ascii_symbol='mT',symbol='mT') +microtesla = NamedUnit(1e-06, Dimensions(0, -2, 1, -1, 0, 0, 0),name='microtesla',ascii_symbol='uT',symbol='µT') +nanotesla = NamedUnit(1e-09, Dimensions(0, -2, 1, -1, 0, 0, 0),name='nanotesla',ascii_symbol='nT',symbol='nT') +picotesla = NamedUnit(1e-12, Dimensions(0, -2, 1, -1, 0, 0, 0),name='picotesla',ascii_symbol='pT',symbol='pT') +femtotesla = NamedUnit(1e-15, Dimensions(0, -2, 1, -1, 0, 0, 0),name='femtotesla',ascii_symbol='fT',symbol='fT') +attotesla = NamedUnit(1e-18, Dimensions(0, -2, 1, -1, 0, 0, 0),name='attotesla',ascii_symbol='aT',symbol='aT') +henry = NamedUnit(1, Dimensions(2, -2, 1, -2, 0, 0, 0),name='henry',ascii_symbol='H',symbol='H') +exahenry = NamedUnit(1e+18, Dimensions(2, -2, 1, -2, 0, 0, 0),name='exahenry',ascii_symbol='EH',symbol='EH') +petahenry = NamedUnit(1000000000000000.0, Dimensions(2, -2, 1, -2, 0, 0, 0),name='petahenry',ascii_symbol='PH',symbol='PH') +terahenry = NamedUnit(1000000000000.0, Dimensions(2, -2, 1, -2, 0, 0, 0),name='terahenry',ascii_symbol='TH',symbol='TH') +gigahenry = NamedUnit(1000000000.0, Dimensions(2, -2, 1, -2, 0, 0, 0),name='gigahenry',ascii_symbol='GH',symbol='GH') +megahenry = NamedUnit(1000000.0, Dimensions(2, -2, 1, -2, 0, 0, 0),name='megahenry',ascii_symbol='MH',symbol='MH') +kilohenry = NamedUnit(1000.0, Dimensions(2, -2, 1, -2, 0, 0, 0),name='kilohenry',ascii_symbol='kH',symbol='kH') +millihenry = NamedUnit(0.001, Dimensions(2, -2, 1, -2, 0, 0, 0),name='millihenry',ascii_symbol='mH',symbol='mH') +microhenry = NamedUnit(1e-06, Dimensions(2, -2, 1, -2, 0, 0, 0),name='microhenry',ascii_symbol='uH',symbol='µH') +nanohenry = NamedUnit(1e-09, Dimensions(2, -2, 1, -2, 0, 0, 0),name='nanohenry',ascii_symbol='nH',symbol='nH') +picohenry = NamedUnit(1e-12, Dimensions(2, -2, 1, -2, 0, 0, 0),name='picohenry',ascii_symbol='pH',symbol='pH') +femtohenry = NamedUnit(1e-15, Dimensions(2, -2, 1, -2, 0, 0, 0),name='femtohenry',ascii_symbol='fH',symbol='fH') +attohenry = NamedUnit(1e-18, Dimensions(2, -2, 1, -2, 0, 0, 0),name='attohenry',ascii_symbol='aH',symbol='aH') +angstroms = NamedUnit(1e-10, Dimensions(1, 0, 0, 0, 0, 0, 0),name='angstroms',ascii_symbol='Ang',symbol='Å') +minutes = NamedUnit(60, Dimensions(0, 1, 0, 0, 0, 0, 0),name='minutes',ascii_symbol='min',symbol='min') +hours = NamedUnit(360, Dimensions(0, 1, 0, 0, 0, 0, 0),name='hours',ascii_symbol='h',symbol='h') +days = NamedUnit(8640, Dimensions(0, 1, 0, 0, 0, 0, 0),name='days',ascii_symbol='d',symbol='d') +years = NamedUnit(3155695.2, Dimensions(0, 1, 0, 0, 0, 0, 0),name='years',ascii_symbol='y',symbol='y') +degrees = NamedUnit(57.29577951308232, Dimensions(0, 0, 0, 0, 0, 0, 1),name='degrees',ascii_symbol='deg',symbol='deg') +radians = NamedUnit(1, Dimensions(0, 0, 0, 0, 0, 0, 1),name='radians',ascii_symbol='rad',symbol='rad') +stradians = NamedUnit(1, Dimensions(0, 0, 0, 0, 0, 0, 2),name='stradians',ascii_symbol='sr',symbol='sr') +litres = NamedUnit(0.001, Dimensions(3, 0, 0, 0, 0, 0, 0),name='litres',ascii_symbol='l',symbol='l') +electronvolts = NamedUnit(1.602176634e-19, Dimensions(2, -2, 1, 0, 0, 0, 0),name='electronvolts',ascii_symbol='eV',symbol='eV') +exaelectronvolts = NamedUnit(0.1602176634, Dimensions(2, -2, 1, 0, 0, 0, 0),name='exaelectronvolts',ascii_symbol='EeV',symbol='EeV') +petaelectronvolts = NamedUnit(0.0001602176634, Dimensions(2, -2, 1, 0, 0, 0, 0),name='petaelectronvolts',ascii_symbol='PeV',symbol='PeV') +teraelectronvolts = NamedUnit(1.602176634e-07, Dimensions(2, -2, 1, 0, 0, 0, 0),name='teraelectronvolts',ascii_symbol='TeV',symbol='TeV') +gigaelectronvolts = NamedUnit(1.6021766339999998e-10, Dimensions(2, -2, 1, 0, 0, 0, 0),name='gigaelectronvolts',ascii_symbol='GeV',symbol='GeV') +megaelectronvolts = NamedUnit(1.6021766339999998e-13, Dimensions(2, -2, 1, 0, 0, 0, 0),name='megaelectronvolts',ascii_symbol='MeV',symbol='MeV') +kiloelectronvolts = NamedUnit(1.602176634e-16, Dimensions(2, -2, 1, 0, 0, 0, 0),name='kiloelectronvolts',ascii_symbol='keV',symbol='keV') +millielectronvolts = NamedUnit(1.6021766339999998e-22, Dimensions(2, -2, 1, 0, 0, 0, 0),name='millielectronvolts',ascii_symbol='meV',symbol='meV') +microelectronvolts = NamedUnit(1.602176634e-25, Dimensions(2, -2, 1, 0, 0, 0, 0),name='microelectronvolts',ascii_symbol='ueV',symbol='µeV') +nanoelectronvolts = NamedUnit(1.602176634e-28, Dimensions(2, -2, 1, 0, 0, 0, 0),name='nanoelectronvolts',ascii_symbol='neV',symbol='neV') +picoelectronvolts = NamedUnit(1.6021766339999998e-31, Dimensions(2, -2, 1, 0, 0, 0, 0),name='picoelectronvolts',ascii_symbol='peV',symbol='peV') +femtoelectronvolts = NamedUnit(1.602176634e-34, Dimensions(2, -2, 1, 0, 0, 0, 0),name='femtoelectronvolts',ascii_symbol='feV',symbol='feV') +attoelectronvolts = NamedUnit(1.602176634e-37, Dimensions(2, -2, 1, 0, 0, 0, 0),name='attoelectronvolts',ascii_symbol='aeV',symbol='aeV') +atomic_mass_units = NamedUnit(1.660538921e-27, Dimensions(0, 0, 1, 0, 0, 0, 0),name='atomic_mass_units',ascii_symbol='au',symbol='au') +moles = NamedUnit(6.02214076e+23, Dimensions(0, 0, 0, 0, 0, 1, 0),name='moles',ascii_symbol='mol',symbol='mol') +millimoles = NamedUnit(6.02214076e+20, Dimensions(0, 0, 0, 0, 0, 1, 0),name='millimoles',ascii_symbol='mmol',symbol='mmol') +micromoles = NamedUnit(6.02214076e+17, Dimensions(0, 0, 0, 0, 0, 1, 0),name='micromoles',ascii_symbol='umol',symbol='µmol') +nanomoles = NamedUnit(602214076000000.0, Dimensions(0, 0, 0, 0, 0, 1, 0),name='nanomoles',ascii_symbol='nmol',symbol='nmol') +picomoles = NamedUnit(602214076000.0, Dimensions(0, 0, 0, 0, 0, 1, 0),name='picomoles',ascii_symbol='pmol',symbol='pmol') +femtomoles = NamedUnit(602214076.0, Dimensions(0, 0, 0, 0, 0, 1, 0),name='femtomoles',ascii_symbol='fmol',symbol='fmol') +attomoles = NamedUnit(602214.076, Dimensions(0, 0, 0, 0, 0, 1, 0),name='attomoles',ascii_symbol='amol',symbol='amol') +kg_force = NamedUnit(9.80665, Dimensions(1, -2, 1, 0, 0, 0, 0),name='kg_force',ascii_symbol='kgForce',symbol='kgForce') +degrees_celsius = NamedUnit(1, Dimensions(0, 0, 0, 0, 1, 0, 0),name='degrees_celsius',ascii_symbol='C',symbol='C') +miles = NamedUnit(1609.344, Dimensions(1, 0, 0, 0, 0, 0, 0),name='miles',ascii_symbol='miles',symbol='miles') +yards = NamedUnit(0.9144000000000001, Dimensions(1, 0, 0, 0, 0, 0, 0),name='yards',ascii_symbol='yrd',symbol='yrd') +feet = NamedUnit(0.3048, Dimensions(1, 0, 0, 0, 0, 0, 0),name='feet',ascii_symbol='ft',symbol='ft') +inches = NamedUnit(0.0254, Dimensions(1, 0, 0, 0, 0, 0, 0),name='inches',ascii_symbol='in',symbol='in') +pounds = NamedUnit(0.45359237, Dimensions(0, 0, 1, 0, 0, 0, 0),name='pounds',ascii_symbol='lb',symbol='lb') +pounds_force = NamedUnit(4.448222, Dimensions(1, -2, 1, 0, 0, 0, 0),name='pounds_force',ascii_symbol='lbf',symbol='lbf') +ounces = NamedUnit(0.028349523125, Dimensions(0, 0, 1, 0, 0, 0, 0),name='ounces',ascii_symbol='oz',symbol='oz') +pounds_force_per_square_inch = NamedUnit(6894.757889515779, Dimensions(-1, -2, 1, 0, 0, 0, 0),name='pounds_force_per_square_inch',ascii_symbol='psi',symbol='psi') +none = NamedUnit(1, Dimensions(0, 0, 0, 0, 0, 0, 0),name='none',ascii_symbol='none',symbol='none') +percent = NamedUnit(0.01, Dimensions(0, 0, 0, 0, 0, 0, 0),name='percent',ascii_symbol='percent',symbol='%') +square_meters = NamedUnit(1, Dimensions(length=2), name='square_meters', ascii_symbol='m^2', symbol='m²') +cubic_meters = NamedUnit(1, Dimensions(length=3), name='cubic_meters', ascii_symbol='m^3', symbol='m³') +per_meter = NamedUnit(1.0, Dimensions(length=-1), name='per_meter', ascii_symbol='m^-1', symbol='m⁻¹') +per_square_meter = NamedUnit(1.0, Dimensions(length=-2), name='per_square_meter', ascii_symbol='m^-2', symbol='m⁻²') +per_cubic_meter = NamedUnit(1.0, Dimensions(length=-3), name='per_cubic_meter', ascii_symbol='m^-3', symbol='m⁻³') +square_exameters = NamedUnit(1e+36, Dimensions(length=2), name='square_exameters', ascii_symbol='Em^2', symbol='Em²') +cubic_exameters = NamedUnit(1e+54, Dimensions(length=3), name='cubic_exameters', ascii_symbol='Em^3', symbol='Em³') +per_exameter = NamedUnit(1e-18, Dimensions(length=-1), name='per_exameter', ascii_symbol='Em^-1', symbol='Em⁻¹') +per_square_exameter = NamedUnit(1e-36, Dimensions(length=-2), name='per_square_exameter', ascii_symbol='Em^-2', symbol='Em⁻²') +per_cubic_exameter = NamedUnit(1e-54, Dimensions(length=-3), name='per_cubic_exameter', ascii_symbol='Em^-3', symbol='Em⁻³') +square_petameters = NamedUnit(1e+30, Dimensions(length=2), name='square_petameters', ascii_symbol='Pm^2', symbol='Pm²') +cubic_petameters = NamedUnit(1e+45, Dimensions(length=3), name='cubic_petameters', ascii_symbol='Pm^3', symbol='Pm³') +per_petameter = NamedUnit(1e-15, Dimensions(length=-1), name='per_petameter', ascii_symbol='Pm^-1', symbol='Pm⁻¹') +per_square_petameter = NamedUnit(1e-30, Dimensions(length=-2), name='per_square_petameter', ascii_symbol='Pm^-2', symbol='Pm⁻²') +per_cubic_petameter = NamedUnit(1e-45, Dimensions(length=-3), name='per_cubic_petameter', ascii_symbol='Pm^-3', symbol='Pm⁻³') +square_terameters = NamedUnit(1e+24, Dimensions(length=2), name='square_terameters', ascii_symbol='Tm^2', symbol='Tm²') +cubic_terameters = NamedUnit(1e+36, Dimensions(length=3), name='cubic_terameters', ascii_symbol='Tm^3', symbol='Tm³') +per_terameter = NamedUnit(1e-12, Dimensions(length=-1), name='per_terameter', ascii_symbol='Tm^-1', symbol='Tm⁻¹') +per_square_terameter = NamedUnit(1e-24, Dimensions(length=-2), name='per_square_terameter', ascii_symbol='Tm^-2', symbol='Tm⁻²') +per_cubic_terameter = NamedUnit(1e-36, Dimensions(length=-3), name='per_cubic_terameter', ascii_symbol='Tm^-3', symbol='Tm⁻³') +square_gigameters = NamedUnit(1e+18, Dimensions(length=2), name='square_gigameters', ascii_symbol='Gm^2', symbol='Gm²') +cubic_gigameters = NamedUnit(1e+27, Dimensions(length=3), name='cubic_gigameters', ascii_symbol='Gm^3', symbol='Gm³') +per_gigameter = NamedUnit(1e-09, Dimensions(length=-1), name='per_gigameter', ascii_symbol='Gm^-1', symbol='Gm⁻¹') +per_square_gigameter = NamedUnit(1e-18, Dimensions(length=-2), name='per_square_gigameter', ascii_symbol='Gm^-2', symbol='Gm⁻²') +per_cubic_gigameter = NamedUnit(1e-27, Dimensions(length=-3), name='per_cubic_gigameter', ascii_symbol='Gm^-3', symbol='Gm⁻³') +square_megameters = NamedUnit(1000000000000.0, Dimensions(length=2), name='square_megameters', ascii_symbol='Mm^2', symbol='Mm²') +cubic_megameters = NamedUnit(1e+18, Dimensions(length=3), name='cubic_megameters', ascii_symbol='Mm^3', symbol='Mm³') +per_megameter = NamedUnit(1e-06, Dimensions(length=-1), name='per_megameter', ascii_symbol='Mm^-1', symbol='Mm⁻¹') +per_square_megameter = NamedUnit(1e-12, Dimensions(length=-2), name='per_square_megameter', ascii_symbol='Mm^-2', symbol='Mm⁻²') +per_cubic_megameter = NamedUnit(1e-18, Dimensions(length=-3), name='per_cubic_megameter', ascii_symbol='Mm^-3', symbol='Mm⁻³') +square_kilometers = NamedUnit(1000000.0, Dimensions(length=2), name='square_kilometers', ascii_symbol='km^2', symbol='km²') +cubic_kilometers = NamedUnit(1000000000.0, Dimensions(length=3), name='cubic_kilometers', ascii_symbol='km^3', symbol='km³') +per_kilometer = NamedUnit(0.001, Dimensions(length=-1), name='per_kilometer', ascii_symbol='km^-1', symbol='km⁻¹') +per_square_kilometer = NamedUnit(1e-06, Dimensions(length=-2), name='per_square_kilometer', ascii_symbol='km^-2', symbol='km⁻²') +per_cubic_kilometer = NamedUnit(1e-09, Dimensions(length=-3), name='per_cubic_kilometer', ascii_symbol='km^-3', symbol='km⁻³') +square_millimeters = NamedUnit(1e-06, Dimensions(length=2), name='square_millimeters', ascii_symbol='mm^2', symbol='mm²') +cubic_millimeters = NamedUnit(1e-09, Dimensions(length=3), name='cubic_millimeters', ascii_symbol='mm^3', symbol='mm³') +per_millimeter = NamedUnit(1000.0, Dimensions(length=-1), name='per_millimeter', ascii_symbol='mm^-1', symbol='mm⁻¹') +per_square_millimeter = NamedUnit(1000000.0, Dimensions(length=-2), name='per_square_millimeter', ascii_symbol='mm^-2', symbol='mm⁻²') +per_cubic_millimeter = NamedUnit(999999999.9999999, Dimensions(length=-3), name='per_cubic_millimeter', ascii_symbol='mm^-3', symbol='mm⁻³') +square_micrometers = NamedUnit(1e-12, Dimensions(length=2), name='square_micrometers', ascii_symbol='um^2', symbol='µm²') +cubic_micrometers = NamedUnit(9.999999999999999e-19, Dimensions(length=3), name='cubic_micrometers', ascii_symbol='um^3', symbol='µm³') +per_micrometer = NamedUnit(1000000.0, Dimensions(length=-1), name='per_micrometer', ascii_symbol='um^-1', symbol='µm⁻¹') +per_square_micrometer = NamedUnit(1000000000000.0001, Dimensions(length=-2), name='per_square_micrometer', ascii_symbol='um^-2', symbol='µm⁻²') +per_cubic_micrometer = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3), name='per_cubic_micrometer', ascii_symbol='um^-3', symbol='µm⁻³') +square_nanometers = NamedUnit(1e-18, Dimensions(length=2), name='square_nanometers', ascii_symbol='nm^2', symbol='nm²') +cubic_nanometers = NamedUnit(1.0000000000000002e-27, Dimensions(length=3), name='cubic_nanometers', ascii_symbol='nm^3', symbol='nm³') +per_nanometer = NamedUnit(999999999.9999999, Dimensions(length=-1), name='per_nanometer', ascii_symbol='nm^-1', symbol='nm⁻¹') +per_square_nanometer = NamedUnit(9.999999999999999e+17, Dimensions(length=-2), name='per_square_nanometer', ascii_symbol='nm^-2', symbol='nm⁻²') +per_cubic_nanometer = NamedUnit(9.999999999999999e+26, Dimensions(length=-3), name='per_cubic_nanometer', ascii_symbol='nm^-3', symbol='nm⁻³') +square_picometers = NamedUnit(1e-24, Dimensions(length=2), name='square_picometers', ascii_symbol='pm^2', symbol='pm²') +cubic_picometers = NamedUnit(1e-36, Dimensions(length=3), name='cubic_picometers', ascii_symbol='pm^3', symbol='pm³') +per_picometer = NamedUnit(1000000000000.0, Dimensions(length=-1), name='per_picometer', ascii_symbol='pm^-1', symbol='pm⁻¹') +per_square_picometer = NamedUnit(1e+24, Dimensions(length=-2), name='per_square_picometer', ascii_symbol='pm^-2', symbol='pm⁻²') +per_cubic_picometer = NamedUnit(1e+36, Dimensions(length=-3), name='per_cubic_picometer', ascii_symbol='pm^-3', symbol='pm⁻³') +square_femtometers = NamedUnit(1e-30, Dimensions(length=2), name='square_femtometers', ascii_symbol='fm^2', symbol='fm²') +cubic_femtometers = NamedUnit(1.0000000000000003e-45, Dimensions(length=3), name='cubic_femtometers', ascii_symbol='fm^3', symbol='fm³') +per_femtometer = NamedUnit(999999999999999.9, Dimensions(length=-1), name='per_femtometer', ascii_symbol='fm^-1', symbol='fm⁻¹') +per_square_femtometer = NamedUnit(9.999999999999999e+29, Dimensions(length=-2), name='per_square_femtometer', ascii_symbol='fm^-2', symbol='fm⁻²') +per_cubic_femtometer = NamedUnit(9.999999999999998e+44, Dimensions(length=-3), name='per_cubic_femtometer', ascii_symbol='fm^-3', symbol='fm⁻³') +square_attometers = NamedUnit(1.0000000000000001e-36, Dimensions(length=2), name='square_attometers', ascii_symbol='am^2', symbol='am²') +cubic_attometers = NamedUnit(1.0000000000000002e-54, Dimensions(length=3), name='cubic_attometers', ascii_symbol='am^3', symbol='am³') +per_attometer = NamedUnit(9.999999999999999e+17, Dimensions(length=-1), name='per_attometer', ascii_symbol='am^-1', symbol='am⁻¹') +per_square_attometer = NamedUnit(9.999999999999999e+35, Dimensions(length=-2), name='per_square_attometer', ascii_symbol='am^-2', symbol='am⁻²') +per_cubic_attometer = NamedUnit(9.999999999999997e+53, Dimensions(length=-3), name='per_cubic_attometer', ascii_symbol='am^-3', symbol='am⁻³') +square_decimeters = NamedUnit(0.010000000000000002, Dimensions(length=2), name='square_decimeters', ascii_symbol='dm^2', symbol='dm²') +cubic_decimeters = NamedUnit(0.0010000000000000002, Dimensions(length=3), name='cubic_decimeters', ascii_symbol='dm^3', symbol='dm³') +per_decimeter = NamedUnit(10.0, Dimensions(length=-1), name='per_decimeter', ascii_symbol='dm^-1', symbol='dm⁻¹') +per_square_decimeter = NamedUnit(99.99999999999999, Dimensions(length=-2), name='per_square_decimeter', ascii_symbol='dm^-2', symbol='dm⁻²') +per_cubic_decimeter = NamedUnit(999.9999999999999, Dimensions(length=-3), name='per_cubic_decimeter', ascii_symbol='dm^-3', symbol='dm⁻³') +square_centimeters = NamedUnit(0.0001, Dimensions(length=2), name='square_centimeters', ascii_symbol='cm^2', symbol='cm²') +cubic_centimeters = NamedUnit(1.0000000000000002e-06, Dimensions(length=3), name='cubic_centimeters', ascii_symbol='cm^3', symbol='cm³') +per_centimeter = NamedUnit(100.0, Dimensions(length=-1), name='per_centimeter', ascii_symbol='cm^-1', symbol='cm⁻¹') +per_square_centimeter = NamedUnit(10000.0, Dimensions(length=-2), name='per_square_centimeter', ascii_symbol='cm^-2', symbol='cm⁻²') +per_cubic_centimeter = NamedUnit(999999.9999999999, Dimensions(length=-3), name='per_cubic_centimeter', ascii_symbol='cm^-3', symbol='cm⁻³') +square_angstroms = NamedUnit(1.0000000000000001e-20, Dimensions(length=2), name='square_angstroms', ascii_symbol='Ang^2', symbol='Ų') +cubic_angstroms = NamedUnit(1e-30, Dimensions(length=3), name='cubic_angstroms', ascii_symbol='Ang^3', symbol='ų') +per_angstrom = NamedUnit(10000000000.0, Dimensions(length=-1), name='per_angstrom', ascii_symbol='Ang^-1', symbol='Å⁻¹') +per_square_angstrom = NamedUnit(1e+20, Dimensions(length=-2), name='per_square_angstrom', ascii_symbol='Ang^-2', symbol='Å⁻²') +per_cubic_angstrom = NamedUnit(9.999999999999999e+29, Dimensions(length=-3), name='per_cubic_angstrom', ascii_symbol='Ang^-3', symbol='Å⁻³') +square_miles = NamedUnit(2589988.110336, Dimensions(length=2), name='square_miles', ascii_symbol='miles^2', symbol='miles²') +cubic_miles = NamedUnit(4168181825.44058, Dimensions(length=3), name='cubic_miles', ascii_symbol='miles^3', symbol='miles³') +per_mile = NamedUnit(0.0006213711922373339, Dimensions(length=-1), name='per_mile', ascii_symbol='miles^-1', symbol='miles⁻¹') +per_square_mile = NamedUnit(3.861021585424458e-07, Dimensions(length=-2), name='per_square_mile', ascii_symbol='miles^-2', symbol='miles⁻²') +per_cubic_mile = NamedUnit(2.399127585789277e-10, Dimensions(length=-3), name='per_cubic_mile', ascii_symbol='miles^-3', symbol='miles⁻³') +square_yards = NamedUnit(0.8361273600000002, Dimensions(length=2), name='square_yards', ascii_symbol='yrd^2', symbol='yrd²') +cubic_yards = NamedUnit(0.7645548579840002, Dimensions(length=3), name='cubic_yards', ascii_symbol='yrd^3', symbol='yrd³') +per_yard = NamedUnit(1.0936132983377076, Dimensions(length=-1), name='per_yard', ascii_symbol='yrd^-1', symbol='yrd⁻¹') +per_square_yard = NamedUnit(1.19599004630108, Dimensions(length=-2), name='per_square_yard', ascii_symbol='yrd^-2', symbol='yrd⁻²') +per_cubic_yard = NamedUnit(1.3079506193143917, Dimensions(length=-3), name='per_cubic_yard', ascii_symbol='yrd^-3', symbol='yrd⁻³') +square_feet = NamedUnit(0.09290304, Dimensions(length=2), name='square_feet', ascii_symbol='ft^2', symbol='ft²') +cubic_feet = NamedUnit(0.028316846592000004, Dimensions(length=3), name='cubic_feet', ascii_symbol='ft^3', symbol='ft³') +per_foot = NamedUnit(3.280839895013123, Dimensions(length=-1), name='per_foot', ascii_symbol='ft^-1', symbol='ft⁻¹') +per_square_foot = NamedUnit(10.763910416709722, Dimensions(length=-2), name='per_square_foot', ascii_symbol='ft^-2', symbol='ft⁻²') +per_cubic_foot = NamedUnit(35.314666721488585, Dimensions(length=-3), name='per_cubic_foot', ascii_symbol='ft^-3', symbol='ft⁻³') +square_inches = NamedUnit(0.00064516, Dimensions(length=2), name='square_inches', ascii_symbol='in^2', symbol='in²') +cubic_inches = NamedUnit(1.6387064e-05, Dimensions(length=3), name='cubic_inches', ascii_symbol='in^3', symbol='in³') +per_inch = NamedUnit(39.37007874015748, Dimensions(length=-1), name='per_inch', ascii_symbol='in^-1', symbol='in⁻¹') +per_square_inch = NamedUnit(1550.0031000062002, Dimensions(length=-2), name='per_square_inch', ascii_symbol='in^-2', symbol='in⁻²') +per_cubic_inch = NamedUnit(61023.74409473229, Dimensions(length=-3), name='per_cubic_inch', ascii_symbol='in^-3', symbol='in⁻³') +meters_per_second = NamedUnit(1.0, Dimensions(length=1, time=-1), name='meters_per_second', ascii_symbol='m/s', symbol='ms⁻¹') +meters_per_square_second = NamedUnit(1.0, Dimensions(length=1, time=-2), name='meters_per_square_second', ascii_symbol='m/s^2', symbol='ms⁻²') +meters_per_millisecond = NamedUnit(1000.0, Dimensions(length=1, time=-1), name='meters_per_millisecond', ascii_symbol='m/ms', symbol='mms⁻¹') +meters_per_square_millisecond = NamedUnit(1000000.0, Dimensions(length=1, time=-2), name='meters_per_square_millisecond', ascii_symbol='m/ms^2', symbol='mms⁻²') +meters_per_microsecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='meters_per_microsecond', ascii_symbol='m/us', symbol='mµs⁻¹') +meters_per_square_microsecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='meters_per_square_microsecond', ascii_symbol='m/us^2', symbol='mµs⁻²') +meters_per_nanosecond = NamedUnit(999999999.9999999, Dimensions(length=1, time=-1), name='meters_per_nanosecond', ascii_symbol='m/ns', symbol='mns⁻¹') +meters_per_square_nanosecond = NamedUnit(9.999999999999999e+17, Dimensions(length=1, time=-2), name='meters_per_square_nanosecond', ascii_symbol='m/ns^2', symbol='mns⁻²') +meters_per_picosecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='meters_per_picosecond', ascii_symbol='m/ps', symbol='mps⁻¹') +meters_per_square_picosecond = NamedUnit(1.0000000000000001e+24, Dimensions(length=1, time=-2), name='meters_per_square_picosecond', ascii_symbol='m/ps^2', symbol='mps⁻²') +meters_per_femtosecond = NamedUnit(999999999999999.9, Dimensions(length=1, time=-1), name='meters_per_femtosecond', ascii_symbol='m/fs', symbol='mfs⁻¹') +meters_per_square_femtosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-2), name='meters_per_square_femtosecond', ascii_symbol='m/fs^2', symbol='mfs⁻²') +meters_per_attosecond = NamedUnit(9.999999999999999e+17, Dimensions(length=1, time=-1), name='meters_per_attosecond', ascii_symbol='m/as', symbol='mas⁻¹') +meters_per_square_attosecond = NamedUnit(9.999999999999999e+35, Dimensions(length=1, time=-2), name='meters_per_square_attosecond', ascii_symbol='m/as^2', symbol='mas⁻²') +meters_per_minute = NamedUnit(0.016666666666666666, Dimensions(length=1, time=-1), name='meters_per_minute', ascii_symbol='m/min', symbol='mmin⁻¹') +meters_per_square_minute = NamedUnit(0.0002777777777777778, Dimensions(length=1, time=-2), name='meters_per_square_minute', ascii_symbol='m/min^2', symbol='mmin⁻²') +meters_per_hour = NamedUnit(0.002777777777777778, Dimensions(length=1, time=-1), name='meters_per_hour', ascii_symbol='m/h', symbol='mh⁻¹') +meters_per_square_hour = NamedUnit(7.71604938271605e-06, Dimensions(length=1, time=-2), name='meters_per_square_hour', ascii_symbol='m/h^2', symbol='mh⁻²') +meters_per_day = NamedUnit(0.00011574074074074075, Dimensions(length=1, time=-1), name='meters_per_day', ascii_symbol='m/d', symbol='md⁻¹') +meters_per_square_day = NamedUnit(1.3395919067215363e-08, Dimensions(length=1, time=-2), name='meters_per_square_day', ascii_symbol='m/d^2', symbol='md⁻²') +meters_per_year = NamedUnit(3.168873850681143e-07, Dimensions(length=1, time=-1), name='meters_per_year', ascii_symbol='m/y', symbol='my⁻¹') +meters_per_square_year = NamedUnit(1.0041761481530735e-13, Dimensions(length=1, time=-2), name='meters_per_square_year', ascii_symbol='m/y^2', symbol='my⁻²') +exameters_per_second = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='exameters_per_second', ascii_symbol='Em/s', symbol='Ems⁻¹') +exameters_per_square_second = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='exameters_per_square_second', ascii_symbol='Em/s^2', symbol='Ems⁻²') +exameters_per_millisecond = NamedUnit(1e+21, Dimensions(length=1, time=-1), name='exameters_per_millisecond', ascii_symbol='Em/ms', symbol='Emms⁻¹') +exameters_per_square_millisecond = NamedUnit(1e+24, Dimensions(length=1, time=-2), name='exameters_per_square_millisecond', ascii_symbol='Em/ms^2', symbol='Emms⁻²') +exameters_per_microsecond = NamedUnit(1e+24, Dimensions(length=1, time=-1), name='exameters_per_microsecond', ascii_symbol='Em/us', symbol='Emµs⁻¹') +exameters_per_square_microsecond = NamedUnit(1e+30, Dimensions(length=1, time=-2), name='exameters_per_square_microsecond', ascii_symbol='Em/us^2', symbol='Emµs⁻²') +exameters_per_nanosecond = NamedUnit(9.999999999999999e+26, Dimensions(length=1, time=-1), name='exameters_per_nanosecond', ascii_symbol='Em/ns', symbol='Emns⁻¹') +exameters_per_square_nanosecond = NamedUnit(9.999999999999999e+35, Dimensions(length=1, time=-2), name='exameters_per_square_nanosecond', ascii_symbol='Em/ns^2', symbol='Emns⁻²') +exameters_per_picosecond = NamedUnit(1e+30, Dimensions(length=1, time=-1), name='exameters_per_picosecond', ascii_symbol='Em/ps', symbol='Emps⁻¹') +exameters_per_square_picosecond = NamedUnit(1e+42, Dimensions(length=1, time=-2), name='exameters_per_square_picosecond', ascii_symbol='Em/ps^2', symbol='Emps⁻²') +exameters_per_femtosecond = NamedUnit(1e+33, Dimensions(length=1, time=-1), name='exameters_per_femtosecond', ascii_symbol='Em/fs', symbol='Emfs⁻¹') +exameters_per_square_femtosecond = NamedUnit(9.999999999999999e+47, Dimensions(length=1, time=-2), name='exameters_per_square_femtosecond', ascii_symbol='Em/fs^2', symbol='Emfs⁻²') +exameters_per_attosecond = NamedUnit(9.999999999999999e+35, Dimensions(length=1, time=-1), name='exameters_per_attosecond', ascii_symbol='Em/as', symbol='Emas⁻¹') +exameters_per_square_attosecond = NamedUnit(9.999999999999999e+53, Dimensions(length=1, time=-2), name='exameters_per_square_attosecond', ascii_symbol='Em/as^2', symbol='Emas⁻²') +exameters_per_minute = NamedUnit(1.6666666666666666e+16, Dimensions(length=1, time=-1), name='exameters_per_minute', ascii_symbol='Em/min', symbol='Emmin⁻¹') +exameters_per_square_minute = NamedUnit(277777777777777.78, Dimensions(length=1, time=-2), name='exameters_per_square_minute', ascii_symbol='Em/min^2', symbol='Emmin⁻²') +exameters_per_hour = NamedUnit(2777777777777778.0, Dimensions(length=1, time=-1), name='exameters_per_hour', ascii_symbol='Em/h', symbol='Emh⁻¹') +exameters_per_square_hour = NamedUnit(7716049382716.05, Dimensions(length=1, time=-2), name='exameters_per_square_hour', ascii_symbol='Em/h^2', symbol='Emh⁻²') +exameters_per_day = NamedUnit(115740740740740.73, Dimensions(length=1, time=-1), name='exameters_per_day', ascii_symbol='Em/d', symbol='Emd⁻¹') +exameters_per_square_day = NamedUnit(13395919067.215364, Dimensions(length=1, time=-2), name='exameters_per_square_day', ascii_symbol='Em/d^2', symbol='Emd⁻²') +exameters_per_year = NamedUnit(316887385068.1143, Dimensions(length=1, time=-1), name='exameters_per_year', ascii_symbol='Em/y', symbol='Emy⁻¹') +exameters_per_square_year = NamedUnit(100417.61481530734, Dimensions(length=1, time=-2), name='exameters_per_square_year', ascii_symbol='Em/y^2', symbol='Emy⁻²') +petameters_per_second = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='petameters_per_second', ascii_symbol='Pm/s', symbol='Pms⁻¹') +petameters_per_square_second = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='petameters_per_square_second', ascii_symbol='Pm/s^2', symbol='Pms⁻²') +petameters_per_millisecond = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='petameters_per_millisecond', ascii_symbol='Pm/ms', symbol='Pmms⁻¹') +petameters_per_square_millisecond = NamedUnit(1e+21, Dimensions(length=1, time=-2), name='petameters_per_square_millisecond', ascii_symbol='Pm/ms^2', symbol='Pmms⁻²') +petameters_per_microsecond = NamedUnit(1e+21, Dimensions(length=1, time=-1), name='petameters_per_microsecond', ascii_symbol='Pm/us', symbol='Pmµs⁻¹') +petameters_per_square_microsecond = NamedUnit(1e+27, Dimensions(length=1, time=-2), name='petameters_per_square_microsecond', ascii_symbol='Pm/us^2', symbol='Pmµs⁻²') +petameters_per_nanosecond = NamedUnit(1e+24, Dimensions(length=1, time=-1), name='petameters_per_nanosecond', ascii_symbol='Pm/ns', symbol='Pmns⁻¹') +petameters_per_square_nanosecond = NamedUnit(1e+33, Dimensions(length=1, time=-2), name='petameters_per_square_nanosecond', ascii_symbol='Pm/ns^2', symbol='Pmns⁻²') +petameters_per_picosecond = NamedUnit(1e+27, Dimensions(length=1, time=-1), name='petameters_per_picosecond', ascii_symbol='Pm/ps', symbol='Pmps⁻¹') +petameters_per_square_picosecond = NamedUnit(1.0000000000000001e+39, Dimensions(length=1, time=-2), name='petameters_per_square_picosecond', ascii_symbol='Pm/ps^2', symbol='Pmps⁻²') +petameters_per_femtosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-1), name='petameters_per_femtosecond', ascii_symbol='Pm/fs', symbol='Pmfs⁻¹') +petameters_per_square_femtosecond = NamedUnit(1e+45, Dimensions(length=1, time=-2), name='petameters_per_square_femtosecond', ascii_symbol='Pm/fs^2', symbol='Pmfs⁻²') +petameters_per_attosecond = NamedUnit(1e+33, Dimensions(length=1, time=-1), name='petameters_per_attosecond', ascii_symbol='Pm/as', symbol='Pmas⁻¹') +petameters_per_square_attosecond = NamedUnit(9.999999999999998e+50, Dimensions(length=1, time=-2), name='petameters_per_square_attosecond', ascii_symbol='Pm/as^2', symbol='Pmas⁻²') +petameters_per_minute = NamedUnit(16666666666666.666, Dimensions(length=1, time=-1), name='petameters_per_minute', ascii_symbol='Pm/min', symbol='Pmmin⁻¹') +petameters_per_square_minute = NamedUnit(277777777777.7778, Dimensions(length=1, time=-2), name='petameters_per_square_minute', ascii_symbol='Pm/min^2', symbol='Pmmin⁻²') +petameters_per_hour = NamedUnit(2777777777777.778, Dimensions(length=1, time=-1), name='petameters_per_hour', ascii_symbol='Pm/h', symbol='Pmh⁻¹') +petameters_per_square_hour = NamedUnit(7716049382.716049, Dimensions(length=1, time=-2), name='petameters_per_square_hour', ascii_symbol='Pm/h^2', symbol='Pmh⁻²') +petameters_per_day = NamedUnit(115740740740.74074, Dimensions(length=1, time=-1), name='petameters_per_day', ascii_symbol='Pm/d', symbol='Pmd⁻¹') +petameters_per_square_day = NamedUnit(13395919.067215364, Dimensions(length=1, time=-2), name='petameters_per_square_day', ascii_symbol='Pm/d^2', symbol='Pmd⁻²') +petameters_per_year = NamedUnit(316887385.0681143, Dimensions(length=1, time=-1), name='petameters_per_year', ascii_symbol='Pm/y', symbol='Pmy⁻¹') +petameters_per_square_year = NamedUnit(100.41761481530735, Dimensions(length=1, time=-2), name='petameters_per_square_year', ascii_symbol='Pm/y^2', symbol='Pmy⁻²') +terameters_per_second = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='terameters_per_second', ascii_symbol='Tm/s', symbol='Tms⁻¹') +terameters_per_square_second = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='terameters_per_square_second', ascii_symbol='Tm/s^2', symbol='Tms⁻²') +terameters_per_millisecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='terameters_per_millisecond', ascii_symbol='Tm/ms', symbol='Tmms⁻¹') +terameters_per_square_millisecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='terameters_per_square_millisecond', ascii_symbol='Tm/ms^2', symbol='Tmms⁻²') +terameters_per_microsecond = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='terameters_per_microsecond', ascii_symbol='Tm/us', symbol='Tmµs⁻¹') +terameters_per_square_microsecond = NamedUnit(1e+24, Dimensions(length=1, time=-2), name='terameters_per_square_microsecond', ascii_symbol='Tm/us^2', symbol='Tmµs⁻²') +terameters_per_nanosecond = NamedUnit(1e+21, Dimensions(length=1, time=-1), name='terameters_per_nanosecond', ascii_symbol='Tm/ns', symbol='Tmns⁻¹') +terameters_per_square_nanosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-2), name='terameters_per_square_nanosecond', ascii_symbol='Tm/ns^2', symbol='Tmns⁻²') +terameters_per_picosecond = NamedUnit(1e+24, Dimensions(length=1, time=-1), name='terameters_per_picosecond', ascii_symbol='Tm/ps', symbol='Tmps⁻¹') +terameters_per_square_picosecond = NamedUnit(1e+36, Dimensions(length=1, time=-2), name='terameters_per_square_picosecond', ascii_symbol='Tm/ps^2', symbol='Tmps⁻²') +terameters_per_femtosecond = NamedUnit(9.999999999999999e+26, Dimensions(length=1, time=-1), name='terameters_per_femtosecond', ascii_symbol='Tm/fs', symbol='Tmfs⁻¹') +terameters_per_square_femtosecond = NamedUnit(9.999999999999999e+41, Dimensions(length=1, time=-2), name='terameters_per_square_femtosecond', ascii_symbol='Tm/fs^2', symbol='Tmfs⁻²') +terameters_per_attosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-1), name='terameters_per_attosecond', ascii_symbol='Tm/as', symbol='Tmas⁻¹') +terameters_per_square_attosecond = NamedUnit(9.999999999999999e+47, Dimensions(length=1, time=-2), name='terameters_per_square_attosecond', ascii_symbol='Tm/as^2', symbol='Tmas⁻²') +terameters_per_minute = NamedUnit(16666666666.666666, Dimensions(length=1, time=-1), name='terameters_per_minute', ascii_symbol='Tm/min', symbol='Tmmin⁻¹') +terameters_per_square_minute = NamedUnit(277777777.7777778, Dimensions(length=1, time=-2), name='terameters_per_square_minute', ascii_symbol='Tm/min^2', symbol='Tmmin⁻²') +terameters_per_hour = NamedUnit(2777777777.7777777, Dimensions(length=1, time=-1), name='terameters_per_hour', ascii_symbol='Tm/h', symbol='Tmh⁻¹') +terameters_per_square_hour = NamedUnit(7716049.382716049, Dimensions(length=1, time=-2), name='terameters_per_square_hour', ascii_symbol='Tm/h^2', symbol='Tmh⁻²') +terameters_per_day = NamedUnit(115740740.74074075, Dimensions(length=1, time=-1), name='terameters_per_day', ascii_symbol='Tm/d', symbol='Tmd⁻¹') +terameters_per_square_day = NamedUnit(13395.919067215364, Dimensions(length=1, time=-2), name='terameters_per_square_day', ascii_symbol='Tm/d^2', symbol='Tmd⁻²') +terameters_per_year = NamedUnit(316887.38506811426, Dimensions(length=1, time=-1), name='terameters_per_year', ascii_symbol='Tm/y', symbol='Tmy⁻¹') +terameters_per_square_year = NamedUnit(0.10041761481530735, Dimensions(length=1, time=-2), name='terameters_per_square_year', ascii_symbol='Tm/y^2', symbol='Tmy⁻²') +gigameters_per_second = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='gigameters_per_second', ascii_symbol='Gm/s', symbol='Gms⁻¹') +gigameters_per_square_second = NamedUnit(1000000000.0, Dimensions(length=1, time=-2), name='gigameters_per_square_second', ascii_symbol='Gm/s^2', symbol='Gms⁻²') +gigameters_per_millisecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='gigameters_per_millisecond', ascii_symbol='Gm/ms', symbol='Gmms⁻¹') +gigameters_per_square_millisecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='gigameters_per_square_millisecond', ascii_symbol='Gm/ms^2', symbol='Gmms⁻²') +gigameters_per_microsecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='gigameters_per_microsecond', ascii_symbol='Gm/us', symbol='Gmµs⁻¹') +gigameters_per_square_microsecond = NamedUnit(1e+21, Dimensions(length=1, time=-2), name='gigameters_per_square_microsecond', ascii_symbol='Gm/us^2', symbol='Gmµs⁻²') +gigameters_per_nanosecond = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='gigameters_per_nanosecond', ascii_symbol='Gm/ns', symbol='Gmns⁻¹') +gigameters_per_square_nanosecond = NamedUnit(9.999999999999999e+26, Dimensions(length=1, time=-2), name='gigameters_per_square_nanosecond', ascii_symbol='Gm/ns^2', symbol='Gmns⁻²') +gigameters_per_picosecond = NamedUnit(1e+21, Dimensions(length=1, time=-1), name='gigameters_per_picosecond', ascii_symbol='Gm/ps', symbol='Gmps⁻¹') +gigameters_per_square_picosecond = NamedUnit(1.0000000000000001e+33, Dimensions(length=1, time=-2), name='gigameters_per_square_picosecond', ascii_symbol='Gm/ps^2', symbol='Gmps⁻²') +gigameters_per_femtosecond = NamedUnit(1e+24, Dimensions(length=1, time=-1), name='gigameters_per_femtosecond', ascii_symbol='Gm/fs', symbol='Gmfs⁻¹') +gigameters_per_square_femtosecond = NamedUnit(1e+39, Dimensions(length=1, time=-2), name='gigameters_per_square_femtosecond', ascii_symbol='Gm/fs^2', symbol='Gmfs⁻²') +gigameters_per_attosecond = NamedUnit(9.999999999999999e+26, Dimensions(length=1, time=-1), name='gigameters_per_attosecond', ascii_symbol='Gm/as', symbol='Gmas⁻¹') +gigameters_per_square_attosecond = NamedUnit(1e+45, Dimensions(length=1, time=-2), name='gigameters_per_square_attosecond', ascii_symbol='Gm/as^2', symbol='Gmas⁻²') +gigameters_per_minute = NamedUnit(16666666.666666666, Dimensions(length=1, time=-1), name='gigameters_per_minute', ascii_symbol='Gm/min', symbol='Gmmin⁻¹') +gigameters_per_square_minute = NamedUnit(277777.77777777775, Dimensions(length=1, time=-2), name='gigameters_per_square_minute', ascii_symbol='Gm/min^2', symbol='Gmmin⁻²') +gigameters_per_hour = NamedUnit(2777777.777777778, Dimensions(length=1, time=-1), name='gigameters_per_hour', ascii_symbol='Gm/h', symbol='Gmh⁻¹') +gigameters_per_square_hour = NamedUnit(7716.049382716049, Dimensions(length=1, time=-2), name='gigameters_per_square_hour', ascii_symbol='Gm/h^2', symbol='Gmh⁻²') +gigameters_per_day = NamedUnit(115740.74074074074, Dimensions(length=1, time=-1), name='gigameters_per_day', ascii_symbol='Gm/d', symbol='Gmd⁻¹') +gigameters_per_square_day = NamedUnit(13.395919067215363, Dimensions(length=1, time=-2), name='gigameters_per_square_day', ascii_symbol='Gm/d^2', symbol='Gmd⁻²') +gigameters_per_year = NamedUnit(316.88738506811427, Dimensions(length=1, time=-1), name='gigameters_per_year', ascii_symbol='Gm/y', symbol='Gmy⁻¹') +gigameters_per_square_year = NamedUnit(0.00010041761481530735, Dimensions(length=1, time=-2), name='gigameters_per_square_year', ascii_symbol='Gm/y^2', symbol='Gmy⁻²') +megameters_per_second = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='megameters_per_second', ascii_symbol='Mm/s', symbol='Mms⁻¹') +megameters_per_square_second = NamedUnit(1000000.0, Dimensions(length=1, time=-2), name='megameters_per_square_second', ascii_symbol='Mm/s^2', symbol='Mms⁻²') +megameters_per_millisecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='megameters_per_millisecond', ascii_symbol='Mm/ms', symbol='Mmms⁻¹') +megameters_per_square_millisecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='megameters_per_square_millisecond', ascii_symbol='Mm/ms^2', symbol='Mmms⁻²') +megameters_per_microsecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='megameters_per_microsecond', ascii_symbol='Mm/us', symbol='Mmµs⁻¹') +megameters_per_square_microsecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='megameters_per_square_microsecond', ascii_symbol='Mm/us^2', symbol='Mmµs⁻²') +megameters_per_nanosecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='megameters_per_nanosecond', ascii_symbol='Mm/ns', symbol='Mmns⁻¹') +megameters_per_square_nanosecond = NamedUnit(1e+24, Dimensions(length=1, time=-2), name='megameters_per_square_nanosecond', ascii_symbol='Mm/ns^2', symbol='Mmns⁻²') +megameters_per_picosecond = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='megameters_per_picosecond', ascii_symbol='Mm/ps', symbol='Mmps⁻¹') +megameters_per_square_picosecond = NamedUnit(1e+30, Dimensions(length=1, time=-2), name='megameters_per_square_picosecond', ascii_symbol='Mm/ps^2', symbol='Mmps⁻²') +megameters_per_femtosecond = NamedUnit(9.999999999999999e+20, Dimensions(length=1, time=-1), name='megameters_per_femtosecond', ascii_symbol='Mm/fs', symbol='Mmfs⁻¹') +megameters_per_square_femtosecond = NamedUnit(9.999999999999999e+35, Dimensions(length=1, time=-2), name='megameters_per_square_femtosecond', ascii_symbol='Mm/fs^2', symbol='Mmfs⁻²') +megameters_per_attosecond = NamedUnit(1e+24, Dimensions(length=1, time=-1), name='megameters_per_attosecond', ascii_symbol='Mm/as', symbol='Mmas⁻¹') +megameters_per_square_attosecond = NamedUnit(9.999999999999999e+41, Dimensions(length=1, time=-2), name='megameters_per_square_attosecond', ascii_symbol='Mm/as^2', symbol='Mmas⁻²') +megameters_per_minute = NamedUnit(16666.666666666668, Dimensions(length=1, time=-1), name='megameters_per_minute', ascii_symbol='Mm/min', symbol='Mmmin⁻¹') +megameters_per_square_minute = NamedUnit(277.77777777777777, Dimensions(length=1, time=-2), name='megameters_per_square_minute', ascii_symbol='Mm/min^2', symbol='Mmmin⁻²') +megameters_per_hour = NamedUnit(2777.777777777778, Dimensions(length=1, time=-1), name='megameters_per_hour', ascii_symbol='Mm/h', symbol='Mmh⁻¹') +megameters_per_square_hour = NamedUnit(7.716049382716049, Dimensions(length=1, time=-2), name='megameters_per_square_hour', ascii_symbol='Mm/h^2', symbol='Mmh⁻²') +megameters_per_day = NamedUnit(115.74074074074075, Dimensions(length=1, time=-1), name='megameters_per_day', ascii_symbol='Mm/d', symbol='Mmd⁻¹') +megameters_per_square_day = NamedUnit(0.013395919067215363, Dimensions(length=1, time=-2), name='megameters_per_square_day', ascii_symbol='Mm/d^2', symbol='Mmd⁻²') +megameters_per_year = NamedUnit(0.3168873850681143, Dimensions(length=1, time=-1), name='megameters_per_year', ascii_symbol='Mm/y', symbol='Mmy⁻¹') +megameters_per_square_year = NamedUnit(1.0041761481530735e-07, Dimensions(length=1, time=-2), name='megameters_per_square_year', ascii_symbol='Mm/y^2', symbol='Mmy⁻²') +kilometers_per_second = NamedUnit(1000.0, Dimensions(length=1, time=-1), name='kilometers_per_second', ascii_symbol='km/s', symbol='kms⁻¹') +kilometers_per_square_second = NamedUnit(1000.0, Dimensions(length=1, time=-2), name='kilometers_per_square_second', ascii_symbol='km/s^2', symbol='kms⁻²') +kilometers_per_millisecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='kilometers_per_millisecond', ascii_symbol='km/ms', symbol='kmms⁻¹') +kilometers_per_square_millisecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-2), name='kilometers_per_square_millisecond', ascii_symbol='km/ms^2', symbol='kmms⁻²') +kilometers_per_microsecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='kilometers_per_microsecond', ascii_symbol='km/us', symbol='kmµs⁻¹') +kilometers_per_square_microsecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='kilometers_per_square_microsecond', ascii_symbol='km/us^2', symbol='kmµs⁻²') +kilometers_per_nanosecond = NamedUnit(999999999999.9999, Dimensions(length=1, time=-1), name='kilometers_per_nanosecond', ascii_symbol='km/ns', symbol='kmns⁻¹') +kilometers_per_square_nanosecond = NamedUnit(9.999999999999999e+20, Dimensions(length=1, time=-2), name='kilometers_per_square_nanosecond', ascii_symbol='km/ns^2', symbol='kmns⁻²') +kilometers_per_picosecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='kilometers_per_picosecond', ascii_symbol='km/ps', symbol='kmps⁻¹') +kilometers_per_square_picosecond = NamedUnit(1e+27, Dimensions(length=1, time=-2), name='kilometers_per_square_picosecond', ascii_symbol='km/ps^2', symbol='kmps⁻²') +kilometers_per_femtosecond = NamedUnit(9.999999999999999e+17, Dimensions(length=1, time=-1), name='kilometers_per_femtosecond', ascii_symbol='km/fs', symbol='kmfs⁻¹') +kilometers_per_square_femtosecond = NamedUnit(1e+33, Dimensions(length=1, time=-2), name='kilometers_per_square_femtosecond', ascii_symbol='km/fs^2', symbol='kmfs⁻²') +kilometers_per_attosecond = NamedUnit(9.999999999999999e+20, Dimensions(length=1, time=-1), name='kilometers_per_attosecond', ascii_symbol='km/as', symbol='kmas⁻¹') +kilometers_per_square_attosecond = NamedUnit(1e+39, Dimensions(length=1, time=-2), name='kilometers_per_square_attosecond', ascii_symbol='km/as^2', symbol='kmas⁻²') +kilometers_per_minute = NamedUnit(16.666666666666668, Dimensions(length=1, time=-1), name='kilometers_per_minute', ascii_symbol='km/min', symbol='kmmin⁻¹') +kilometers_per_square_minute = NamedUnit(0.2777777777777778, Dimensions(length=1, time=-2), name='kilometers_per_square_minute', ascii_symbol='km/min^2', symbol='kmmin⁻²') +kilometers_per_hour = NamedUnit(2.7777777777777777, Dimensions(length=1, time=-1), name='kilometers_per_hour', ascii_symbol='km/h', symbol='kmh⁻¹') +kilometers_per_square_hour = NamedUnit(0.007716049382716049, Dimensions(length=1, time=-2), name='kilometers_per_square_hour', ascii_symbol='km/h^2', symbol='kmh⁻²') +kilometers_per_day = NamedUnit(0.11574074074074074, Dimensions(length=1, time=-1), name='kilometers_per_day', ascii_symbol='km/d', symbol='kmd⁻¹') +kilometers_per_square_day = NamedUnit(1.3395919067215363e-05, Dimensions(length=1, time=-2), name='kilometers_per_square_day', ascii_symbol='km/d^2', symbol='kmd⁻²') +kilometers_per_year = NamedUnit(0.0003168873850681143, Dimensions(length=1, time=-1), name='kilometers_per_year', ascii_symbol='km/y', symbol='kmy⁻¹') +kilometers_per_square_year = NamedUnit(1.0041761481530735e-10, Dimensions(length=1, time=-2), name='kilometers_per_square_year', ascii_symbol='km/y^2', symbol='kmy⁻²') +millimeters_per_second = NamedUnit(0.001, Dimensions(length=1, time=-1), name='millimeters_per_second', ascii_symbol='mm/s', symbol='mms⁻¹') +millimeters_per_square_second = NamedUnit(0.001, Dimensions(length=1, time=-2), name='millimeters_per_square_second', ascii_symbol='mm/s^2', symbol='mms⁻²') +millimeters_per_millisecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='millimeters_per_millisecond', ascii_symbol='mm/ms', symbol='mmms⁻¹') +millimeters_per_square_millisecond = NamedUnit(1000.0000000000001, Dimensions(length=1, time=-2), name='millimeters_per_square_millisecond', ascii_symbol='mm/ms^2', symbol='mmms⁻²') +millimeters_per_microsecond = NamedUnit(1000.0000000000001, Dimensions(length=1, time=-1), name='millimeters_per_microsecond', ascii_symbol='mm/us', symbol='mmµs⁻¹') +millimeters_per_square_microsecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-2), name='millimeters_per_square_microsecond', ascii_symbol='mm/us^2', symbol='mmµs⁻²') +millimeters_per_nanosecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='millimeters_per_nanosecond', ascii_symbol='mm/ns', symbol='mmns⁻¹') +millimeters_per_square_nanosecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='millimeters_per_square_nanosecond', ascii_symbol='mm/ns^2', symbol='mmns⁻²') +millimeters_per_picosecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='millimeters_per_picosecond', ascii_symbol='mm/ps', symbol='mmps⁻¹') +millimeters_per_square_picosecond = NamedUnit(1.0000000000000001e+21, Dimensions(length=1, time=-2), name='millimeters_per_square_picosecond', ascii_symbol='mm/ps^2', symbol='mmps⁻²') +millimeters_per_femtosecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='millimeters_per_femtosecond', ascii_symbol='mm/fs', symbol='mmfs⁻¹') +millimeters_per_square_femtosecond = NamedUnit(9.999999999999999e+26, Dimensions(length=1, time=-2), name='millimeters_per_square_femtosecond', ascii_symbol='mm/fs^2', symbol='mmfs⁻²') +millimeters_per_attosecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='millimeters_per_attosecond', ascii_symbol='mm/as', symbol='mmas⁻¹') +millimeters_per_square_attosecond = NamedUnit(1e+33, Dimensions(length=1, time=-2), name='millimeters_per_square_attosecond', ascii_symbol='mm/as^2', symbol='mmas⁻²') +millimeters_per_minute = NamedUnit(1.6666666666666667e-05, Dimensions(length=1, time=-1), name='millimeters_per_minute', ascii_symbol='mm/min', symbol='mmmin⁻¹') +millimeters_per_square_minute = NamedUnit(2.7777777777777776e-07, Dimensions(length=1, time=-2), name='millimeters_per_square_minute', ascii_symbol='mm/min^2', symbol='mmmin⁻²') +millimeters_per_hour = NamedUnit(2.777777777777778e-06, Dimensions(length=1, time=-1), name='millimeters_per_hour', ascii_symbol='mm/h', symbol='mmh⁻¹') +millimeters_per_square_hour = NamedUnit(7.71604938271605e-09, Dimensions(length=1, time=-2), name='millimeters_per_square_hour', ascii_symbol='mm/h^2', symbol='mmh⁻²') +millimeters_per_day = NamedUnit(1.1574074074074074e-07, Dimensions(length=1, time=-1), name='millimeters_per_day', ascii_symbol='mm/d', symbol='mmd⁻¹') +millimeters_per_square_day = NamedUnit(1.3395919067215364e-11, Dimensions(length=1, time=-2), name='millimeters_per_square_day', ascii_symbol='mm/d^2', symbol='mmd⁻²') +millimeters_per_year = NamedUnit(3.168873850681143e-10, Dimensions(length=1, time=-1), name='millimeters_per_year', ascii_symbol='mm/y', symbol='mmy⁻¹') +millimeters_per_square_year = NamedUnit(1.0041761481530735e-16, Dimensions(length=1, time=-2), name='millimeters_per_square_year', ascii_symbol='mm/y^2', symbol='mmy⁻²') +micrometers_per_second = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='micrometers_per_second', ascii_symbol='um/s', symbol='µms⁻¹') +micrometers_per_square_second = NamedUnit(1e-06, Dimensions(length=1, time=-2), name='micrometers_per_square_second', ascii_symbol='um/s^2', symbol='µms⁻²') +micrometers_per_millisecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='micrometers_per_millisecond', ascii_symbol='um/ms', symbol='µmms⁻¹') +micrometers_per_square_millisecond = NamedUnit(1.0, Dimensions(length=1, time=-2), name='micrometers_per_square_millisecond', ascii_symbol='um/ms^2', symbol='µmms⁻²') +micrometers_per_microsecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='micrometers_per_microsecond', ascii_symbol='um/us', symbol='µmµs⁻¹') +micrometers_per_square_microsecond = NamedUnit(1000000.0, Dimensions(length=1, time=-2), name='micrometers_per_square_microsecond', ascii_symbol='um/us^2', symbol='µmµs⁻²') +micrometers_per_nanosecond = NamedUnit(999.9999999999999, Dimensions(length=1, time=-1), name='micrometers_per_nanosecond', ascii_symbol='um/ns', symbol='µmns⁻¹') +micrometers_per_square_nanosecond = NamedUnit(999999999999.9999, Dimensions(length=1, time=-2), name='micrometers_per_square_nanosecond', ascii_symbol='um/ns^2', symbol='µmns⁻²') +micrometers_per_picosecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='micrometers_per_picosecond', ascii_symbol='um/ps', symbol='µmps⁻¹') +micrometers_per_square_picosecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='micrometers_per_square_picosecond', ascii_symbol='um/ps^2', symbol='µmps⁻²') +micrometers_per_femtosecond = NamedUnit(999999999.9999999, Dimensions(length=1, time=-1), name='micrometers_per_femtosecond', ascii_symbol='um/fs', symbol='µmfs⁻¹') +micrometers_per_square_femtosecond = NamedUnit(9.999999999999998e+23, Dimensions(length=1, time=-2), name='micrometers_per_square_femtosecond', ascii_symbol='um/fs^2', symbol='µmfs⁻²') +micrometers_per_attosecond = NamedUnit(999999999999.9999, Dimensions(length=1, time=-1), name='micrometers_per_attosecond', ascii_symbol='um/as', symbol='µmas⁻¹') +micrometers_per_square_attosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-2), name='micrometers_per_square_attosecond', ascii_symbol='um/as^2', symbol='µmas⁻²') +micrometers_per_minute = NamedUnit(1.6666666666666667e-08, Dimensions(length=1, time=-1), name='micrometers_per_minute', ascii_symbol='um/min', symbol='µmmin⁻¹') +micrometers_per_square_minute = NamedUnit(2.7777777777777777e-10, Dimensions(length=1, time=-2), name='micrometers_per_square_minute', ascii_symbol='um/min^2', symbol='µmmin⁻²') +micrometers_per_hour = NamedUnit(2.7777777777777776e-09, Dimensions(length=1, time=-1), name='micrometers_per_hour', ascii_symbol='um/h', symbol='µmh⁻¹') +micrometers_per_square_hour = NamedUnit(7.716049382716049e-12, Dimensions(length=1, time=-2), name='micrometers_per_square_hour', ascii_symbol='um/h^2', symbol='µmh⁻²') +micrometers_per_day = NamedUnit(1.1574074074074074e-10, Dimensions(length=1, time=-1), name='micrometers_per_day', ascii_symbol='um/d', symbol='µmd⁻¹') +micrometers_per_square_day = NamedUnit(1.3395919067215363e-14, Dimensions(length=1, time=-2), name='micrometers_per_square_day', ascii_symbol='um/d^2', symbol='µmd⁻²') +micrometers_per_year = NamedUnit(3.168873850681143e-13, Dimensions(length=1, time=-1), name='micrometers_per_year', ascii_symbol='um/y', symbol='µmy⁻¹') +micrometers_per_square_year = NamedUnit(1.0041761481530734e-19, Dimensions(length=1, time=-2), name='micrometers_per_square_year', ascii_symbol='um/y^2', symbol='µmy⁻²') +nanometers_per_second = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='nanometers_per_second', ascii_symbol='nm/s', symbol='nms⁻¹') +nanometers_per_square_second = NamedUnit(1e-09, Dimensions(length=1, time=-2), name='nanometers_per_square_second', ascii_symbol='nm/s^2', symbol='nms⁻²') +nanometers_per_millisecond = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='nanometers_per_millisecond', ascii_symbol='nm/ms', symbol='nmms⁻¹') +nanometers_per_square_millisecond = NamedUnit(0.001, Dimensions(length=1, time=-2), name='nanometers_per_square_millisecond', ascii_symbol='nm/ms^2', symbol='nmms⁻²') +nanometers_per_microsecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='nanometers_per_microsecond', ascii_symbol='nm/us', symbol='nmµs⁻¹') +nanometers_per_square_microsecond = NamedUnit(1000.0000000000001, Dimensions(length=1, time=-2), name='nanometers_per_square_microsecond', ascii_symbol='nm/us^2', symbol='nmµs⁻²') +nanometers_per_nanosecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='nanometers_per_nanosecond', ascii_symbol='nm/ns', symbol='nmns⁻¹') +nanometers_per_square_nanosecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-2), name='nanometers_per_square_nanosecond', ascii_symbol='nm/ns^2', symbol='nmns⁻²') +nanometers_per_picosecond = NamedUnit(1000.0000000000001, Dimensions(length=1, time=-1), name='nanometers_per_picosecond', ascii_symbol='nm/ps', symbol='nmps⁻¹') +nanometers_per_square_picosecond = NamedUnit(1000000000000000.1, Dimensions(length=1, time=-2), name='nanometers_per_square_picosecond', ascii_symbol='nm/ps^2', symbol='nmps⁻²') +nanometers_per_femtosecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='nanometers_per_femtosecond', ascii_symbol='nm/fs', symbol='nmfs⁻¹') +nanometers_per_square_femtosecond = NamedUnit(1e+21, Dimensions(length=1, time=-2), name='nanometers_per_square_femtosecond', ascii_symbol='nm/fs^2', symbol='nmfs⁻²') +nanometers_per_attosecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='nanometers_per_attosecond', ascii_symbol='nm/as', symbol='nmas⁻¹') +nanometers_per_square_attosecond = NamedUnit(1e+27, Dimensions(length=1, time=-2), name='nanometers_per_square_attosecond', ascii_symbol='nm/as^2', symbol='nmas⁻²') +nanometers_per_minute = NamedUnit(1.6666666666666667e-11, Dimensions(length=1, time=-1), name='nanometers_per_minute', ascii_symbol='nm/min', symbol='nmmin⁻¹') +nanometers_per_square_minute = NamedUnit(2.777777777777778e-13, Dimensions(length=1, time=-2), name='nanometers_per_square_minute', ascii_symbol='nm/min^2', symbol='nmmin⁻²') +nanometers_per_hour = NamedUnit(2.777777777777778e-12, Dimensions(length=1, time=-1), name='nanometers_per_hour', ascii_symbol='nm/h', symbol='nmh⁻¹') +nanometers_per_square_hour = NamedUnit(7.71604938271605e-15, Dimensions(length=1, time=-2), name='nanometers_per_square_hour', ascii_symbol='nm/h^2', symbol='nmh⁻²') +nanometers_per_day = NamedUnit(1.1574074074074076e-13, Dimensions(length=1, time=-1), name='nanometers_per_day', ascii_symbol='nm/d', symbol='nmd⁻¹') +nanometers_per_square_day = NamedUnit(1.3395919067215365e-17, Dimensions(length=1, time=-2), name='nanometers_per_square_day', ascii_symbol='nm/d^2', symbol='nmd⁻²') +nanometers_per_year = NamedUnit(3.1688738506811433e-16, Dimensions(length=1, time=-1), name='nanometers_per_year', ascii_symbol='nm/y', symbol='nmy⁻¹') +nanometers_per_square_year = NamedUnit(1.0041761481530736e-22, Dimensions(length=1, time=-2), name='nanometers_per_square_year', ascii_symbol='nm/y^2', symbol='nmy⁻²') +picometers_per_second = NamedUnit(1e-12, Dimensions(length=1, time=-1), name='picometers_per_second', ascii_symbol='pm/s', symbol='pms⁻¹') +picometers_per_square_second = NamedUnit(1e-12, Dimensions(length=1, time=-2), name='picometers_per_square_second', ascii_symbol='pm/s^2', symbol='pms⁻²') +picometers_per_millisecond = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='picometers_per_millisecond', ascii_symbol='pm/ms', symbol='pmms⁻¹') +picometers_per_square_millisecond = NamedUnit(1e-06, Dimensions(length=1, time=-2), name='picometers_per_square_millisecond', ascii_symbol='pm/ms^2', symbol='pmms⁻²') +picometers_per_microsecond = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='picometers_per_microsecond', ascii_symbol='pm/us', symbol='pmµs⁻¹') +picometers_per_square_microsecond = NamedUnit(1.0, Dimensions(length=1, time=-2), name='picometers_per_square_microsecond', ascii_symbol='pm/us^2', symbol='pmµs⁻²') +picometers_per_nanosecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='picometers_per_nanosecond', ascii_symbol='pm/ns', symbol='pmns⁻¹') +picometers_per_square_nanosecond = NamedUnit(999999.9999999999, Dimensions(length=1, time=-2), name='picometers_per_square_nanosecond', ascii_symbol='pm/ns^2', symbol='pmns⁻²') +picometers_per_picosecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='picometers_per_picosecond', ascii_symbol='pm/ps', symbol='pmps⁻¹') +picometers_per_square_picosecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='picometers_per_square_picosecond', ascii_symbol='pm/ps^2', symbol='pmps⁻²') +picometers_per_femtosecond = NamedUnit(999.9999999999999, Dimensions(length=1, time=-1), name='picometers_per_femtosecond', ascii_symbol='pm/fs', symbol='pmfs⁻¹') +picometers_per_square_femtosecond = NamedUnit(9.999999999999999e+17, Dimensions(length=1, time=-2), name='picometers_per_square_femtosecond', ascii_symbol='pm/fs^2', symbol='pmfs⁻²') +picometers_per_attosecond = NamedUnit(999999.9999999999, Dimensions(length=1, time=-1), name='picometers_per_attosecond', ascii_symbol='pm/as', symbol='pmas⁻¹') +picometers_per_square_attosecond = NamedUnit(9.999999999999998e+23, Dimensions(length=1, time=-2), name='picometers_per_square_attosecond', ascii_symbol='pm/as^2', symbol='pmas⁻²') +picometers_per_minute = NamedUnit(1.6666666666666667e-14, Dimensions(length=1, time=-1), name='picometers_per_minute', ascii_symbol='pm/min', symbol='pmmin⁻¹') +picometers_per_square_minute = NamedUnit(2.7777777777777775e-16, Dimensions(length=1, time=-2), name='picometers_per_square_minute', ascii_symbol='pm/min^2', symbol='pmmin⁻²') +picometers_per_hour = NamedUnit(2.7777777777777776e-15, Dimensions(length=1, time=-1), name='picometers_per_hour', ascii_symbol='pm/h', symbol='pmh⁻¹') +picometers_per_square_hour = NamedUnit(7.716049382716049e-18, Dimensions(length=1, time=-2), name='picometers_per_square_hour', ascii_symbol='pm/h^2', symbol='pmh⁻²') +picometers_per_day = NamedUnit(1.1574074074074073e-16, Dimensions(length=1, time=-1), name='picometers_per_day', ascii_symbol='pm/d', symbol='pmd⁻¹') +picometers_per_square_day = NamedUnit(1.3395919067215364e-20, Dimensions(length=1, time=-2), name='picometers_per_square_day', ascii_symbol='pm/d^2', symbol='pmd⁻²') +picometers_per_year = NamedUnit(3.168873850681143e-19, Dimensions(length=1, time=-1), name='picometers_per_year', ascii_symbol='pm/y', symbol='pmy⁻¹') +picometers_per_square_year = NamedUnit(1.0041761481530734e-25, Dimensions(length=1, time=-2), name='picometers_per_square_year', ascii_symbol='pm/y^2', symbol='pmy⁻²') +femtometers_per_second = NamedUnit(1e-15, Dimensions(length=1, time=-1), name='femtometers_per_second', ascii_symbol='fm/s', symbol='fms⁻¹') +femtometers_per_square_second = NamedUnit(1e-15, Dimensions(length=1, time=-2), name='femtometers_per_square_second', ascii_symbol='fm/s^2', symbol='fms⁻²') +femtometers_per_millisecond = NamedUnit(1e-12, Dimensions(length=1, time=-1), name='femtometers_per_millisecond', ascii_symbol='fm/ms', symbol='fmms⁻¹') +femtometers_per_square_millisecond = NamedUnit(1e-09, Dimensions(length=1, time=-2), name='femtometers_per_square_millisecond', ascii_symbol='fm/ms^2', symbol='fmms⁻²') +femtometers_per_microsecond = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='femtometers_per_microsecond', ascii_symbol='fm/us', symbol='fmµs⁻¹') +femtometers_per_square_microsecond = NamedUnit(0.001, Dimensions(length=1, time=-2), name='femtometers_per_square_microsecond', ascii_symbol='fm/us^2', symbol='fmµs⁻²') +femtometers_per_nanosecond = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='femtometers_per_nanosecond', ascii_symbol='fm/ns', symbol='fmns⁻¹') +femtometers_per_square_nanosecond = NamedUnit(1000.0, Dimensions(length=1, time=-2), name='femtometers_per_square_nanosecond', ascii_symbol='fm/ns^2', symbol='fmns⁻²') +femtometers_per_picosecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='femtometers_per_picosecond', ascii_symbol='fm/ps', symbol='fmps⁻¹') +femtometers_per_square_picosecond = NamedUnit(1000000000.0000001, Dimensions(length=1, time=-2), name='femtometers_per_square_picosecond', ascii_symbol='fm/ps^2', symbol='fmps⁻²') +femtometers_per_femtosecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='femtometers_per_femtosecond', ascii_symbol='fm/fs', symbol='fmfs⁻¹') +femtometers_per_square_femtosecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='femtometers_per_square_femtosecond', ascii_symbol='fm/fs^2', symbol='fmfs⁻²') +femtometers_per_attosecond = NamedUnit(1000.0, Dimensions(length=1, time=-1), name='femtometers_per_attosecond', ascii_symbol='fm/as', symbol='fmas⁻¹') +femtometers_per_square_attosecond = NamedUnit(1e+21, Dimensions(length=1, time=-2), name='femtometers_per_square_attosecond', ascii_symbol='fm/as^2', symbol='fmas⁻²') +femtometers_per_minute = NamedUnit(1.6666666666666667e-17, Dimensions(length=1, time=-1), name='femtometers_per_minute', ascii_symbol='fm/min', symbol='fmmin⁻¹') +femtometers_per_square_minute = NamedUnit(2.777777777777778e-19, Dimensions(length=1, time=-2), name='femtometers_per_square_minute', ascii_symbol='fm/min^2', symbol='fmmin⁻²') +femtometers_per_hour = NamedUnit(2.777777777777778e-18, Dimensions(length=1, time=-1), name='femtometers_per_hour', ascii_symbol='fm/h', symbol='fmh⁻¹') +femtometers_per_square_hour = NamedUnit(7.71604938271605e-21, Dimensions(length=1, time=-2), name='femtometers_per_square_hour', ascii_symbol='fm/h^2', symbol='fmh⁻²') +femtometers_per_day = NamedUnit(1.1574074074074075e-19, Dimensions(length=1, time=-1), name='femtometers_per_day', ascii_symbol='fm/d', symbol='fmd⁻¹') +femtometers_per_square_day = NamedUnit(1.3395919067215363e-23, Dimensions(length=1, time=-2), name='femtometers_per_square_day', ascii_symbol='fm/d^2', symbol='fmd⁻²') +femtometers_per_year = NamedUnit(3.168873850681143e-22, Dimensions(length=1, time=-1), name='femtometers_per_year', ascii_symbol='fm/y', symbol='fmy⁻¹') +femtometers_per_square_year = NamedUnit(1.0041761481530735e-28, Dimensions(length=1, time=-2), name='femtometers_per_square_year', ascii_symbol='fm/y^2', symbol='fmy⁻²') +attometers_per_second = NamedUnit(1e-18, Dimensions(length=1, time=-1), name='attometers_per_second', ascii_symbol='am/s', symbol='ams⁻¹') +attometers_per_square_second = NamedUnit(1e-18, Dimensions(length=1, time=-2), name='attometers_per_square_second', ascii_symbol='am/s^2', symbol='ams⁻²') +attometers_per_millisecond = NamedUnit(1e-15, Dimensions(length=1, time=-1), name='attometers_per_millisecond', ascii_symbol='am/ms', symbol='amms⁻¹') +attometers_per_square_millisecond = NamedUnit(1.0000000000000002e-12, Dimensions(length=1, time=-2), name='attometers_per_square_millisecond', ascii_symbol='am/ms^2', symbol='amms⁻²') +attometers_per_microsecond = NamedUnit(1.0000000000000002e-12, Dimensions(length=1, time=-1), name='attometers_per_microsecond', ascii_symbol='am/us', symbol='amµs⁻¹') +attometers_per_square_microsecond = NamedUnit(1.0000000000000002e-06, Dimensions(length=1, time=-2), name='attometers_per_square_microsecond', ascii_symbol='am/us^2', symbol='amµs⁻²') +attometers_per_nanosecond = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='attometers_per_nanosecond', ascii_symbol='am/ns', symbol='amns⁻¹') +attometers_per_square_nanosecond = NamedUnit(1.0, Dimensions(length=1, time=-2), name='attometers_per_square_nanosecond', ascii_symbol='am/ns^2', symbol='amns⁻²') +attometers_per_picosecond = NamedUnit(1.0000000000000002e-06, Dimensions(length=1, time=-1), name='attometers_per_picosecond', ascii_symbol='am/ps', symbol='amps⁻¹') +attometers_per_square_picosecond = NamedUnit(1000000.0000000001, Dimensions(length=1, time=-2), name='attometers_per_square_picosecond', ascii_symbol='am/ps^2', symbol='amps⁻²') +attometers_per_femtosecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='attometers_per_femtosecond', ascii_symbol='am/fs', symbol='amfs⁻¹') +attometers_per_square_femtosecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='attometers_per_square_femtosecond', ascii_symbol='am/fs^2', symbol='amfs⁻²') +attometers_per_attosecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='attometers_per_attosecond', ascii_symbol='am/as', symbol='amas⁻¹') +attometers_per_square_attosecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='attometers_per_square_attosecond', ascii_symbol='am/as^2', symbol='amas⁻²') +attometers_per_minute = NamedUnit(1.6666666666666668e-20, Dimensions(length=1, time=-1), name='attometers_per_minute', ascii_symbol='am/min', symbol='ammin⁻¹') +attometers_per_square_minute = NamedUnit(2.777777777777778e-22, Dimensions(length=1, time=-2), name='attometers_per_square_minute', ascii_symbol='am/min^2', symbol='ammin⁻²') +attometers_per_hour = NamedUnit(2.7777777777777778e-21, Dimensions(length=1, time=-1), name='attometers_per_hour', ascii_symbol='am/h', symbol='amh⁻¹') +attometers_per_square_hour = NamedUnit(7.71604938271605e-24, Dimensions(length=1, time=-2), name='attometers_per_square_hour', ascii_symbol='am/h^2', symbol='amh⁻²') +attometers_per_day = NamedUnit(1.1574074074074074e-22, Dimensions(length=1, time=-1), name='attometers_per_day', ascii_symbol='am/d', symbol='amd⁻¹') +attometers_per_square_day = NamedUnit(1.3395919067215363e-26, Dimensions(length=1, time=-2), name='attometers_per_square_day', ascii_symbol='am/d^2', symbol='amd⁻²') +attometers_per_year = NamedUnit(3.1688738506811433e-25, Dimensions(length=1, time=-1), name='attometers_per_year', ascii_symbol='am/y', symbol='amy⁻¹') +attometers_per_square_year = NamedUnit(1.0041761481530734e-31, Dimensions(length=1, time=-2), name='attometers_per_square_year', ascii_symbol='am/y^2', symbol='amy⁻²') +decimeters_per_second = NamedUnit(0.1, Dimensions(length=1, time=-1), name='decimeters_per_second', ascii_symbol='dm/s', symbol='dms⁻¹') +decimeters_per_square_second = NamedUnit(0.1, Dimensions(length=1, time=-2), name='decimeters_per_square_second', ascii_symbol='dm/s^2', symbol='dms⁻²') +decimeters_per_millisecond = NamedUnit(100.0, Dimensions(length=1, time=-1), name='decimeters_per_millisecond', ascii_symbol='dm/ms', symbol='dmms⁻¹') +decimeters_per_square_millisecond = NamedUnit(100000.00000000001, Dimensions(length=1, time=-2), name='decimeters_per_square_millisecond', ascii_symbol='dm/ms^2', symbol='dmms⁻²') +decimeters_per_microsecond = NamedUnit(100000.00000000001, Dimensions(length=1, time=-1), name='decimeters_per_microsecond', ascii_symbol='dm/us', symbol='dmµs⁻¹') +decimeters_per_square_microsecond = NamedUnit(100000000000.0, Dimensions(length=1, time=-2), name='decimeters_per_square_microsecond', ascii_symbol='dm/us^2', symbol='dmµs⁻²') +decimeters_per_nanosecond = NamedUnit(100000000.0, Dimensions(length=1, time=-1), name='decimeters_per_nanosecond', ascii_symbol='dm/ns', symbol='dmns⁻¹') +decimeters_per_square_nanosecond = NamedUnit(1e+17, Dimensions(length=1, time=-2), name='decimeters_per_square_nanosecond', ascii_symbol='dm/ns^2', symbol='dmns⁻²') +decimeters_per_picosecond = NamedUnit(100000000000.0, Dimensions(length=1, time=-1), name='decimeters_per_picosecond', ascii_symbol='dm/ps', symbol='dmps⁻¹') +decimeters_per_square_picosecond = NamedUnit(1.0000000000000001e+23, Dimensions(length=1, time=-2), name='decimeters_per_square_picosecond', ascii_symbol='dm/ps^2', symbol='dmps⁻²') +decimeters_per_femtosecond = NamedUnit(100000000000000.0, Dimensions(length=1, time=-1), name='decimeters_per_femtosecond', ascii_symbol='dm/fs', symbol='dmfs⁻¹') +decimeters_per_square_femtosecond = NamedUnit(1e+29, Dimensions(length=1, time=-2), name='decimeters_per_square_femtosecond', ascii_symbol='dm/fs^2', symbol='dmfs⁻²') +decimeters_per_attosecond = NamedUnit(1e+17, Dimensions(length=1, time=-1), name='decimeters_per_attosecond', ascii_symbol='dm/as', symbol='dmas⁻¹') +decimeters_per_square_attosecond = NamedUnit(1e+35, Dimensions(length=1, time=-2), name='decimeters_per_square_attosecond', ascii_symbol='dm/as^2', symbol='dmas⁻²') +decimeters_per_minute = NamedUnit(0.0016666666666666668, Dimensions(length=1, time=-1), name='decimeters_per_minute', ascii_symbol='dm/min', symbol='dmmin⁻¹') +decimeters_per_square_minute = NamedUnit(2.777777777777778e-05, Dimensions(length=1, time=-2), name='decimeters_per_square_minute', ascii_symbol='dm/min^2', symbol='dmmin⁻²') +decimeters_per_hour = NamedUnit(0.0002777777777777778, Dimensions(length=1, time=-1), name='decimeters_per_hour', ascii_symbol='dm/h', symbol='dmh⁻¹') +decimeters_per_square_hour = NamedUnit(7.71604938271605e-07, Dimensions(length=1, time=-2), name='decimeters_per_square_hour', ascii_symbol='dm/h^2', symbol='dmh⁻²') +decimeters_per_day = NamedUnit(1.1574074074074075e-05, Dimensions(length=1, time=-1), name='decimeters_per_day', ascii_symbol='dm/d', symbol='dmd⁻¹') +decimeters_per_square_day = NamedUnit(1.3395919067215364e-09, Dimensions(length=1, time=-2), name='decimeters_per_square_day', ascii_symbol='dm/d^2', symbol='dmd⁻²') +decimeters_per_year = NamedUnit(3.168873850681143e-08, Dimensions(length=1, time=-1), name='decimeters_per_year', ascii_symbol='dm/y', symbol='dmy⁻¹') +decimeters_per_square_year = NamedUnit(1.0041761481530735e-14, Dimensions(length=1, time=-2), name='decimeters_per_square_year', ascii_symbol='dm/y^2', symbol='dmy⁻²') +centimeters_per_second = NamedUnit(0.01, Dimensions(length=1, time=-1), name='centimeters_per_second', ascii_symbol='cm/s', symbol='cms⁻¹') +centimeters_per_square_second = NamedUnit(0.01, Dimensions(length=1, time=-2), name='centimeters_per_square_second', ascii_symbol='cm/s^2', symbol='cms⁻²') +centimeters_per_millisecond = NamedUnit(10.0, Dimensions(length=1, time=-1), name='centimeters_per_millisecond', ascii_symbol='cm/ms', symbol='cmms⁻¹') +centimeters_per_square_millisecond = NamedUnit(10000.0, Dimensions(length=1, time=-2), name='centimeters_per_square_millisecond', ascii_symbol='cm/ms^2', symbol='cmms⁻²') +centimeters_per_microsecond = NamedUnit(10000.0, Dimensions(length=1, time=-1), name='centimeters_per_microsecond', ascii_symbol='cm/us', symbol='cmµs⁻¹') +centimeters_per_square_microsecond = NamedUnit(10000000000.0, Dimensions(length=1, time=-2), name='centimeters_per_square_microsecond', ascii_symbol='cm/us^2', symbol='cmµs⁻²') +centimeters_per_nanosecond = NamedUnit(10000000.0, Dimensions(length=1, time=-1), name='centimeters_per_nanosecond', ascii_symbol='cm/ns', symbol='cmns⁻¹') +centimeters_per_square_nanosecond = NamedUnit(1e+16, Dimensions(length=1, time=-2), name='centimeters_per_square_nanosecond', ascii_symbol='cm/ns^2', symbol='cmns⁻²') +centimeters_per_picosecond = NamedUnit(10000000000.0, Dimensions(length=1, time=-1), name='centimeters_per_picosecond', ascii_symbol='cm/ps', symbol='cmps⁻¹') +centimeters_per_square_picosecond = NamedUnit(1e+22, Dimensions(length=1, time=-2), name='centimeters_per_square_picosecond', ascii_symbol='cm/ps^2', symbol='cmps⁻²') +centimeters_per_femtosecond = NamedUnit(10000000000000.0, Dimensions(length=1, time=-1), name='centimeters_per_femtosecond', ascii_symbol='cm/fs', symbol='cmfs⁻¹') +centimeters_per_square_femtosecond = NamedUnit(1e+28, Dimensions(length=1, time=-2), name='centimeters_per_square_femtosecond', ascii_symbol='cm/fs^2', symbol='cmfs⁻²') +centimeters_per_attosecond = NamedUnit(1e+16, Dimensions(length=1, time=-1), name='centimeters_per_attosecond', ascii_symbol='cm/as', symbol='cmas⁻¹') +centimeters_per_square_attosecond = NamedUnit(1e+34, Dimensions(length=1, time=-2), name='centimeters_per_square_attosecond', ascii_symbol='cm/as^2', symbol='cmas⁻²') +centimeters_per_minute = NamedUnit(0.00016666666666666666, Dimensions(length=1, time=-1), name='centimeters_per_minute', ascii_symbol='cm/min', symbol='cmmin⁻¹') +centimeters_per_square_minute = NamedUnit(2.777777777777778e-06, Dimensions(length=1, time=-2), name='centimeters_per_square_minute', ascii_symbol='cm/min^2', symbol='cmmin⁻²') +centimeters_per_hour = NamedUnit(2.777777777777778e-05, Dimensions(length=1, time=-1), name='centimeters_per_hour', ascii_symbol='cm/h', symbol='cmh⁻¹') +centimeters_per_square_hour = NamedUnit(7.71604938271605e-08, Dimensions(length=1, time=-2), name='centimeters_per_square_hour', ascii_symbol='cm/h^2', symbol='cmh⁻²') +centimeters_per_day = NamedUnit(1.1574074074074074e-06, Dimensions(length=1, time=-1), name='centimeters_per_day', ascii_symbol='cm/d', symbol='cmd⁻¹') +centimeters_per_square_day = NamedUnit(1.3395919067215363e-10, Dimensions(length=1, time=-2), name='centimeters_per_square_day', ascii_symbol='cm/d^2', symbol='cmd⁻²') +centimeters_per_year = NamedUnit(3.168873850681143e-09, Dimensions(length=1, time=-1), name='centimeters_per_year', ascii_symbol='cm/y', symbol='cmy⁻¹') +centimeters_per_square_year = NamedUnit(1.0041761481530735e-15, Dimensions(length=1, time=-2), name='centimeters_per_square_year', ascii_symbol='cm/y^2', symbol='cmy⁻²') +angstroms_per_second = NamedUnit(1e-10, Dimensions(length=1, time=-1), name='angstroms_per_second', ascii_symbol='Ang/s', symbol='Ås⁻¹') +angstroms_per_square_second = NamedUnit(1e-10, Dimensions(length=1, time=-2), name='angstroms_per_square_second', ascii_symbol='Ang/s^2', symbol='Ås⁻²') +angstroms_per_millisecond = NamedUnit(1e-07, Dimensions(length=1, time=-1), name='angstroms_per_millisecond', ascii_symbol='Ang/ms', symbol='Åms⁻¹') +angstroms_per_square_millisecond = NamedUnit(0.0001, Dimensions(length=1, time=-2), name='angstroms_per_square_millisecond', ascii_symbol='Ang/ms^2', symbol='Åms⁻²') +angstroms_per_microsecond = NamedUnit(0.0001, Dimensions(length=1, time=-1), name='angstroms_per_microsecond', ascii_symbol='Ang/us', symbol='ŵs⁻¹') +angstroms_per_square_microsecond = NamedUnit(100.0, Dimensions(length=1, time=-2), name='angstroms_per_square_microsecond', ascii_symbol='Ang/us^2', symbol='ŵs⁻²') +angstroms_per_nanosecond = NamedUnit(0.09999999999999999, Dimensions(length=1, time=-1), name='angstroms_per_nanosecond', ascii_symbol='Ang/ns', symbol='Åns⁻¹') +angstroms_per_square_nanosecond = NamedUnit(100000000.0, Dimensions(length=1, time=-2), name='angstroms_per_square_nanosecond', ascii_symbol='Ang/ns^2', symbol='Åns⁻²') +angstroms_per_picosecond = NamedUnit(100.0, Dimensions(length=1, time=-1), name='angstroms_per_picosecond', ascii_symbol='Ang/ps', symbol='Åps⁻¹') +angstroms_per_square_picosecond = NamedUnit(100000000000000.02, Dimensions(length=1, time=-2), name='angstroms_per_square_picosecond', ascii_symbol='Ang/ps^2', symbol='Åps⁻²') +angstroms_per_femtosecond = NamedUnit(100000.0, Dimensions(length=1, time=-1), name='angstroms_per_femtosecond', ascii_symbol='Ang/fs', symbol='Åfs⁻¹') +angstroms_per_square_femtosecond = NamedUnit(1e+20, Dimensions(length=1, time=-2), name='angstroms_per_square_femtosecond', ascii_symbol='Ang/fs^2', symbol='Åfs⁻²') +angstroms_per_attosecond = NamedUnit(100000000.0, Dimensions(length=1, time=-1), name='angstroms_per_attosecond', ascii_symbol='Ang/as', symbol='Åas⁻¹') +angstroms_per_square_attosecond = NamedUnit(9.999999999999999e+25, Dimensions(length=1, time=-2), name='angstroms_per_square_attosecond', ascii_symbol='Ang/as^2', symbol='Åas⁻²') +angstroms_per_minute = NamedUnit(1.6666666666666668e-12, Dimensions(length=1, time=-1), name='angstroms_per_minute', ascii_symbol='Ang/min', symbol='Åmin⁻¹') +angstroms_per_square_minute = NamedUnit(2.7777777777777778e-14, Dimensions(length=1, time=-2), name='angstroms_per_square_minute', ascii_symbol='Ang/min^2', symbol='Åmin⁻²') +angstroms_per_hour = NamedUnit(2.777777777777778e-13, Dimensions(length=1, time=-1), name='angstroms_per_hour', ascii_symbol='Ang/h', symbol='Åh⁻¹') +angstroms_per_square_hour = NamedUnit(7.716049382716049e-16, Dimensions(length=1, time=-2), name='angstroms_per_square_hour', ascii_symbol='Ang/h^2', symbol='Åh⁻²') +angstroms_per_day = NamedUnit(1.1574074074074074e-14, Dimensions(length=1, time=-1), name='angstroms_per_day', ascii_symbol='Ang/d', symbol='Åd⁻¹') +angstroms_per_square_day = NamedUnit(1.3395919067215363e-18, Dimensions(length=1, time=-2), name='angstroms_per_square_day', ascii_symbol='Ang/d^2', symbol='Åd⁻²') +angstroms_per_year = NamedUnit(3.168873850681143e-17, Dimensions(length=1, time=-1), name='angstroms_per_year', ascii_symbol='Ang/y', symbol='Åy⁻¹') +angstroms_per_square_year = NamedUnit(1.0041761481530734e-23, Dimensions(length=1, time=-2), name='angstroms_per_square_year', ascii_symbol='Ang/y^2', symbol='Åy⁻²') +miles_per_second = NamedUnit(1609.344, Dimensions(length=1, time=-1), name='miles_per_second', ascii_symbol='miles/s', symbol='miless⁻¹') +miles_per_square_second = NamedUnit(1609.344, Dimensions(length=1, time=-2), name='miles_per_square_second', ascii_symbol='miles/s^2', symbol='miless⁻²') +miles_per_millisecond = NamedUnit(1609344.0, Dimensions(length=1, time=-1), name='miles_per_millisecond', ascii_symbol='miles/ms', symbol='milesms⁻¹') +miles_per_square_millisecond = NamedUnit(1609344000.0000002, Dimensions(length=1, time=-2), name='miles_per_square_millisecond', ascii_symbol='miles/ms^2', symbol='milesms⁻²') +miles_per_microsecond = NamedUnit(1609344000.0000002, Dimensions(length=1, time=-1), name='miles_per_microsecond', ascii_symbol='miles/us', symbol='milesµs⁻¹') +miles_per_square_microsecond = NamedUnit(1609344000000000.0, Dimensions(length=1, time=-2), name='miles_per_square_microsecond', ascii_symbol='miles/us^2', symbol='milesµs⁻²') +miles_per_nanosecond = NamedUnit(1609344000000.0, Dimensions(length=1, time=-1), name='miles_per_nanosecond', ascii_symbol='miles/ns', symbol='milesns⁻¹') +miles_per_square_nanosecond = NamedUnit(1.609344e+21, Dimensions(length=1, time=-2), name='miles_per_square_nanosecond', ascii_symbol='miles/ns^2', symbol='milesns⁻²') +miles_per_picosecond = NamedUnit(1609344000000000.0, Dimensions(length=1, time=-1), name='miles_per_picosecond', ascii_symbol='miles/ps', symbol='milesps⁻¹') +miles_per_square_picosecond = NamedUnit(1.609344e+27, Dimensions(length=1, time=-2), name='miles_per_square_picosecond', ascii_symbol='miles/ps^2', symbol='milesps⁻²') +miles_per_femtosecond = NamedUnit(1.609344e+18, Dimensions(length=1, time=-1), name='miles_per_femtosecond', ascii_symbol='miles/fs', symbol='milesfs⁻¹') +miles_per_square_femtosecond = NamedUnit(1.609344e+33, Dimensions(length=1, time=-2), name='miles_per_square_femtosecond', ascii_symbol='miles/fs^2', symbol='milesfs⁻²') +miles_per_attosecond = NamedUnit(1.609344e+21, Dimensions(length=1, time=-1), name='miles_per_attosecond', ascii_symbol='miles/as', symbol='milesas⁻¹') +miles_per_square_attosecond = NamedUnit(1.609344e+39, Dimensions(length=1, time=-2), name='miles_per_square_attosecond', ascii_symbol='miles/as^2', symbol='milesas⁻²') +miles_per_minute = NamedUnit(26.822400000000002, Dimensions(length=1, time=-1), name='miles_per_minute', ascii_symbol='miles/min', symbol='milesmin⁻¹') +miles_per_square_minute = NamedUnit(0.44704, Dimensions(length=1, time=-2), name='miles_per_square_minute', ascii_symbol='miles/min^2', symbol='milesmin⁻²') +miles_per_hour = NamedUnit(4.4704, Dimensions(length=1, time=-1), name='miles_per_hour', ascii_symbol='miles/h', symbol='milesh⁻¹') +miles_per_square_hour = NamedUnit(0.012417777777777778, Dimensions(length=1, time=-2), name='miles_per_square_hour', ascii_symbol='miles/h^2', symbol='milesh⁻²') +miles_per_day = NamedUnit(0.18626666666666666, Dimensions(length=1, time=-1), name='miles_per_day', ascii_symbol='miles/d', symbol='milesd⁻¹') +miles_per_square_day = NamedUnit(2.1558641975308643e-05, Dimensions(length=1, time=-2), name='miles_per_square_day', ascii_symbol='miles/d^2', symbol='milesd⁻²') +miles_per_year = NamedUnit(0.0005099808118350593, Dimensions(length=1, time=-1), name='miles_per_year', ascii_symbol='miles/y', symbol='milesy⁻¹') +miles_per_square_year = NamedUnit(1.61606485897326e-10, Dimensions(length=1, time=-2), name='miles_per_square_year', ascii_symbol='miles/y^2', symbol='milesy⁻²') +yards_per_second = NamedUnit(0.9144000000000001, Dimensions(length=1, time=-1), name='yards_per_second', ascii_symbol='yrd/s', symbol='yrds⁻¹') +yards_per_square_second = NamedUnit(0.9144000000000001, Dimensions(length=1, time=-2), name='yards_per_square_second', ascii_symbol='yrd/s^2', symbol='yrds⁻²') +yards_per_millisecond = NamedUnit(914.4000000000001, Dimensions(length=1, time=-1), name='yards_per_millisecond', ascii_symbol='yrd/ms', symbol='yrdms⁻¹') +yards_per_square_millisecond = NamedUnit(914400.0000000001, Dimensions(length=1, time=-2), name='yards_per_square_millisecond', ascii_symbol='yrd/ms^2', symbol='yrdms⁻²') +yards_per_microsecond = NamedUnit(914400.0000000001, Dimensions(length=1, time=-1), name='yards_per_microsecond', ascii_symbol='yrd/us', symbol='yrdµs⁻¹') +yards_per_square_microsecond = NamedUnit(914400000000.0001, Dimensions(length=1, time=-2), name='yards_per_square_microsecond', ascii_symbol='yrd/us^2', symbol='yrdµs⁻²') +yards_per_nanosecond = NamedUnit(914400000.0, Dimensions(length=1, time=-1), name='yards_per_nanosecond', ascii_symbol='yrd/ns', symbol='yrdns⁻¹') +yards_per_square_nanosecond = NamedUnit(9.144e+17, Dimensions(length=1, time=-2), name='yards_per_square_nanosecond', ascii_symbol='yrd/ns^2', symbol='yrdns⁻²') +yards_per_picosecond = NamedUnit(914400000000.0001, Dimensions(length=1, time=-1), name='yards_per_picosecond', ascii_symbol='yrd/ps', symbol='yrdps⁻¹') +yards_per_square_picosecond = NamedUnit(9.144000000000002e+23, Dimensions(length=1, time=-2), name='yards_per_square_picosecond', ascii_symbol='yrd/ps^2', symbol='yrdps⁻²') +yards_per_femtosecond = NamedUnit(914400000000000.0, Dimensions(length=1, time=-1), name='yards_per_femtosecond', ascii_symbol='yrd/fs', symbol='yrdfs⁻¹') +yards_per_square_femtosecond = NamedUnit(9.144e+29, Dimensions(length=1, time=-2), name='yards_per_square_femtosecond', ascii_symbol='yrd/fs^2', symbol='yrdfs⁻²') +yards_per_attosecond = NamedUnit(9.144e+17, Dimensions(length=1, time=-1), name='yards_per_attosecond', ascii_symbol='yrd/as', symbol='yrdas⁻¹') +yards_per_square_attosecond = NamedUnit(9.144e+35, Dimensions(length=1, time=-2), name='yards_per_square_attosecond', ascii_symbol='yrd/as^2', symbol='yrdas⁻²') +yards_per_minute = NamedUnit(0.015240000000000002, Dimensions(length=1, time=-1), name='yards_per_minute', ascii_symbol='yrd/min', symbol='yrdmin⁻¹') +yards_per_square_minute = NamedUnit(0.00025400000000000005, Dimensions(length=1, time=-2), name='yards_per_square_minute', ascii_symbol='yrd/min^2', symbol='yrdmin⁻²') +yards_per_hour = NamedUnit(0.00254, Dimensions(length=1, time=-1), name='yards_per_hour', ascii_symbol='yrd/h', symbol='yrdh⁻¹') +yards_per_square_hour = NamedUnit(7.055555555555557e-06, Dimensions(length=1, time=-2), name='yards_per_square_hour', ascii_symbol='yrd/h^2', symbol='yrdh⁻²') +yards_per_day = NamedUnit(0.00010583333333333335, Dimensions(length=1, time=-1), name='yards_per_day', ascii_symbol='yrd/d', symbol='yrdd⁻¹') +yards_per_square_day = NamedUnit(1.224922839506173e-08, Dimensions(length=1, time=-2), name='yards_per_square_day', ascii_symbol='yrd/d^2', symbol='yrdd⁻²') +yards_per_year = NamedUnit(2.897618249062837e-07, Dimensions(length=1, time=-1), name='yards_per_year', ascii_symbol='yrd/y', symbol='yrdy⁻¹') +yards_per_square_year = NamedUnit(9.182186698711705e-14, Dimensions(length=1, time=-2), name='yards_per_square_year', ascii_symbol='yrd/y^2', symbol='yrdy⁻²') +feet_per_second = NamedUnit(0.3048, Dimensions(length=1, time=-1), name='feet_per_second', ascii_symbol='ft/s', symbol='fts⁻¹') +feet_per_square_second = NamedUnit(0.3048, Dimensions(length=1, time=-2), name='feet_per_square_second', ascii_symbol='ft/s^2', symbol='fts⁻²') +feet_per_millisecond = NamedUnit(304.8, Dimensions(length=1, time=-1), name='feet_per_millisecond', ascii_symbol='ft/ms', symbol='ftms⁻¹') +feet_per_square_millisecond = NamedUnit(304800.00000000006, Dimensions(length=1, time=-2), name='feet_per_square_millisecond', ascii_symbol='ft/ms^2', symbol='ftms⁻²') +feet_per_microsecond = NamedUnit(304800.00000000006, Dimensions(length=1, time=-1), name='feet_per_microsecond', ascii_symbol='ft/us', symbol='ftµs⁻¹') +feet_per_square_microsecond = NamedUnit(304800000000.0, Dimensions(length=1, time=-2), name='feet_per_square_microsecond', ascii_symbol='ft/us^2', symbol='ftµs⁻²') +feet_per_nanosecond = NamedUnit(304800000.0, Dimensions(length=1, time=-1), name='feet_per_nanosecond', ascii_symbol='ft/ns', symbol='ftns⁻¹') +feet_per_square_nanosecond = NamedUnit(3.048e+17, Dimensions(length=1, time=-2), name='feet_per_square_nanosecond', ascii_symbol='ft/ns^2', symbol='ftns⁻²') +feet_per_picosecond = NamedUnit(304800000000.0, Dimensions(length=1, time=-1), name='feet_per_picosecond', ascii_symbol='ft/ps', symbol='ftps⁻¹') +feet_per_square_picosecond = NamedUnit(3.048e+23, Dimensions(length=1, time=-2), name='feet_per_square_picosecond', ascii_symbol='ft/ps^2', symbol='ftps⁻²') +feet_per_femtosecond = NamedUnit(304800000000000.0, Dimensions(length=1, time=-1), name='feet_per_femtosecond', ascii_symbol='ft/fs', symbol='ftfs⁻¹') +feet_per_square_femtosecond = NamedUnit(3.048e+29, Dimensions(length=1, time=-2), name='feet_per_square_femtosecond', ascii_symbol='ft/fs^2', symbol='ftfs⁻²') +feet_per_attosecond = NamedUnit(3.048e+17, Dimensions(length=1, time=-1), name='feet_per_attosecond', ascii_symbol='ft/as', symbol='ftas⁻¹') +feet_per_square_attosecond = NamedUnit(3.0479999999999997e+35, Dimensions(length=1, time=-2), name='feet_per_square_attosecond', ascii_symbol='ft/as^2', symbol='ftas⁻²') +feet_per_minute = NamedUnit(0.00508, Dimensions(length=1, time=-1), name='feet_per_minute', ascii_symbol='ft/min', symbol='ftmin⁻¹') +feet_per_square_minute = NamedUnit(8.466666666666667e-05, Dimensions(length=1, time=-2), name='feet_per_square_minute', ascii_symbol='ft/min^2', symbol='ftmin⁻²') +feet_per_hour = NamedUnit(0.0008466666666666667, Dimensions(length=1, time=-1), name='feet_per_hour', ascii_symbol='ft/h', symbol='fth⁻¹') +feet_per_square_hour = NamedUnit(2.351851851851852e-06, Dimensions(length=1, time=-2), name='feet_per_square_hour', ascii_symbol='ft/h^2', symbol='fth⁻²') +feet_per_day = NamedUnit(3.527777777777778e-05, Dimensions(length=1, time=-1), name='feet_per_day', ascii_symbol='ft/d', symbol='ftd⁻¹') +feet_per_square_day = NamedUnit(4.083076131687243e-09, Dimensions(length=1, time=-2), name='feet_per_square_day', ascii_symbol='ft/d^2', symbol='ftd⁻²') +feet_per_year = NamedUnit(9.658727496876123e-08, Dimensions(length=1, time=-1), name='feet_per_year', ascii_symbol='ft/y', symbol='fty⁻¹') +feet_per_square_year = NamedUnit(3.060728899570568e-14, Dimensions(length=1, time=-2), name='feet_per_square_year', ascii_symbol='ft/y^2', symbol='fty⁻²') +inches_per_second = NamedUnit(0.0254, Dimensions(length=1, time=-1), name='inches_per_second', ascii_symbol='in/s', symbol='ins⁻¹') +inches_per_square_second = NamedUnit(0.0254, Dimensions(length=1, time=-2), name='inches_per_square_second', ascii_symbol='in/s^2', symbol='ins⁻²') +inches_per_millisecond = NamedUnit(25.4, Dimensions(length=1, time=-1), name='inches_per_millisecond', ascii_symbol='in/ms', symbol='inms⁻¹') +inches_per_square_millisecond = NamedUnit(25400.0, Dimensions(length=1, time=-2), name='inches_per_square_millisecond', ascii_symbol='in/ms^2', symbol='inms⁻²') +inches_per_microsecond = NamedUnit(25400.0, Dimensions(length=1, time=-1), name='inches_per_microsecond', ascii_symbol='in/us', symbol='inµs⁻¹') +inches_per_square_microsecond = NamedUnit(25400000000.0, Dimensions(length=1, time=-2), name='inches_per_square_microsecond', ascii_symbol='in/us^2', symbol='inµs⁻²') +inches_per_nanosecond = NamedUnit(25399999.999999996, Dimensions(length=1, time=-1), name='inches_per_nanosecond', ascii_symbol='in/ns', symbol='inns⁻¹') +inches_per_square_nanosecond = NamedUnit(2.5399999999999996e+16, Dimensions(length=1, time=-2), name='inches_per_square_nanosecond', ascii_symbol='in/ns^2', symbol='inns⁻²') +inches_per_picosecond = NamedUnit(25400000000.0, Dimensions(length=1, time=-1), name='inches_per_picosecond', ascii_symbol='in/ps', symbol='inps⁻¹') +inches_per_square_picosecond = NamedUnit(2.54e+22, Dimensions(length=1, time=-2), name='inches_per_square_picosecond', ascii_symbol='in/ps^2', symbol='inps⁻²') +inches_per_femtosecond = NamedUnit(25399999999999.996, Dimensions(length=1, time=-1), name='inches_per_femtosecond', ascii_symbol='in/fs', symbol='infs⁻¹') +inches_per_square_femtosecond = NamedUnit(2.54e+28, Dimensions(length=1, time=-2), name='inches_per_square_femtosecond', ascii_symbol='in/fs^2', symbol='infs⁻²') +inches_per_attosecond = NamedUnit(2.5399999999999996e+16, Dimensions(length=1, time=-1), name='inches_per_attosecond', ascii_symbol='in/as', symbol='inas⁻¹') +inches_per_square_attosecond = NamedUnit(2.5399999999999998e+34, Dimensions(length=1, time=-2), name='inches_per_square_attosecond', ascii_symbol='in/as^2', symbol='inas⁻²') +inches_per_minute = NamedUnit(0.00042333333333333334, Dimensions(length=1, time=-1), name='inches_per_minute', ascii_symbol='in/min', symbol='inmin⁻¹') +inches_per_square_minute = NamedUnit(7.055555555555555e-06, Dimensions(length=1, time=-2), name='inches_per_square_minute', ascii_symbol='in/min^2', symbol='inmin⁻²') +inches_per_hour = NamedUnit(7.055555555555556e-05, Dimensions(length=1, time=-1), name='inches_per_hour', ascii_symbol='in/h', symbol='inh⁻¹') +inches_per_square_hour = NamedUnit(1.9598765432098765e-07, Dimensions(length=1, time=-2), name='inches_per_square_hour', ascii_symbol='in/h^2', symbol='inh⁻²') +inches_per_day = NamedUnit(2.9398148148148147e-06, Dimensions(length=1, time=-1), name='inches_per_day', ascii_symbol='in/d', symbol='ind⁻¹') +inches_per_square_day = NamedUnit(3.4025634430727023e-10, Dimensions(length=1, time=-2), name='inches_per_square_day', ascii_symbol='in/d^2', symbol='ind⁻²') +inches_per_year = NamedUnit(8.048939580730103e-09, Dimensions(length=1, time=-1), name='inches_per_year', ascii_symbol='in/y', symbol='iny⁻¹') +inches_per_square_year = NamedUnit(2.5506074163088065e-15, Dimensions(length=1, time=-2), name='inches_per_square_year', ascii_symbol='in/y^2', symbol='iny⁻²') +grams_per_cubic_meter = NamedUnit(0.001, Dimensions(length=-3, mass=1), name='grams_per_cubic_meter', ascii_symbol='g m^-3', symbol='gm⁻³') +exagrams_per_cubic_meter = NamedUnit(1000000000000000.0, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_meter', ascii_symbol='Eg m^-3', symbol='Egm⁻³') +petagrams_per_cubic_meter = NamedUnit(1000000000000.0, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_meter', ascii_symbol='Pg m^-3', symbol='Pgm⁻³') +teragrams_per_cubic_meter = NamedUnit(1000000000.0, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_meter', ascii_symbol='Tg m^-3', symbol='Tgm⁻³') +gigagrams_per_cubic_meter = NamedUnit(1000000.0, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_meter', ascii_symbol='Gg m^-3', symbol='Ggm⁻³') +megagrams_per_cubic_meter = NamedUnit(1000.0, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_meter', ascii_symbol='Mg m^-3', symbol='Mgm⁻³') +kilograms_per_cubic_meter = NamedUnit(1.0, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_meter', ascii_symbol='kg m^-3', symbol='kgm⁻³') +milligrams_per_cubic_meter = NamedUnit(1e-06, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_meter', ascii_symbol='mg m^-3', symbol='mgm⁻³') +micrograms_per_cubic_meter = NamedUnit(1e-09, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_meter', ascii_symbol='ug m^-3', symbol='µgm⁻³') +nanograms_per_cubic_meter = NamedUnit(1.0000000000000002e-12, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_meter', ascii_symbol='ng m^-3', symbol='ngm⁻³') +picograms_per_cubic_meter = NamedUnit(1e-15, Dimensions(length=-3, mass=1), name='picograms_per_cubic_meter', ascii_symbol='pg m^-3', symbol='pgm⁻³') +femtograms_per_cubic_meter = NamedUnit(1e-18, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_meter', ascii_symbol='fg m^-3', symbol='fgm⁻³') +attograms_per_cubic_meter = NamedUnit(1.0000000000000001e-21, Dimensions(length=-3, mass=1), name='attograms_per_cubic_meter', ascii_symbol='ag m^-3', symbol='agm⁻³') +atomic_mass_units_per_cubic_meter = NamedUnit(1.660538921e-27, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_meter', ascii_symbol='au m^-3', symbol='aum⁻³') +pounds_per_cubic_meter = NamedUnit(0.45359237, Dimensions(length=-3, mass=1), name='pounds_per_cubic_meter', ascii_symbol='lb m^-3', symbol='lbm⁻³') +ounces_per_cubic_meter = NamedUnit(0.028349523125, Dimensions(length=-3, mass=1), name='ounces_per_cubic_meter', ascii_symbol='oz m^-3', symbol='ozm⁻³') +grams_per_cubic_exameter = NamedUnit(1e-57, Dimensions(length=-3, mass=1), name='grams_per_cubic_exameter', ascii_symbol='g Em^-3', symbol='gEm⁻³') +exagrams_per_cubic_exameter = NamedUnit(1e-39, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_exameter', ascii_symbol='Eg Em^-3', symbol='EgEm⁻³') +petagrams_per_cubic_exameter = NamedUnit(9.999999999999999e-43, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_exameter', ascii_symbol='Pg Em^-3', symbol='PgEm⁻³') +teragrams_per_cubic_exameter = NamedUnit(1e-45, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_exameter', ascii_symbol='Tg Em^-3', symbol='TgEm⁻³') +gigagrams_per_cubic_exameter = NamedUnit(1e-48, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_exameter', ascii_symbol='Gg Em^-3', symbol='GgEm⁻³') +megagrams_per_cubic_exameter = NamedUnit(9.999999999999999e-52, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_exameter', ascii_symbol='Mg Em^-3', symbol='MgEm⁻³') +kilograms_per_cubic_exameter = NamedUnit(9.999999999999999e-55, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_exameter', ascii_symbol='kg Em^-3', symbol='kgEm⁻³') +milligrams_per_cubic_exameter = NamedUnit(9.999999999999998e-61, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_exameter', ascii_symbol='mg Em^-3', symbol='mgEm⁻³') +micrograms_per_cubic_exameter = NamedUnit(9.999999999999999e-64, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_exameter', ascii_symbol='ug Em^-3', symbol='µgEm⁻³') +nanograms_per_cubic_exameter = NamedUnit(1.0000000000000001e-66, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_exameter', ascii_symbol='ng Em^-3', symbol='ngEm⁻³') +picograms_per_cubic_exameter = NamedUnit(1e-69, Dimensions(length=-3, mass=1), name='picograms_per_cubic_exameter', ascii_symbol='pg Em^-3', symbol='pgEm⁻³') +femtograms_per_cubic_exameter = NamedUnit(1e-72, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_exameter', ascii_symbol='fg Em^-3', symbol='fgEm⁻³') +attograms_per_cubic_exameter = NamedUnit(1e-75, Dimensions(length=-3, mass=1), name='attograms_per_cubic_exameter', ascii_symbol='ag Em^-3', symbol='agEm⁻³') +atomic_mass_units_per_cubic_exameter = NamedUnit(1.6605389209999996e-81, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_exameter', ascii_symbol='au Em^-3', symbol='auEm⁻³') +pounds_per_cubic_exameter = NamedUnit(4.5359237e-55, Dimensions(length=-3, mass=1), name='pounds_per_cubic_exameter', ascii_symbol='lb Em^-3', symbol='lbEm⁻³') +ounces_per_cubic_exameter = NamedUnit(2.8349523125e-56, Dimensions(length=-3, mass=1), name='ounces_per_cubic_exameter', ascii_symbol='oz Em^-3', symbol='ozEm⁻³') +grams_per_cubic_petameter = NamedUnit(1.0000000000000001e-48, Dimensions(length=-3, mass=1), name='grams_per_cubic_petameter', ascii_symbol='g Pm^-3', symbol='gPm⁻³') +exagrams_per_cubic_petameter = NamedUnit(1e-30, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_petameter', ascii_symbol='Eg Pm^-3', symbol='EgPm⁻³') +petagrams_per_cubic_petameter = NamedUnit(1e-33, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_petameter', ascii_symbol='Pg Pm^-3', symbol='PgPm⁻³') +teragrams_per_cubic_petameter = NamedUnit(1.0000000000000001e-36, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_petameter', ascii_symbol='Tg Pm^-3', symbol='TgPm⁻³') +gigagrams_per_cubic_petameter = NamedUnit(1.0000000000000001e-39, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_petameter', ascii_symbol='Gg Pm^-3', symbol='GgPm⁻³') +megagrams_per_cubic_petameter = NamedUnit(1e-42, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_petameter', ascii_symbol='Mg Pm^-3', symbol='MgPm⁻³') +kilograms_per_cubic_petameter = NamedUnit(1.0000000000000001e-45, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_petameter', ascii_symbol='kg Pm^-3', symbol='kgPm⁻³') +milligrams_per_cubic_petameter = NamedUnit(1e-51, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_petameter', ascii_symbol='mg Pm^-3', symbol='mgPm⁻³') +micrograms_per_cubic_petameter = NamedUnit(1.0000000000000002e-54, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_petameter', ascii_symbol='ug Pm^-3', symbol='µgPm⁻³') +nanograms_per_cubic_petameter = NamedUnit(1.0000000000000002e-57, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_petameter', ascii_symbol='ng Pm^-3', symbol='ngPm⁻³') +picograms_per_cubic_petameter = NamedUnit(1.0000000000000001e-60, Dimensions(length=-3, mass=1), name='picograms_per_cubic_petameter', ascii_symbol='pg Pm^-3', symbol='pgPm⁻³') +femtograms_per_cubic_petameter = NamedUnit(1.0000000000000002e-63, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_petameter', ascii_symbol='fg Pm^-3', symbol='fgPm⁻³') +attograms_per_cubic_petameter = NamedUnit(1.0000000000000001e-66, Dimensions(length=-3, mass=1), name='attograms_per_cubic_petameter', ascii_symbol='ag Pm^-3', symbol='agPm⁻³') +atomic_mass_units_per_cubic_petameter = NamedUnit(1.660538921e-72, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_petameter', ascii_symbol='au Pm^-3', symbol='auPm⁻³') +pounds_per_cubic_petameter = NamedUnit(4.5359237000000005e-46, Dimensions(length=-3, mass=1), name='pounds_per_cubic_petameter', ascii_symbol='lb Pm^-3', symbol='lbPm⁻³') +ounces_per_cubic_petameter = NamedUnit(2.8349523125000003e-47, Dimensions(length=-3, mass=1), name='ounces_per_cubic_petameter', ascii_symbol='oz Pm^-3', symbol='ozPm⁻³') +grams_per_cubic_terameter = NamedUnit(1e-39, Dimensions(length=-3, mass=1), name='grams_per_cubic_terameter', ascii_symbol='g Tm^-3', symbol='gTm⁻³') +exagrams_per_cubic_terameter = NamedUnit(1e-21, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_terameter', ascii_symbol='Eg Tm^-3', symbol='EgTm⁻³') +petagrams_per_cubic_terameter = NamedUnit(1e-24, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_terameter', ascii_symbol='Pg Tm^-3', symbol='PgTm⁻³') +teragrams_per_cubic_terameter = NamedUnit(1e-27, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_terameter', ascii_symbol='Tg Tm^-3', symbol='TgTm⁻³') +gigagrams_per_cubic_terameter = NamedUnit(9.999999999999999e-31, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_terameter', ascii_symbol='Gg Tm^-3', symbol='GgTm⁻³') +megagrams_per_cubic_terameter = NamedUnit(9.999999999999999e-34, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_terameter', ascii_symbol='Mg Tm^-3', symbol='MgTm⁻³') +kilograms_per_cubic_terameter = NamedUnit(1e-36, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_terameter', ascii_symbol='kg Tm^-3', symbol='kgTm⁻³') +milligrams_per_cubic_terameter = NamedUnit(9.999999999999999e-43, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_terameter', ascii_symbol='mg Tm^-3', symbol='mgTm⁻³') +micrograms_per_cubic_terameter = NamedUnit(1e-45, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_terameter', ascii_symbol='ug Tm^-3', symbol='µgTm⁻³') +nanograms_per_cubic_terameter = NamedUnit(1.0000000000000001e-48, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_terameter', ascii_symbol='ng Tm^-3', symbol='ngTm⁻³') +picograms_per_cubic_terameter = NamedUnit(1e-51, Dimensions(length=-3, mass=1), name='picograms_per_cubic_terameter', ascii_symbol='pg Tm^-3', symbol='pgTm⁻³') +femtograms_per_cubic_terameter = NamedUnit(1e-54, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_terameter', ascii_symbol='fg Tm^-3', symbol='fgTm⁻³') +attograms_per_cubic_terameter = NamedUnit(1.0000000000000001e-57, Dimensions(length=-3, mass=1), name='attograms_per_cubic_terameter', ascii_symbol='ag Tm^-3', symbol='agTm⁻³') +atomic_mass_units_per_cubic_terameter = NamedUnit(1.6605389209999997e-63, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_terameter', ascii_symbol='au Tm^-3', symbol='auTm⁻³') +pounds_per_cubic_terameter = NamedUnit(4.5359237e-37, Dimensions(length=-3, mass=1), name='pounds_per_cubic_terameter', ascii_symbol='lb Tm^-3', symbol='lbTm⁻³') +ounces_per_cubic_terameter = NamedUnit(2.8349523125e-38, Dimensions(length=-3, mass=1), name='ounces_per_cubic_terameter', ascii_symbol='oz Tm^-3', symbol='ozTm⁻³') +grams_per_cubic_gigameter = NamedUnit(1e-30, Dimensions(length=-3, mass=1), name='grams_per_cubic_gigameter', ascii_symbol='g Gm^-3', symbol='gGm⁻³') +exagrams_per_cubic_gigameter = NamedUnit(1e-12, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_gigameter', ascii_symbol='Eg Gm^-3', symbol='EgGm⁻³') +petagrams_per_cubic_gigameter = NamedUnit(1e-15, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_gigameter', ascii_symbol='Pg Gm^-3', symbol='PgGm⁻³') +teragrams_per_cubic_gigameter = NamedUnit(1e-18, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_gigameter', ascii_symbol='Tg Gm^-3', symbol='TgGm⁻³') +gigagrams_per_cubic_gigameter = NamedUnit(1e-21, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_gigameter', ascii_symbol='Gg Gm^-3', symbol='GgGm⁻³') +megagrams_per_cubic_gigameter = NamedUnit(1e-24, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_gigameter', ascii_symbol='Mg Gm^-3', symbol='MgGm⁻³') +kilograms_per_cubic_gigameter = NamedUnit(1e-27, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_gigameter', ascii_symbol='kg Gm^-3', symbol='kgGm⁻³') +milligrams_per_cubic_gigameter = NamedUnit(9.999999999999999e-34, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_gigameter', ascii_symbol='mg Gm^-3', symbol='mgGm⁻³') +micrograms_per_cubic_gigameter = NamedUnit(1.0000000000000001e-36, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_gigameter', ascii_symbol='ug Gm^-3', symbol='µgGm⁻³') +nanograms_per_cubic_gigameter = NamedUnit(1.0000000000000001e-39, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_gigameter', ascii_symbol='ng Gm^-3', symbol='ngGm⁻³') +picograms_per_cubic_gigameter = NamedUnit(1e-42, Dimensions(length=-3, mass=1), name='picograms_per_cubic_gigameter', ascii_symbol='pg Gm^-3', symbol='pgGm⁻³') +femtograms_per_cubic_gigameter = NamedUnit(1e-45, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_gigameter', ascii_symbol='fg Gm^-3', symbol='fgGm⁻³') +attograms_per_cubic_gigameter = NamedUnit(1.0000000000000001e-48, Dimensions(length=-3, mass=1), name='attograms_per_cubic_gigameter', ascii_symbol='ag Gm^-3', symbol='agGm⁻³') +atomic_mass_units_per_cubic_gigameter = NamedUnit(1.660538921e-54, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_gigameter', ascii_symbol='au Gm^-3', symbol='auGm⁻³') +pounds_per_cubic_gigameter = NamedUnit(4.5359237e-28, Dimensions(length=-3, mass=1), name='pounds_per_cubic_gigameter', ascii_symbol='lb Gm^-3', symbol='lbGm⁻³') +ounces_per_cubic_gigameter = NamedUnit(2.8349523125e-29, Dimensions(length=-3, mass=1), name='ounces_per_cubic_gigameter', ascii_symbol='oz Gm^-3', symbol='ozGm⁻³') +grams_per_cubic_megameter = NamedUnit(1.0000000000000001e-21, Dimensions(length=-3, mass=1), name='grams_per_cubic_megameter', ascii_symbol='g Mm^-3', symbol='gMm⁻³') +exagrams_per_cubic_megameter = NamedUnit(0.001, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_megameter', ascii_symbol='Eg Mm^-3', symbol='EgMm⁻³') +petagrams_per_cubic_megameter = NamedUnit(1e-06, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_megameter', ascii_symbol='Pg Mm^-3', symbol='PgMm⁻³') +teragrams_per_cubic_megameter = NamedUnit(1e-09, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_megameter', ascii_symbol='Tg Mm^-3', symbol='TgMm⁻³') +gigagrams_per_cubic_megameter = NamedUnit(1e-12, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_megameter', ascii_symbol='Gg Mm^-3', symbol='GgMm⁻³') +megagrams_per_cubic_megameter = NamedUnit(1e-15, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_megameter', ascii_symbol='Mg Mm^-3', symbol='MgMm⁻³') +kilograms_per_cubic_megameter = NamedUnit(1e-18, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_megameter', ascii_symbol='kg Mm^-3', symbol='kgMm⁻³') +milligrams_per_cubic_megameter = NamedUnit(1e-24, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_megameter', ascii_symbol='mg Mm^-3', symbol='mgMm⁻³') +micrograms_per_cubic_megameter = NamedUnit(1e-27, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_megameter', ascii_symbol='ug Mm^-3', symbol='µgMm⁻³') +nanograms_per_cubic_megameter = NamedUnit(1.0000000000000003e-30, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_megameter', ascii_symbol='ng Mm^-3', symbol='ngMm⁻³') +picograms_per_cubic_megameter = NamedUnit(1e-33, Dimensions(length=-3, mass=1), name='picograms_per_cubic_megameter', ascii_symbol='pg Mm^-3', symbol='pgMm⁻³') +femtograms_per_cubic_megameter = NamedUnit(1.0000000000000001e-36, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_megameter', ascii_symbol='fg Mm^-3', symbol='fgMm⁻³') +attograms_per_cubic_megameter = NamedUnit(1.0000000000000001e-39, Dimensions(length=-3, mass=1), name='attograms_per_cubic_megameter', ascii_symbol='ag Mm^-3', symbol='agMm⁻³') +atomic_mass_units_per_cubic_megameter = NamedUnit(1.6605389209999997e-45, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_megameter', ascii_symbol='au Mm^-3', symbol='auMm⁻³') +pounds_per_cubic_megameter = NamedUnit(4.535923700000001e-19, Dimensions(length=-3, mass=1), name='pounds_per_cubic_megameter', ascii_symbol='lb Mm^-3', symbol='lbMm⁻³') +ounces_per_cubic_megameter = NamedUnit(2.8349523125000004e-20, Dimensions(length=-3, mass=1), name='ounces_per_cubic_megameter', ascii_symbol='oz Mm^-3', symbol='ozMm⁻³') +grams_per_cubic_kilometer = NamedUnit(1e-12, Dimensions(length=-3, mass=1), name='grams_per_cubic_kilometer', ascii_symbol='g km^-3', symbol='gkm⁻³') +exagrams_per_cubic_kilometer = NamedUnit(1000000.0, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_kilometer', ascii_symbol='Eg km^-3', symbol='Egkm⁻³') +petagrams_per_cubic_kilometer = NamedUnit(1000.0, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_kilometer', ascii_symbol='Pg km^-3', symbol='Pgkm⁻³') +teragrams_per_cubic_kilometer = NamedUnit(1.0, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_kilometer', ascii_symbol='Tg km^-3', symbol='Tgkm⁻³') +gigagrams_per_cubic_kilometer = NamedUnit(0.001, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_kilometer', ascii_symbol='Gg km^-3', symbol='Ggkm⁻³') +megagrams_per_cubic_kilometer = NamedUnit(1e-06, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_kilometer', ascii_symbol='Mg km^-3', symbol='Mgkm⁻³') +kilograms_per_cubic_kilometer = NamedUnit(1e-09, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_kilometer', ascii_symbol='kg km^-3', symbol='kgkm⁻³') +milligrams_per_cubic_kilometer = NamedUnit(9.999999999999999e-16, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_kilometer', ascii_symbol='mg km^-3', symbol='mgkm⁻³') +micrograms_per_cubic_kilometer = NamedUnit(1e-18, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_kilometer', ascii_symbol='ug km^-3', symbol='µgkm⁻³') +nanograms_per_cubic_kilometer = NamedUnit(1.0000000000000001e-21, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_kilometer', ascii_symbol='ng km^-3', symbol='ngkm⁻³') +picograms_per_cubic_kilometer = NamedUnit(1.0000000000000001e-24, Dimensions(length=-3, mass=1), name='picograms_per_cubic_kilometer', ascii_symbol='pg km^-3', symbol='pgkm⁻³') +femtograms_per_cubic_kilometer = NamedUnit(1e-27, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_kilometer', ascii_symbol='fg km^-3', symbol='fgkm⁻³') +attograms_per_cubic_kilometer = NamedUnit(1e-30, Dimensions(length=-3, mass=1), name='attograms_per_cubic_kilometer', ascii_symbol='ag km^-3', symbol='agkm⁻³') +atomic_mass_units_per_cubic_kilometer = NamedUnit(1.6605389209999997e-36, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_kilometer', ascii_symbol='au km^-3', symbol='aukm⁻³') +pounds_per_cubic_kilometer = NamedUnit(4.5359237000000004e-10, Dimensions(length=-3, mass=1), name='pounds_per_cubic_kilometer', ascii_symbol='lb km^-3', symbol='lbkm⁻³') +ounces_per_cubic_kilometer = NamedUnit(2.8349523125000003e-11, Dimensions(length=-3, mass=1), name='ounces_per_cubic_kilometer', ascii_symbol='oz km^-3', symbol='ozkm⁻³') +grams_per_cubic_millimeter = NamedUnit(1000000.0, Dimensions(length=-3, mass=1), name='grams_per_cubic_millimeter', ascii_symbol='g mm^-3', symbol='gmm⁻³') +exagrams_per_cubic_millimeter = NamedUnit(1e+24, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_millimeter', ascii_symbol='Eg mm^-3', symbol='Egmm⁻³') +petagrams_per_cubic_millimeter = NamedUnit(1e+21, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_millimeter', ascii_symbol='Pg mm^-3', symbol='Pgmm⁻³') +teragrams_per_cubic_millimeter = NamedUnit(1e+18, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_millimeter', ascii_symbol='Tg mm^-3', symbol='Tgmm⁻³') +gigagrams_per_cubic_millimeter = NamedUnit(1000000000000000.0, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_millimeter', ascii_symbol='Gg mm^-3', symbol='Ggmm⁻³') +megagrams_per_cubic_millimeter = NamedUnit(999999999999.9999, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_millimeter', ascii_symbol='Mg mm^-3', symbol='Mgmm⁻³') +kilograms_per_cubic_millimeter = NamedUnit(999999999.9999999, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_millimeter', ascii_symbol='kg mm^-3', symbol='kgmm⁻³') +milligrams_per_cubic_millimeter = NamedUnit(999.9999999999999, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_millimeter', ascii_symbol='mg mm^-3', symbol='mgmm⁻³') +micrograms_per_cubic_millimeter = NamedUnit(1.0, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_millimeter', ascii_symbol='ug mm^-3', symbol='µgmm⁻³') +nanograms_per_cubic_millimeter = NamedUnit(0.001, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_millimeter', ascii_symbol='ng mm^-3', symbol='ngmm⁻³') +picograms_per_cubic_millimeter = NamedUnit(1e-06, Dimensions(length=-3, mass=1), name='picograms_per_cubic_millimeter', ascii_symbol='pg mm^-3', symbol='pgmm⁻³') +femtograms_per_cubic_millimeter = NamedUnit(1e-09, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_millimeter', ascii_symbol='fg mm^-3', symbol='fgmm⁻³') +attograms_per_cubic_millimeter = NamedUnit(1e-12, Dimensions(length=-3, mass=1), name='attograms_per_cubic_millimeter', ascii_symbol='ag mm^-3', symbol='agmm⁻³') +atomic_mass_units_per_cubic_millimeter = NamedUnit(1.6605389209999997e-18, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_millimeter', ascii_symbol='au mm^-3', symbol='aumm⁻³') +pounds_per_cubic_millimeter = NamedUnit(453592370.0, Dimensions(length=-3, mass=1), name='pounds_per_cubic_millimeter', ascii_symbol='lb mm^-3', symbol='lbmm⁻³') +ounces_per_cubic_millimeter = NamedUnit(28349523.125, Dimensions(length=-3, mass=1), name='ounces_per_cubic_millimeter', ascii_symbol='oz mm^-3', symbol='ozmm⁻³') +grams_per_cubic_micrometer = NamedUnit(1000000000000000.1, Dimensions(length=-3, mass=1), name='grams_per_cubic_micrometer', ascii_symbol='g um^-3', symbol='gµm⁻³') +exagrams_per_cubic_micrometer = NamedUnit(1.0000000000000001e+33, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_micrometer', ascii_symbol='Eg um^-3', symbol='Egµm⁻³') +petagrams_per_cubic_micrometer = NamedUnit(1.0000000000000002e+30, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_micrometer', ascii_symbol='Pg um^-3', symbol='Pgµm⁻³') +teragrams_per_cubic_micrometer = NamedUnit(1.0000000000000002e+27, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_micrometer', ascii_symbol='Tg um^-3', symbol='Tgµm⁻³') +gigagrams_per_cubic_micrometer = NamedUnit(1.0000000000000001e+24, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_micrometer', ascii_symbol='Gg um^-3', symbol='Ggµm⁻³') +megagrams_per_cubic_micrometer = NamedUnit(1.0000000000000001e+21, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_micrometer', ascii_symbol='Mg um^-3', symbol='Mgµm⁻³') +kilograms_per_cubic_micrometer = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_micrometer', ascii_symbol='kg um^-3', symbol='kgµm⁻³') +milligrams_per_cubic_micrometer = NamedUnit(1000000000000.0001, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_micrometer', ascii_symbol='mg um^-3', symbol='mgµm⁻³') +micrograms_per_cubic_micrometer = NamedUnit(1000000000.0000002, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_micrometer', ascii_symbol='ug um^-3', symbol='µgµm⁻³') +nanograms_per_cubic_micrometer = NamedUnit(1000000.0000000003, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_micrometer', ascii_symbol='ng um^-3', symbol='ngµm⁻³') +picograms_per_cubic_micrometer = NamedUnit(1000.0000000000002, Dimensions(length=-3, mass=1), name='picograms_per_cubic_micrometer', ascii_symbol='pg um^-3', symbol='pgµm⁻³') +femtograms_per_cubic_micrometer = NamedUnit(1.0000000000000002, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_micrometer', ascii_symbol='fg um^-3', symbol='fgµm⁻³') +attograms_per_cubic_micrometer = NamedUnit(0.0010000000000000002, Dimensions(length=-3, mass=1), name='attograms_per_cubic_micrometer', ascii_symbol='ag um^-3', symbol='agµm⁻³') +atomic_mass_units_per_cubic_micrometer = NamedUnit(1.660538921e-09, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_micrometer', ascii_symbol='au um^-3', symbol='auµm⁻³') +pounds_per_cubic_micrometer = NamedUnit(4.5359237000000006e+17, Dimensions(length=-3, mass=1), name='pounds_per_cubic_micrometer', ascii_symbol='lb um^-3', symbol='lbµm⁻³') +ounces_per_cubic_micrometer = NamedUnit(2.8349523125000004e+16, Dimensions(length=-3, mass=1), name='ounces_per_cubic_micrometer', ascii_symbol='oz um^-3', symbol='ozµm⁻³') +grams_per_cubic_nanometer = NamedUnit(9.999999999999998e+23, Dimensions(length=-3, mass=1), name='grams_per_cubic_nanometer', ascii_symbol='g nm^-3', symbol='gnm⁻³') +exagrams_per_cubic_nanometer = NamedUnit(9.999999999999997e+41, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_nanometer', ascii_symbol='Eg nm^-3', symbol='Egnm⁻³') +petagrams_per_cubic_nanometer = NamedUnit(9.999999999999998e+38, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_nanometer', ascii_symbol='Pg nm^-3', symbol='Pgnm⁻³') +teragrams_per_cubic_nanometer = NamedUnit(9.999999999999997e+35, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_nanometer', ascii_symbol='Tg nm^-3', symbol='Tgnm⁻³') +gigagrams_per_cubic_nanometer = NamedUnit(9.999999999999998e+32, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_nanometer', ascii_symbol='Gg nm^-3', symbol='Ggnm⁻³') +megagrams_per_cubic_nanometer = NamedUnit(9.999999999999997e+29, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_nanometer', ascii_symbol='Mg nm^-3', symbol='Mgnm⁻³') +kilograms_per_cubic_nanometer = NamedUnit(9.999999999999997e+26, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_nanometer', ascii_symbol='kg nm^-3', symbol='kgnm⁻³') +milligrams_per_cubic_nanometer = NamedUnit(9.999999999999997e+20, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_nanometer', ascii_symbol='mg nm^-3', symbol='mgnm⁻³') +micrograms_per_cubic_nanometer = NamedUnit(9.999999999999999e+17, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_nanometer', ascii_symbol='ug nm^-3', symbol='µgnm⁻³') +nanograms_per_cubic_nanometer = NamedUnit(1000000000000000.0, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_nanometer', ascii_symbol='ng nm^-3', symbol='ngnm⁻³') +picograms_per_cubic_nanometer = NamedUnit(999999999999.9999, Dimensions(length=-3, mass=1), name='picograms_per_cubic_nanometer', ascii_symbol='pg nm^-3', symbol='pgnm⁻³') +femtograms_per_cubic_nanometer = NamedUnit(999999999.9999999, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_nanometer', ascii_symbol='fg nm^-3', symbol='fgnm⁻³') +attograms_per_cubic_nanometer = NamedUnit(999999.9999999999, Dimensions(length=-3, mass=1), name='attograms_per_cubic_nanometer', ascii_symbol='ag nm^-3', symbol='agnm⁻³') +atomic_mass_units_per_cubic_nanometer = NamedUnit(1.6605389209999994, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_nanometer', ascii_symbol='au nm^-3', symbol='aunm⁻³') +pounds_per_cubic_nanometer = NamedUnit(4.535923699999999e+26, Dimensions(length=-3, mass=1), name='pounds_per_cubic_nanometer', ascii_symbol='lb nm^-3', symbol='lbnm⁻³') +ounces_per_cubic_nanometer = NamedUnit(2.8349523124999993e+25, Dimensions(length=-3, mass=1), name='ounces_per_cubic_nanometer', ascii_symbol='oz nm^-3', symbol='oznm⁻³') +grams_per_cubic_picometer = NamedUnit(1.0000000000000001e+33, Dimensions(length=-3, mass=1), name='grams_per_cubic_picometer', ascii_symbol='g pm^-3', symbol='gpm⁻³') +exagrams_per_cubic_picometer = NamedUnit(1e+51, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_picometer', ascii_symbol='Eg pm^-3', symbol='Egpm⁻³') +petagrams_per_cubic_picometer = NamedUnit(1e+48, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_picometer', ascii_symbol='Pg pm^-3', symbol='Pgpm⁻³') +teragrams_per_cubic_picometer = NamedUnit(1.0000000000000001e+45, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_picometer', ascii_symbol='Tg pm^-3', symbol='Tgpm⁻³') +gigagrams_per_cubic_picometer = NamedUnit(1e+42, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_picometer', ascii_symbol='Gg pm^-3', symbol='Ggpm⁻³') +megagrams_per_cubic_picometer = NamedUnit(1.0000000000000001e+39, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_picometer', ascii_symbol='Mg pm^-3', symbol='Mgpm⁻³') +kilograms_per_cubic_picometer = NamedUnit(1e+36, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_picometer', ascii_symbol='kg pm^-3', symbol='kgpm⁻³') +milligrams_per_cubic_picometer = NamedUnit(1e+30, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_picometer', ascii_symbol='mg pm^-3', symbol='mgpm⁻³') +micrograms_per_cubic_picometer = NamedUnit(1.0000000000000002e+27, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_picometer', ascii_symbol='ug pm^-3', symbol='µgpm⁻³') +nanograms_per_cubic_picometer = NamedUnit(1.0000000000000003e+24, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_picometer', ascii_symbol='ng pm^-3', symbol='ngpm⁻³') +picograms_per_cubic_picometer = NamedUnit(1.0000000000000001e+21, Dimensions(length=-3, mass=1), name='picograms_per_cubic_picometer', ascii_symbol='pg pm^-3', symbol='pgpm⁻³') +femtograms_per_cubic_picometer = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_picometer', ascii_symbol='fg pm^-3', symbol='fgpm⁻³') +attograms_per_cubic_picometer = NamedUnit(1000000000000000.1, Dimensions(length=-3, mass=1), name='attograms_per_cubic_picometer', ascii_symbol='ag pm^-3', symbol='agpm⁻³') +atomic_mass_units_per_cubic_picometer = NamedUnit(1660538921.0, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_picometer', ascii_symbol='au pm^-3', symbol='aupm⁻³') +pounds_per_cubic_picometer = NamedUnit(4.5359237000000005e+35, Dimensions(length=-3, mass=1), name='pounds_per_cubic_picometer', ascii_symbol='lb pm^-3', symbol='lbpm⁻³') +ounces_per_cubic_picometer = NamedUnit(2.8349523125000003e+34, Dimensions(length=-3, mass=1), name='ounces_per_cubic_picometer', ascii_symbol='oz pm^-3', symbol='ozpm⁻³') +grams_per_cubic_femtometer = NamedUnit(9.999999999999997e+41, Dimensions(length=-3, mass=1), name='grams_per_cubic_femtometer', ascii_symbol='g fm^-3', symbol='gfm⁻³') +exagrams_per_cubic_femtometer = NamedUnit(9.999999999999998e+59, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_femtometer', ascii_symbol='Eg fm^-3', symbol='Egfm⁻³') +petagrams_per_cubic_femtometer = NamedUnit(9.999999999999997e+56, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_femtometer', ascii_symbol='Pg fm^-3', symbol='Pgfm⁻³') +teragrams_per_cubic_femtometer = NamedUnit(9.999999999999997e+53, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_femtometer', ascii_symbol='Tg fm^-3', symbol='Tgfm⁻³') +gigagrams_per_cubic_femtometer = NamedUnit(9.999999999999997e+50, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_femtometer', ascii_symbol='Gg fm^-3', symbol='Ggfm⁻³') +megagrams_per_cubic_femtometer = NamedUnit(9.999999999999997e+47, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_femtometer', ascii_symbol='Mg fm^-3', symbol='Mgfm⁻³') +kilograms_per_cubic_femtometer = NamedUnit(9.999999999999998e+44, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_femtometer', ascii_symbol='kg fm^-3', symbol='kgfm⁻³') +milligrams_per_cubic_femtometer = NamedUnit(9.999999999999996e+38, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_femtometer', ascii_symbol='mg fm^-3', symbol='mgfm⁻³') +micrograms_per_cubic_femtometer = NamedUnit(9.999999999999997e+35, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_femtometer', ascii_symbol='ug fm^-3', symbol='µgfm⁻³') +nanograms_per_cubic_femtometer = NamedUnit(1e+33, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_femtometer', ascii_symbol='ng fm^-3', symbol='ngfm⁻³') +picograms_per_cubic_femtometer = NamedUnit(9.999999999999997e+29, Dimensions(length=-3, mass=1), name='picograms_per_cubic_femtometer', ascii_symbol='pg fm^-3', symbol='pgfm⁻³') +femtograms_per_cubic_femtometer = NamedUnit(9.999999999999997e+26, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_femtometer', ascii_symbol='fg fm^-3', symbol='fgfm⁻³') +attograms_per_cubic_femtometer = NamedUnit(9.999999999999998e+23, Dimensions(length=-3, mass=1), name='attograms_per_cubic_femtometer', ascii_symbol='ag fm^-3', symbol='agfm⁻³') +atomic_mass_units_per_cubic_femtometer = NamedUnit(1.6605389209999992e+18, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_femtometer', ascii_symbol='au fm^-3', symbol='aufm⁻³') +pounds_per_cubic_femtometer = NamedUnit(4.5359236999999985e+44, Dimensions(length=-3, mass=1), name='pounds_per_cubic_femtometer', ascii_symbol='lb fm^-3', symbol='lbfm⁻³') +ounces_per_cubic_femtometer = NamedUnit(2.834952312499999e+43, Dimensions(length=-3, mass=1), name='ounces_per_cubic_femtometer', ascii_symbol='oz fm^-3', symbol='ozfm⁻³') +grams_per_cubic_attometer = NamedUnit(9.999999999999998e+50, Dimensions(length=-3, mass=1), name='grams_per_cubic_attometer', ascii_symbol='g am^-3', symbol='gam⁻³') +exagrams_per_cubic_attometer = NamedUnit(9.999999999999999e+68, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_attometer', ascii_symbol='Eg am^-3', symbol='Egam⁻³') +petagrams_per_cubic_attometer = NamedUnit(9.999999999999998e+65, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_attometer', ascii_symbol='Pg am^-3', symbol='Pgam⁻³') +teragrams_per_cubic_attometer = NamedUnit(9.999999999999999e+62, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_attometer', ascii_symbol='Tg am^-3', symbol='Tgam⁻³') +gigagrams_per_cubic_attometer = NamedUnit(9.999999999999998e+59, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_attometer', ascii_symbol='Gg am^-3', symbol='Ggam⁻³') +megagrams_per_cubic_attometer = NamedUnit(9.999999999999999e+56, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_attometer', ascii_symbol='Mg am^-3', symbol='Mgam⁻³') +kilograms_per_cubic_attometer = NamedUnit(9.999999999999999e+53, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_attometer', ascii_symbol='kg am^-3', symbol='kgam⁻³') +milligrams_per_cubic_attometer = NamedUnit(9.999999999999997e+47, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_attometer', ascii_symbol='mg am^-3', symbol='mgam⁻³') +micrograms_per_cubic_attometer = NamedUnit(1e+45, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_attometer', ascii_symbol='ug am^-3', symbol='µgam⁻³') +nanograms_per_cubic_attometer = NamedUnit(1e+42, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_attometer', ascii_symbol='ng am^-3', symbol='ngam⁻³') +picograms_per_cubic_attometer = NamedUnit(1e+39, Dimensions(length=-3, mass=1), name='picograms_per_cubic_attometer', ascii_symbol='pg am^-3', symbol='pgam⁻³') +femtograms_per_cubic_attometer = NamedUnit(9.999999999999999e+35, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_attometer', ascii_symbol='fg am^-3', symbol='fgam⁻³') +attograms_per_cubic_attometer = NamedUnit(1e+33, Dimensions(length=-3, mass=1), name='attograms_per_cubic_attometer', ascii_symbol='ag am^-3', symbol='agam⁻³') +atomic_mass_units_per_cubic_attometer = NamedUnit(1.6605389209999997e+27, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_attometer', ascii_symbol='au am^-3', symbol='auam⁻³') +pounds_per_cubic_attometer = NamedUnit(4.5359237e+53, Dimensions(length=-3, mass=1), name='pounds_per_cubic_attometer', ascii_symbol='lb am^-3', symbol='lbam⁻³') +ounces_per_cubic_attometer = NamedUnit(2.8349523125e+52, Dimensions(length=-3, mass=1), name='ounces_per_cubic_attometer', ascii_symbol='oz am^-3', symbol='ozam⁻³') +grams_per_cubic_decimeter = NamedUnit(0.9999999999999998, Dimensions(length=-3, mass=1), name='grams_per_cubic_decimeter', ascii_symbol='g dm^-3', symbol='gdm⁻³') +exagrams_per_cubic_decimeter = NamedUnit(9.999999999999997e+17, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_decimeter', ascii_symbol='Eg dm^-3', symbol='Egdm⁻³') +petagrams_per_cubic_decimeter = NamedUnit(999999999999999.8, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_decimeter', ascii_symbol='Pg dm^-3', symbol='Pgdm⁻³') +teragrams_per_cubic_decimeter = NamedUnit(999999999999.9998, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_decimeter', ascii_symbol='Tg dm^-3', symbol='Tgdm⁻³') +gigagrams_per_cubic_decimeter = NamedUnit(999999999.9999998, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_decimeter', ascii_symbol='Gg dm^-3', symbol='Ggdm⁻³') +megagrams_per_cubic_decimeter = NamedUnit(999999.9999999998, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_decimeter', ascii_symbol='Mg dm^-3', symbol='Mgdm⁻³') +kilograms_per_cubic_decimeter = NamedUnit(999.9999999999998, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_decimeter', ascii_symbol='kg dm^-3', symbol='kgdm⁻³') +milligrams_per_cubic_decimeter = NamedUnit(0.0009999999999999998, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_decimeter', ascii_symbol='mg dm^-3', symbol='mgdm⁻³') +micrograms_per_cubic_decimeter = NamedUnit(9.999999999999997e-07, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_decimeter', ascii_symbol='ug dm^-3', symbol='µgdm⁻³') +nanograms_per_cubic_decimeter = NamedUnit(9.999999999999999e-10, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_decimeter', ascii_symbol='ng dm^-3', symbol='ngdm⁻³') +picograms_per_cubic_decimeter = NamedUnit(9.999999999999998e-13, Dimensions(length=-3, mass=1), name='picograms_per_cubic_decimeter', ascii_symbol='pg dm^-3', symbol='pgdm⁻³') +femtograms_per_cubic_decimeter = NamedUnit(9.999999999999999e-16, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_decimeter', ascii_symbol='fg dm^-3', symbol='fgdm⁻³') +attograms_per_cubic_decimeter = NamedUnit(9.999999999999999e-19, Dimensions(length=-3, mass=1), name='attograms_per_cubic_decimeter', ascii_symbol='ag dm^-3', symbol='agdm⁻³') +atomic_mass_units_per_cubic_decimeter = NamedUnit(1.6605389209999993e-24, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_decimeter', ascii_symbol='au dm^-3', symbol='audm⁻³') +pounds_per_cubic_decimeter = NamedUnit(453.5923699999999, Dimensions(length=-3, mass=1), name='pounds_per_cubic_decimeter', ascii_symbol='lb dm^-3', symbol='lbdm⁻³') +ounces_per_cubic_decimeter = NamedUnit(28.349523124999994, Dimensions(length=-3, mass=1), name='ounces_per_cubic_decimeter', ascii_symbol='oz dm^-3', symbol='ozdm⁻³') +grams_per_cubic_centimeter = NamedUnit(999.9999999999999, Dimensions(length=-3, mass=1), name='grams_per_cubic_centimeter', ascii_symbol='g cm^-3', symbol='gcm⁻³') +exagrams_per_cubic_centimeter = NamedUnit(9.999999999999999e+20, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_centimeter', ascii_symbol='Eg cm^-3', symbol='Egcm⁻³') +petagrams_per_cubic_centimeter = NamedUnit(9.999999999999999e+17, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_centimeter', ascii_symbol='Pg cm^-3', symbol='Pgcm⁻³') +teragrams_per_cubic_centimeter = NamedUnit(999999999999999.9, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_centimeter', ascii_symbol='Tg cm^-3', symbol='Tgcm⁻³') +gigagrams_per_cubic_centimeter = NamedUnit(999999999999.9999, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_centimeter', ascii_symbol='Gg cm^-3', symbol='Ggcm⁻³') +megagrams_per_cubic_centimeter = NamedUnit(999999999.9999999, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_centimeter', ascii_symbol='Mg cm^-3', symbol='Mgcm⁻³') +kilograms_per_cubic_centimeter = NamedUnit(999999.9999999999, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_centimeter', ascii_symbol='kg cm^-3', symbol='kgcm⁻³') +milligrams_per_cubic_centimeter = NamedUnit(0.9999999999999998, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_centimeter', ascii_symbol='mg cm^-3', symbol='mgcm⁻³') +micrograms_per_cubic_centimeter = NamedUnit(0.0009999999999999998, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_centimeter', ascii_symbol='ug cm^-3', symbol='µgcm⁻³') +nanograms_per_cubic_centimeter = NamedUnit(1e-06, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_centimeter', ascii_symbol='ng cm^-3', symbol='ngcm⁻³') +picograms_per_cubic_centimeter = NamedUnit(9.999999999999999e-10, Dimensions(length=-3, mass=1), name='picograms_per_cubic_centimeter', ascii_symbol='pg cm^-3', symbol='pgcm⁻³') +femtograms_per_cubic_centimeter = NamedUnit(1e-12, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_centimeter', ascii_symbol='fg cm^-3', symbol='fgcm⁻³') +attograms_per_cubic_centimeter = NamedUnit(9.999999999999999e-16, Dimensions(length=-3, mass=1), name='attograms_per_cubic_centimeter', ascii_symbol='ag cm^-3', symbol='agcm⁻³') +atomic_mass_units_per_cubic_centimeter = NamedUnit(1.6605389209999996e-21, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_centimeter', ascii_symbol='au cm^-3', symbol='aucm⁻³') +pounds_per_cubic_centimeter = NamedUnit(453592.36999999994, Dimensions(length=-3, mass=1), name='pounds_per_cubic_centimeter', ascii_symbol='lb cm^-3', symbol='lbcm⁻³') +ounces_per_cubic_centimeter = NamedUnit(28349.523124999996, Dimensions(length=-3, mass=1), name='ounces_per_cubic_centimeter', ascii_symbol='oz cm^-3', symbol='ozcm⁻³') +grams_per_cubic_angstrom = NamedUnit(9.999999999999999e+26, Dimensions(length=-3, mass=1), name='grams_per_cubic_angstrom', ascii_symbol='g Ang^-3', symbol='gÅ⁻³') +exagrams_per_cubic_angstrom = NamedUnit(1e+45, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_angstrom', ascii_symbol='Eg Ang^-3', symbol='EgÅ⁻³') +petagrams_per_cubic_angstrom = NamedUnit(9.999999999999999e+41, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_angstrom', ascii_symbol='Pg Ang^-3', symbol='PgÅ⁻³') +teragrams_per_cubic_angstrom = NamedUnit(1e+39, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_angstrom', ascii_symbol='Tg Ang^-3', symbol='TgÅ⁻³') +gigagrams_per_cubic_angstrom = NamedUnit(9.999999999999999e+35, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_angstrom', ascii_symbol='Gg Ang^-3', symbol='GgÅ⁻³') +megagrams_per_cubic_angstrom = NamedUnit(1e+33, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_angstrom', ascii_symbol='Mg Ang^-3', symbol='MgÅ⁻³') +kilograms_per_cubic_angstrom = NamedUnit(9.999999999999999e+29, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_angstrom', ascii_symbol='kg Ang^-3', symbol='kgÅ⁻³') +milligrams_per_cubic_angstrom = NamedUnit(9.999999999999998e+23, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_angstrom', ascii_symbol='mg Ang^-3', symbol='mgÅ⁻³') +micrograms_per_cubic_angstrom = NamedUnit(1e+21, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_angstrom', ascii_symbol='ug Ang^-3', symbol='µgÅ⁻³') +nanograms_per_cubic_angstrom = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_angstrom', ascii_symbol='ng Ang^-3', symbol='ngÅ⁻³') +picograms_per_cubic_angstrom = NamedUnit(1000000000000000.0, Dimensions(length=-3, mass=1), name='picograms_per_cubic_angstrom', ascii_symbol='pg Ang^-3', symbol='pgÅ⁻³') +femtograms_per_cubic_angstrom = NamedUnit(1000000000000.0, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_angstrom', ascii_symbol='fg Ang^-3', symbol='fgÅ⁻³') +attograms_per_cubic_angstrom = NamedUnit(1000000000.0, Dimensions(length=-3, mass=1), name='attograms_per_cubic_angstrom', ascii_symbol='ag Ang^-3', symbol='agÅ⁻³') +atomic_mass_units_per_cubic_angstrom = NamedUnit(1660.5389209999996, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_angstrom', ascii_symbol='au Ang^-3', symbol='auÅ⁻³') +pounds_per_cubic_angstrom = NamedUnit(4.5359237e+29, Dimensions(length=-3, mass=1), name='pounds_per_cubic_angstrom', ascii_symbol='lb Ang^-3', symbol='lbÅ⁻³') +ounces_per_cubic_angstrom = NamedUnit(2.8349523125e+28, Dimensions(length=-3, mass=1), name='ounces_per_cubic_angstrom', ascii_symbol='oz Ang^-3', symbol='ozÅ⁻³') +grams_per_cubic_mile = NamedUnit(2.399127585789277e-13, Dimensions(length=-3, mass=1), name='grams_per_cubic_mile', ascii_symbol='g miles^-3', symbol='gmiles⁻³') +exagrams_per_cubic_mile = NamedUnit(239912.7585789277, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_mile', ascii_symbol='Eg miles^-3', symbol='Egmiles⁻³') +petagrams_per_cubic_mile = NamedUnit(239.9127585789277, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_mile', ascii_symbol='Pg miles^-3', symbol='Pgmiles⁻³') +teragrams_per_cubic_mile = NamedUnit(0.2399127585789277, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_mile', ascii_symbol='Tg miles^-3', symbol='Tgmiles⁻³') +gigagrams_per_cubic_mile = NamedUnit(0.0002399127585789277, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_mile', ascii_symbol='Gg miles^-3', symbol='Ggmiles⁻³') +megagrams_per_cubic_mile = NamedUnit(2.399127585789277e-07, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_mile', ascii_symbol='Mg miles^-3', symbol='Mgmiles⁻³') +kilograms_per_cubic_mile = NamedUnit(2.399127585789277e-10, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_mile', ascii_symbol='kg miles^-3', symbol='kgmiles⁻³') +milligrams_per_cubic_mile = NamedUnit(2.399127585789277e-16, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_mile', ascii_symbol='mg miles^-3', symbol='mgmiles⁻³') +micrograms_per_cubic_mile = NamedUnit(2.3991275857892774e-19, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_mile', ascii_symbol='ug miles^-3', symbol='µgmiles⁻³') +nanograms_per_cubic_mile = NamedUnit(2.3991275857892774e-22, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_mile', ascii_symbol='ng miles^-3', symbol='ngmiles⁻³') +picograms_per_cubic_mile = NamedUnit(2.399127585789277e-25, Dimensions(length=-3, mass=1), name='picograms_per_cubic_mile', ascii_symbol='pg miles^-3', symbol='pgmiles⁻³') +femtograms_per_cubic_mile = NamedUnit(2.3991275857892772e-28, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_mile', ascii_symbol='fg miles^-3', symbol='fgmiles⁻³') +attograms_per_cubic_mile = NamedUnit(2.399127585789277e-31, Dimensions(length=-3, mass=1), name='attograms_per_cubic_mile', ascii_symbol='ag miles^-3', symbol='agmiles⁻³') +atomic_mass_units_per_cubic_mile = NamedUnit(3.98384473264786e-37, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_mile', ascii_symbol='au miles^-3', symbol='aumiles⁻³') +pounds_per_cubic_mile = NamedUnit(1.0882259675705365e-10, Dimensions(length=-3, mass=1), name='pounds_per_cubic_mile', ascii_symbol='lb miles^-3', symbol='lbmiles⁻³') +ounces_per_cubic_mile = NamedUnit(6.801412297315853e-12, Dimensions(length=-3, mass=1), name='ounces_per_cubic_mile', ascii_symbol='oz miles^-3', symbol='ozmiles⁻³') +grams_per_cubic_yard = NamedUnit(0.0013079506193143919, Dimensions(length=-3, mass=1), name='grams_per_cubic_yard', ascii_symbol='g yrd^-3', symbol='gyrd⁻³') +exagrams_per_cubic_yard = NamedUnit(1307950619314391.8, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_yard', ascii_symbol='Eg yrd^-3', symbol='Egyrd⁻³') +petagrams_per_cubic_yard = NamedUnit(1307950619314.3918, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_yard', ascii_symbol='Pg yrd^-3', symbol='Pgyrd⁻³') +teragrams_per_cubic_yard = NamedUnit(1307950619.3143919, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_yard', ascii_symbol='Tg yrd^-3', symbol='Tgyrd⁻³') +gigagrams_per_cubic_yard = NamedUnit(1307950.6193143919, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_yard', ascii_symbol='Gg yrd^-3', symbol='Ggyrd⁻³') +megagrams_per_cubic_yard = NamedUnit(1307.9506193143918, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_yard', ascii_symbol='Mg yrd^-3', symbol='Mgyrd⁻³') +kilograms_per_cubic_yard = NamedUnit(1.3079506193143917, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_yard', ascii_symbol='kg yrd^-3', symbol='kgyrd⁻³') +milligrams_per_cubic_yard = NamedUnit(1.3079506193143917e-06, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_yard', ascii_symbol='mg yrd^-3', symbol='mgyrd⁻³') +micrograms_per_cubic_yard = NamedUnit(1.3079506193143919e-09, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_yard', ascii_symbol='ug yrd^-3', symbol='µgyrd⁻³') +nanograms_per_cubic_yard = NamedUnit(1.307950619314392e-12, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_yard', ascii_symbol='ng yrd^-3', symbol='ngyrd⁻³') +picograms_per_cubic_yard = NamedUnit(1.3079506193143919e-15, Dimensions(length=-3, mass=1), name='picograms_per_cubic_yard', ascii_symbol='pg yrd^-3', symbol='pgyrd⁻³') +femtograms_per_cubic_yard = NamedUnit(1.3079506193143918e-18, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_yard', ascii_symbol='fg yrd^-3', symbol='fgyrd⁻³') +attograms_per_cubic_yard = NamedUnit(1.307950619314392e-21, Dimensions(length=-3, mass=1), name='attograms_per_cubic_yard', ascii_symbol='ag yrd^-3', symbol='agyrd⁻³') +atomic_mass_units_per_cubic_yard = NamedUnit(2.1719029101176016e-27, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_yard', ascii_symbol='au yrd^-3', symbol='auyrd⁻³') +pounds_per_cubic_yard = NamedUnit(0.5932764212577828, Dimensions(length=-3, mass=1), name='pounds_per_cubic_yard', ascii_symbol='lb yrd^-3', symbol='lbyrd⁻³') +ounces_per_cubic_yard = NamedUnit(0.037079776328611425, Dimensions(length=-3, mass=1), name='ounces_per_cubic_yard', ascii_symbol='oz yrd^-3', symbol='ozyrd⁻³') +grams_per_cubic_foot = NamedUnit(0.035314666721488586, Dimensions(length=-3, mass=1), name='grams_per_cubic_foot', ascii_symbol='g ft^-3', symbol='gft⁻³') +exagrams_per_cubic_foot = NamedUnit(3.5314666721488584e+16, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_foot', ascii_symbol='Eg ft^-3', symbol='Egft⁻³') +petagrams_per_cubic_foot = NamedUnit(35314666721488.586, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_foot', ascii_symbol='Pg ft^-3', symbol='Pgft⁻³') +teragrams_per_cubic_foot = NamedUnit(35314666721.48859, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_foot', ascii_symbol='Tg ft^-3', symbol='Tgft⁻³') +gigagrams_per_cubic_foot = NamedUnit(35314666.72148859, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_foot', ascii_symbol='Gg ft^-3', symbol='Ggft⁻³') +megagrams_per_cubic_foot = NamedUnit(35314.66672148858, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_foot', ascii_symbol='Mg ft^-3', symbol='Mgft⁻³') +kilograms_per_cubic_foot = NamedUnit(35.314666721488585, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_foot', ascii_symbol='kg ft^-3', symbol='kgft⁻³') +milligrams_per_cubic_foot = NamedUnit(3.5314666721488586e-05, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_foot', ascii_symbol='mg ft^-3', symbol='mgft⁻³') +micrograms_per_cubic_foot = NamedUnit(3.5314666721488584e-08, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_foot', ascii_symbol='ug ft^-3', symbol='µgft⁻³') +nanograms_per_cubic_foot = NamedUnit(3.531466672148859e-11, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_foot', ascii_symbol='ng ft^-3', symbol='ngft⁻³') +picograms_per_cubic_foot = NamedUnit(3.531466672148859e-14, Dimensions(length=-3, mass=1), name='picograms_per_cubic_foot', ascii_symbol='pg ft^-3', symbol='pgft⁻³') +femtograms_per_cubic_foot = NamedUnit(3.5314666721488585e-17, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_foot', ascii_symbol='fg ft^-3', symbol='fgft⁻³') +attograms_per_cubic_foot = NamedUnit(3.531466672148859e-20, Dimensions(length=-3, mass=1), name='attograms_per_cubic_foot', ascii_symbol='ag ft^-3', symbol='agft⁻³') +atomic_mass_units_per_cubic_foot = NamedUnit(5.864137857317526e-26, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_foot', ascii_symbol='au ft^-3', symbol='auft⁻³') +pounds_per_cubic_foot = NamedUnit(16.018463373960138, Dimensions(length=-3, mass=1), name='pounds_per_cubic_foot', ascii_symbol='lb ft^-3', symbol='lbft⁻³') +ounces_per_cubic_foot = NamedUnit(1.0011539608725086, Dimensions(length=-3, mass=1), name='ounces_per_cubic_foot', ascii_symbol='oz ft^-3', symbol='ozft⁻³') +grams_per_cubic_inch = NamedUnit(61.02374409473229, Dimensions(length=-3, mass=1), name='grams_per_cubic_inch', ascii_symbol='g in^-3', symbol='gin⁻³') +exagrams_per_cubic_inch = NamedUnit(6.102374409473229e+19, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_inch', ascii_symbol='Eg in^-3', symbol='Egin⁻³') +petagrams_per_cubic_inch = NamedUnit(6.102374409473229e+16, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_inch', ascii_symbol='Pg in^-3', symbol='Pgin⁻³') +teragrams_per_cubic_inch = NamedUnit(61023744094732.29, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_inch', ascii_symbol='Tg in^-3', symbol='Tgin⁻³') +gigagrams_per_cubic_inch = NamedUnit(61023744094.732285, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_inch', ascii_symbol='Gg in^-3', symbol='Ggin⁻³') +megagrams_per_cubic_inch = NamedUnit(61023744.094732285, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_inch', ascii_symbol='Mg in^-3', symbol='Mgin⁻³') +kilograms_per_cubic_inch = NamedUnit(61023.74409473229, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_inch', ascii_symbol='kg in^-3', symbol='kgin⁻³') +milligrams_per_cubic_inch = NamedUnit(0.06102374409473228, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_inch', ascii_symbol='mg in^-3', symbol='mgin⁻³') +micrograms_per_cubic_inch = NamedUnit(6.102374409473229e-05, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_inch', ascii_symbol='ug in^-3', symbol='µgin⁻³') +nanograms_per_cubic_inch = NamedUnit(6.10237440947323e-08, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_inch', ascii_symbol='ng in^-3', symbol='ngin⁻³') +picograms_per_cubic_inch = NamedUnit(6.102374409473229e-11, Dimensions(length=-3, mass=1), name='picograms_per_cubic_inch', ascii_symbol='pg in^-3', symbol='pgin⁻³') +femtograms_per_cubic_inch = NamedUnit(6.10237440947323e-14, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_inch', ascii_symbol='fg in^-3', symbol='fgin⁻³') +attograms_per_cubic_inch = NamedUnit(6.10237440947323e-17, Dimensions(length=-3, mass=1), name='attograms_per_cubic_inch', ascii_symbol='ag in^-3', symbol='agin⁻³') +atomic_mass_units_per_cubic_inch = NamedUnit(1.0133230217444687e-22, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_inch', ascii_symbol='au in^-3', symbol='auin⁻³') +pounds_per_cubic_inch = NamedUnit(27679.904710203125, Dimensions(length=-3, mass=1), name='pounds_per_cubic_inch', ascii_symbol='lb in^-3', symbol='lbin⁻³') +ounces_per_cubic_inch = NamedUnit(1729.9940443876953, Dimensions(length=-3, mass=1), name='ounces_per_cubic_inch', ascii_symbol='oz in^-3', symbol='ozin⁻³') +moles_per_cubic_meter = NamedUnit(6.02214076e+23, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_meter', ascii_symbol='mol m^-3', symbol='molm⁻³') +millimoles_per_cubic_meter = NamedUnit(6.02214076e+20, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_meter', ascii_symbol='mmol m^-3', symbol='mmolm⁻³') +micromoles_per_cubic_meter = NamedUnit(6.02214076e+17, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_meter', ascii_symbol='umol m^-3', symbol='µmolm⁻³') +nanomoles_per_cubic_meter = NamedUnit(602214076000000.0, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_meter', ascii_symbol='nmol m^-3', symbol='nmolm⁻³') +picomoles_per_cubic_meter = NamedUnit(602214076000.0, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_meter', ascii_symbol='pmol m^-3', symbol='pmolm⁻³') +femtomoles_per_cubic_meter = NamedUnit(602214076.0, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_meter', ascii_symbol='fmol m^-3', symbol='fmolm⁻³') +attomoles_per_cubic_meter = NamedUnit(602214.076, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_meter', ascii_symbol='amol m^-3', symbol='amolm⁻³') +moles_per_cubic_exameter = NamedUnit(6.0221407599999995e-31, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_exameter', ascii_symbol='mol Em^-3', symbol='molEm⁻³') +millimoles_per_cubic_exameter = NamedUnit(6.02214076e-34, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_exameter', ascii_symbol='mmol Em^-3', symbol='mmolEm⁻³') +micromoles_per_cubic_exameter = NamedUnit(6.02214076e-37, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_exameter', ascii_symbol='umol Em^-3', symbol='µmolEm⁻³') +nanomoles_per_cubic_exameter = NamedUnit(6.022140759999999e-40, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_exameter', ascii_symbol='nmol Em^-3', symbol='nmolEm⁻³') +picomoles_per_cubic_exameter = NamedUnit(6.022140759999999e-43, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_exameter', ascii_symbol='pmol Em^-3', symbol='pmolEm⁻³') +femtomoles_per_cubic_exameter = NamedUnit(6.02214076e-46, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_exameter', ascii_symbol='fmol Em^-3', symbol='fmolEm⁻³') +attomoles_per_cubic_exameter = NamedUnit(6.022140759999999e-49, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_exameter', ascii_symbol='amol Em^-3', symbol='amolEm⁻³') +moles_per_cubic_petameter = NamedUnit(6.02214076e-22, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_petameter', ascii_symbol='mol Pm^-3', symbol='molPm⁻³') +millimoles_per_cubic_petameter = NamedUnit(6.0221407600000005e-25, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_petameter', ascii_symbol='mmol Pm^-3', symbol='mmolPm⁻³') +micromoles_per_cubic_petameter = NamedUnit(6.02214076e-28, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_petameter', ascii_symbol='umol Pm^-3', symbol='µmolPm⁻³') +nanomoles_per_cubic_petameter = NamedUnit(6.02214076e-31, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_petameter', ascii_symbol='nmol Pm^-3', symbol='nmolPm⁻³') +picomoles_per_cubic_petameter = NamedUnit(6.0221407600000005e-34, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_petameter', ascii_symbol='pmol Pm^-3', symbol='pmolPm⁻³') +femtomoles_per_cubic_petameter = NamedUnit(6.022140760000001e-37, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_petameter', ascii_symbol='fmol Pm^-3', symbol='fmolPm⁻³') +attomoles_per_cubic_petameter = NamedUnit(6.022140760000001e-40, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_petameter', ascii_symbol='amol Pm^-3', symbol='amolPm⁻³') +moles_per_cubic_terameter = NamedUnit(6.022140759999999e-13, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_terameter', ascii_symbol='mol Tm^-3', symbol='molTm⁻³') +millimoles_per_cubic_terameter = NamedUnit(6.02214076e-16, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_terameter', ascii_symbol='mmol Tm^-3', symbol='mmolTm⁻³') +micromoles_per_cubic_terameter = NamedUnit(6.02214076e-19, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_terameter', ascii_symbol='umol Tm^-3', symbol='µmolTm⁻³') +nanomoles_per_cubic_terameter = NamedUnit(6.02214076e-22, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_terameter', ascii_symbol='nmol Tm^-3', symbol='nmolTm⁻³') +picomoles_per_cubic_terameter = NamedUnit(6.02214076e-25, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_terameter', ascii_symbol='pmol Tm^-3', symbol='pmolTm⁻³') +femtomoles_per_cubic_terameter = NamedUnit(6.02214076e-28, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_terameter', ascii_symbol='fmol Tm^-3', symbol='fmolTm⁻³') +attomoles_per_cubic_terameter = NamedUnit(6.0221407599999995e-31, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_terameter', ascii_symbol='amol Tm^-3', symbol='amolTm⁻³') +moles_per_cubic_gigameter = NamedUnit(0.000602214076, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_gigameter', ascii_symbol='mol Gm^-3', symbol='molGm⁻³') +millimoles_per_cubic_gigameter = NamedUnit(6.022140760000001e-07, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_gigameter', ascii_symbol='mmol Gm^-3', symbol='mmolGm⁻³') +micromoles_per_cubic_gigameter = NamedUnit(6.02214076e-10, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_gigameter', ascii_symbol='umol Gm^-3', symbol='µmolGm⁻³') +nanomoles_per_cubic_gigameter = NamedUnit(6.02214076e-13, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_gigameter', ascii_symbol='nmol Gm^-3', symbol='nmolGm⁻³') +picomoles_per_cubic_gigameter = NamedUnit(6.02214076e-16, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_gigameter', ascii_symbol='pmol Gm^-3', symbol='pmolGm⁻³') +femtomoles_per_cubic_gigameter = NamedUnit(6.02214076e-19, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_gigameter', ascii_symbol='fmol Gm^-3', symbol='fmolGm⁻³') +attomoles_per_cubic_gigameter = NamedUnit(6.02214076e-22, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_gigameter', ascii_symbol='amol Gm^-3', symbol='amolGm⁻³') +moles_per_cubic_megameter = NamedUnit(602214.076, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_megameter', ascii_symbol='mol Mm^-3', symbol='molMm⁻³') +millimoles_per_cubic_megameter = NamedUnit(602.214076, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_megameter', ascii_symbol='mmol Mm^-3', symbol='mmolMm⁻³') +micromoles_per_cubic_megameter = NamedUnit(0.602214076, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_megameter', ascii_symbol='umol Mm^-3', symbol='µmolMm⁻³') +nanomoles_per_cubic_megameter = NamedUnit(0.000602214076, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_megameter', ascii_symbol='nmol Mm^-3', symbol='nmolMm⁻³') +picomoles_per_cubic_megameter = NamedUnit(6.02214076e-07, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_megameter', ascii_symbol='pmol Mm^-3', symbol='pmolMm⁻³') +femtomoles_per_cubic_megameter = NamedUnit(6.02214076e-10, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_megameter', ascii_symbol='fmol Mm^-3', symbol='fmolMm⁻³') +attomoles_per_cubic_megameter = NamedUnit(6.02214076e-13, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_megameter', ascii_symbol='amol Mm^-3', symbol='amolMm⁻³') +moles_per_cubic_kilometer = NamedUnit(602214076000000.0, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_kilometer', ascii_symbol='mol km^-3', symbol='molkm⁻³') +millimoles_per_cubic_kilometer = NamedUnit(602214076000.0, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_kilometer', ascii_symbol='mmol km^-3', symbol='mmolkm⁻³') +micromoles_per_cubic_kilometer = NamedUnit(602214076.0, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_kilometer', ascii_symbol='umol km^-3', symbol='µmolkm⁻³') +nanomoles_per_cubic_kilometer = NamedUnit(602214.076, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_kilometer', ascii_symbol='nmol km^-3', symbol='nmolkm⁻³') +picomoles_per_cubic_kilometer = NamedUnit(602.214076, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_kilometer', ascii_symbol='pmol km^-3', symbol='pmolkm⁻³') +femtomoles_per_cubic_kilometer = NamedUnit(0.602214076, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_kilometer', ascii_symbol='fmol km^-3', symbol='fmolkm⁻³') +attomoles_per_cubic_kilometer = NamedUnit(0.000602214076, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_kilometer', ascii_symbol='amol km^-3', symbol='amolkm⁻³') +moles_per_cubic_millimeter = NamedUnit(6.0221407599999995e+32, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_millimeter', ascii_symbol='mol mm^-3', symbol='molmm⁻³') +millimoles_per_cubic_millimeter = NamedUnit(6.02214076e+29, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_millimeter', ascii_symbol='mmol mm^-3', symbol='mmolmm⁻³') +micromoles_per_cubic_millimeter = NamedUnit(6.0221407599999996e+26, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_millimeter', ascii_symbol='umol mm^-3', symbol='µmolmm⁻³') +nanomoles_per_cubic_millimeter = NamedUnit(6.02214076e+23, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_millimeter', ascii_symbol='nmol mm^-3', symbol='nmolmm⁻³') +picomoles_per_cubic_millimeter = NamedUnit(6.02214076e+20, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_millimeter', ascii_symbol='pmol mm^-3', symbol='pmolmm⁻³') +femtomoles_per_cubic_millimeter = NamedUnit(6.02214076e+17, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_millimeter', ascii_symbol='fmol mm^-3', symbol='fmolmm⁻³') +attomoles_per_cubic_millimeter = NamedUnit(602214076000000.0, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_millimeter', ascii_symbol='amol mm^-3', symbol='amolmm⁻³') +moles_per_cubic_micrometer = NamedUnit(6.022140760000001e+41, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_micrometer', ascii_symbol='mol um^-3', symbol='molµm⁻³') +millimoles_per_cubic_micrometer = NamedUnit(6.022140760000001e+38, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_micrometer', ascii_symbol='mmol um^-3', symbol='mmolµm⁻³') +micromoles_per_cubic_micrometer = NamedUnit(6.0221407600000004e+35, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_micrometer', ascii_symbol='umol um^-3', symbol='µmolµm⁻³') +nanomoles_per_cubic_micrometer = NamedUnit(6.022140760000001e+32, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_micrometer', ascii_symbol='nmol um^-3', symbol='nmolµm⁻³') +picomoles_per_cubic_micrometer = NamedUnit(6.022140760000001e+29, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_micrometer', ascii_symbol='pmol um^-3', symbol='pmolµm⁻³') +femtomoles_per_cubic_micrometer = NamedUnit(6.022140760000001e+26, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_micrometer', ascii_symbol='fmol um^-3', symbol='fmolµm⁻³') +attomoles_per_cubic_micrometer = NamedUnit(6.0221407600000005e+23, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_micrometer', ascii_symbol='amol um^-3', symbol='amolµm⁻³') +moles_per_cubic_nanometer = NamedUnit(6.022140759999999e+50, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_nanometer', ascii_symbol='mol nm^-3', symbol='molnm⁻³') +millimoles_per_cubic_nanometer = NamedUnit(6.022140759999999e+47, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_nanometer', ascii_symbol='mmol nm^-3', symbol='mmolnm⁻³') +micromoles_per_cubic_nanometer = NamedUnit(6.022140759999999e+44, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_nanometer', ascii_symbol='umol nm^-3', symbol='µmolnm⁻³') +nanomoles_per_cubic_nanometer = NamedUnit(6.022140759999998e+41, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_nanometer', ascii_symbol='nmol nm^-3', symbol='nmolnm⁻³') +picomoles_per_cubic_nanometer = NamedUnit(6.0221407599999985e+38, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_nanometer', ascii_symbol='pmol nm^-3', symbol='pmolnm⁻³') +femtomoles_per_cubic_nanometer = NamedUnit(6.022140759999999e+35, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_nanometer', ascii_symbol='fmol nm^-3', symbol='fmolnm⁻³') +attomoles_per_cubic_nanometer = NamedUnit(6.022140759999999e+32, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_nanometer', ascii_symbol='amol nm^-3', symbol='amolnm⁻³') +moles_per_cubic_picometer = NamedUnit(6.0221407600000005e+59, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_picometer', ascii_symbol='mol pm^-3', symbol='molpm⁻³') +millimoles_per_cubic_picometer = NamedUnit(6.0221407600000005e+56, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_picometer', ascii_symbol='mmol pm^-3', symbol='mmolpm⁻³') +micromoles_per_cubic_picometer = NamedUnit(6.022140760000001e+53, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_picometer', ascii_symbol='umol pm^-3', symbol='µmolpm⁻³') +nanomoles_per_cubic_picometer = NamedUnit(6.0221407600000005e+50, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_picometer', ascii_symbol='nmol pm^-3', symbol='nmolpm⁻³') +picomoles_per_cubic_picometer = NamedUnit(6.02214076e+47, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_picometer', ascii_symbol='pmol pm^-3', symbol='pmolpm⁻³') +femtomoles_per_cubic_picometer = NamedUnit(6.022140760000001e+44, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_picometer', ascii_symbol='fmol pm^-3', symbol='fmolpm⁻³') +attomoles_per_cubic_picometer = NamedUnit(6.022140760000001e+41, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_picometer', ascii_symbol='amol pm^-3', symbol='amolpm⁻³') +moles_per_cubic_femtometer = NamedUnit(6.022140759999998e+68, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_femtometer', ascii_symbol='mol fm^-3', symbol='molfm⁻³') +millimoles_per_cubic_femtometer = NamedUnit(6.022140759999998e+65, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_femtometer', ascii_symbol='mmol fm^-3', symbol='mmolfm⁻³') +micromoles_per_cubic_femtometer = NamedUnit(6.022140759999999e+62, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_femtometer', ascii_symbol='umol fm^-3', symbol='µmolfm⁻³') +nanomoles_per_cubic_femtometer = NamedUnit(6.022140759999998e+59, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_femtometer', ascii_symbol='nmol fm^-3', symbol='nmolfm⁻³') +picomoles_per_cubic_femtometer = NamedUnit(6.022140759999998e+56, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_femtometer', ascii_symbol='pmol fm^-3', symbol='pmolfm⁻³') +femtomoles_per_cubic_femtometer = NamedUnit(6.022140759999998e+53, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_femtometer', ascii_symbol='fmol fm^-3', symbol='fmolfm⁻³') +attomoles_per_cubic_femtometer = NamedUnit(6.022140759999998e+50, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_femtometer', ascii_symbol='amol fm^-3', symbol='amolfm⁻³') +moles_per_cubic_attometer = NamedUnit(6.022140759999998e+77, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_attometer', ascii_symbol='mol am^-3', symbol='molam⁻³') +millimoles_per_cubic_attometer = NamedUnit(6.022140759999999e+74, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_attometer', ascii_symbol='mmol am^-3', symbol='mmolam⁻³') +micromoles_per_cubic_attometer = NamedUnit(6.022140759999999e+71, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_attometer', ascii_symbol='umol am^-3', symbol='µmolam⁻³') +nanomoles_per_cubic_attometer = NamedUnit(6.022140759999999e+68, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_attometer', ascii_symbol='nmol am^-3', symbol='nmolam⁻³') +picomoles_per_cubic_attometer = NamedUnit(6.022140759999999e+65, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_attometer', ascii_symbol='pmol am^-3', symbol='pmolam⁻³') +femtomoles_per_cubic_attometer = NamedUnit(6.022140759999999e+62, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_attometer', ascii_symbol='fmol am^-3', symbol='fmolam⁻³') +attomoles_per_cubic_attometer = NamedUnit(6.022140759999999e+59, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_attometer', ascii_symbol='amol am^-3', symbol='amolam⁻³') +moles_per_cubic_decimeter = NamedUnit(6.022140759999998e+26, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_decimeter', ascii_symbol='mol dm^-3', symbol='moldm⁻³') +millimoles_per_cubic_decimeter = NamedUnit(6.0221407599999985e+23, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_decimeter', ascii_symbol='mmol dm^-3', symbol='mmoldm⁻³') +micromoles_per_cubic_decimeter = NamedUnit(6.022140759999999e+20, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_decimeter', ascii_symbol='umol dm^-3', symbol='µmoldm⁻³') +nanomoles_per_cubic_decimeter = NamedUnit(6.022140759999999e+17, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_decimeter', ascii_symbol='nmol dm^-3', symbol='nmoldm⁻³') +picomoles_per_cubic_decimeter = NamedUnit(602214075999999.9, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_decimeter', ascii_symbol='pmol dm^-3', symbol='pmoldm⁻³') +femtomoles_per_cubic_decimeter = NamedUnit(602214075999.9999, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_decimeter', ascii_symbol='fmol dm^-3', symbol='fmoldm⁻³') +attomoles_per_cubic_decimeter = NamedUnit(602214075.9999999, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_decimeter', ascii_symbol='amol dm^-3', symbol='amoldm⁻³') +moles_per_cubic_centimeter = NamedUnit(6.022140759999999e+29, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_centimeter', ascii_symbol='mol cm^-3', symbol='molcm⁻³') +millimoles_per_cubic_centimeter = NamedUnit(6.022140759999999e+26, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_centimeter', ascii_symbol='mmol cm^-3', symbol='mmolcm⁻³') +micromoles_per_cubic_centimeter = NamedUnit(6.022140759999999e+23, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_centimeter', ascii_symbol='umol cm^-3', symbol='µmolcm⁻³') +nanomoles_per_cubic_centimeter = NamedUnit(6.022140759999999e+20, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_centimeter', ascii_symbol='nmol cm^-3', symbol='nmolcm⁻³') +picomoles_per_cubic_centimeter = NamedUnit(6.022140759999999e+17, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_centimeter', ascii_symbol='pmol cm^-3', symbol='pmolcm⁻³') +femtomoles_per_cubic_centimeter = NamedUnit(602214075999999.9, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_centimeter', ascii_symbol='fmol cm^-3', symbol='fmolcm⁻³') +attomoles_per_cubic_centimeter = NamedUnit(602214075999.9999, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_centimeter', ascii_symbol='amol cm^-3', symbol='amolcm⁻³') +moles_per_cubic_angstrom = NamedUnit(6.022140759999999e+53, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_angstrom', ascii_symbol='mol Ang^-3', symbol='molÅ⁻³') +millimoles_per_cubic_angstrom = NamedUnit(6.02214076e+50, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_angstrom', ascii_symbol='mmol Ang^-3', symbol='mmolÅ⁻³') +micromoles_per_cubic_angstrom = NamedUnit(6.022140759999999e+47, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_angstrom', ascii_symbol='umol Ang^-3', symbol='µmolÅ⁻³') +nanomoles_per_cubic_angstrom = NamedUnit(6.02214076e+44, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_angstrom', ascii_symbol='nmol Ang^-3', symbol='nmolÅ⁻³') +picomoles_per_cubic_angstrom = NamedUnit(6.02214076e+41, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_angstrom', ascii_symbol='pmol Ang^-3', symbol='pmolÅ⁻³') +femtomoles_per_cubic_angstrom = NamedUnit(6.022140759999999e+38, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_angstrom', ascii_symbol='fmol Ang^-3', symbol='fmolÅ⁻³') +attomoles_per_cubic_angstrom = NamedUnit(6.02214076e+35, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_angstrom', ascii_symbol='amol Ang^-3', symbol='amolÅ⁻³') +moles_per_cubic_mile = NamedUnit(144478840228220.0, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_mile', ascii_symbol='mol miles^-3', symbol='molmiles⁻³') +millimoles_per_cubic_mile = NamedUnit(144478840228.22003, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_mile', ascii_symbol='mmol miles^-3', symbol='mmolmiles⁻³') +micromoles_per_cubic_mile = NamedUnit(144478840.22822002, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_mile', ascii_symbol='umol miles^-3', symbol='µmolmiles⁻³') +nanomoles_per_cubic_mile = NamedUnit(144478.84022822, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_mile', ascii_symbol='nmol miles^-3', symbol='nmolmiles⁻³') +picomoles_per_cubic_mile = NamedUnit(144.47884022822, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_mile', ascii_symbol='pmol miles^-3', symbol='pmolmiles⁻³') +femtomoles_per_cubic_mile = NamedUnit(0.14447884022822002, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_mile', ascii_symbol='fmol miles^-3', symbol='fmolmiles⁻³') +attomoles_per_cubic_mile = NamedUnit(0.00014447884022822003, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_mile', ascii_symbol='amol miles^-3', symbol='amolmiles⁻³') +moles_per_cubic_yard = NamedUnit(7.876662736640442e+23, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_yard', ascii_symbol='mol yrd^-3', symbol='molyrd⁻³') +millimoles_per_cubic_yard = NamedUnit(7.876662736640442e+20, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_yard', ascii_symbol='mmol yrd^-3', symbol='mmolyrd⁻³') +micromoles_per_cubic_yard = NamedUnit(7.876662736640442e+17, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_yard', ascii_symbol='umol yrd^-3', symbol='µmolyrd⁻³') +nanomoles_per_cubic_yard = NamedUnit(787666273664044.2, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_yard', ascii_symbol='nmol yrd^-3', symbol='nmolyrd⁻³') +picomoles_per_cubic_yard = NamedUnit(787666273664.0442, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_yard', ascii_symbol='pmol yrd^-3', symbol='pmolyrd⁻³') +femtomoles_per_cubic_yard = NamedUnit(787666273.6640443, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_yard', ascii_symbol='fmol yrd^-3', symbol='fmolyrd⁻³') +attomoles_per_cubic_yard = NamedUnit(787666.2736640442, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_yard', ascii_symbol='amol yrd^-3', symbol='amolyrd⁻³') +moles_per_cubic_foot = NamedUnit(2.1266989388929195e+25, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_foot', ascii_symbol='mol ft^-3', symbol='molft⁻³') +millimoles_per_cubic_foot = NamedUnit(2.1266989388929197e+22, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_foot', ascii_symbol='mmol ft^-3', symbol='mmolft⁻³') +micromoles_per_cubic_foot = NamedUnit(2.1266989388929196e+19, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_foot', ascii_symbol='umol ft^-3', symbol='µmolft⁻³') +nanomoles_per_cubic_foot = NamedUnit(2.1266989388929196e+16, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_foot', ascii_symbol='nmol ft^-3', symbol='nmolft⁻³') +picomoles_per_cubic_foot = NamedUnit(21266989388929.2, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_foot', ascii_symbol='pmol ft^-3', symbol='pmolft⁻³') +femtomoles_per_cubic_foot = NamedUnit(21266989388.9292, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_foot', ascii_symbol='fmol ft^-3', symbol='fmolft⁻³') +attomoles_per_cubic_foot = NamedUnit(21266989.388929196, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_foot', ascii_symbol='amol ft^-3', symbol='amolft⁻³') +moles_per_cubic_inch = NamedUnit(3.6749357664069658e+28, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_inch', ascii_symbol='mol in^-3', symbol='molin⁻³') +millimoles_per_cubic_inch = NamedUnit(3.674935766406966e+25, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_inch', ascii_symbol='mmol in^-3', symbol='mmolin⁻³') +micromoles_per_cubic_inch = NamedUnit(3.674935766406966e+22, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_inch', ascii_symbol='umol in^-3', symbol='µmolin⁻³') +nanomoles_per_cubic_inch = NamedUnit(3.674935766406966e+19, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_inch', ascii_symbol='nmol in^-3', symbol='nmolin⁻³') +picomoles_per_cubic_inch = NamedUnit(3.674935766406966e+16, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_inch', ascii_symbol='pmol in^-3', symbol='pmolin⁻³') +femtomoles_per_cubic_inch = NamedUnit(36749357664069.664, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_inch', ascii_symbol='fmol in^-3', symbol='fmolin⁻³') +attomoles_per_cubic_inch = NamedUnit(36749357664.069664, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_inch', ascii_symbol='amol in^-3', symbol='amolin⁻³') + +# +# Lookup table from symbols to units +# + +symbol_lookup = { + "m": meters, + "Em": exameters, + "Pm": petameters, + "Tm": terameters, + "Gm": gigameters, + "Mm": megameters, + "km": kilometers, + "mm": millimeters, + "um": micrometers, + "µm": micrometers, + "nm": nanometers, + "pm": picometers, + "fm": femtometers, + "am": attometers, + "dm": decimeters, + "cm": centimeters, + "s": seconds, + "ms": milliseconds, + "us": microseconds, + "µs": microseconds, + "ns": nanoseconds, + "ps": picoseconds, + "fs": femtoseconds, + "as": attoseconds, + "g": grams, + "Eg": exagrams, + "Pg": petagrams, + "Tg": teragrams, + "Gg": gigagrams, + "Mg": megagrams, + "kg": kilograms, + "mg": milligrams, + "ug": micrograms, + "µg": micrograms, + "ng": nanograms, + "pg": picograms, + "fg": femtograms, + "ag": attograms, + "A": angstroms, + "EA": exaamperes, + "PA": petaamperes, + "TA": teraamperes, + "GA": gigaamperes, + "MA": megaamperes, + "kA": kiloamperes, + "mA": milliamperes, + "uA": microamperes, + "µA": microamperes, + "nA": nanoamperes, + "pA": picoamperes, + "fA": femtoamperes, + "aA": attoamperes, + "K": kelvin, + "EK": exakelvin, + "PK": petakelvin, + "TK": terakelvin, + "GK": gigakelvin, + "MK": megakelvin, + "kK": kilokelvin, + "mK": millikelvin, + "uK": microkelvin, + "µK": microkelvin, + "nK": nanokelvin, + "pK": picokelvin, + "fK": femtokelvin, + "aK": attokelvin, + "Hz": hertz, + "EHz": exahertz, + "PHz": petahertz, + "THz": terahertz, + "GHz": gigahertz, + "MHz": megahertz, + "kHz": kilohertz, + "mHz": millihertz, + "uHz": microhertz, + "µHz": microhertz, + "nHz": nanohertz, + "pHz": picohertz, + "fHz": femtohertz, + "aHz": attohertz, + "N": newtons, + "EN": exanewtons, + "PN": petanewtons, + "TN": teranewtons, + "GN": giganewtons, + "MN": meganewtons, + "kN": kilonewtons, + "mN": millinewtons, + "uN": micronewtons, + "µN": micronewtons, + "nN": nanonewtons, + "pN": piconewtons, + "fN": femtonewtons, + "aN": attonewtons, + "Pa": pascals, + "EPa": exapascals, + "PPa": petapascals, + "TPa": terapascals, + "GPa": gigapascals, + "MPa": megapascals, + "kPa": kilopascals, + "mPa": millipascals, + "uPa": micropascals, + "µPa": micropascals, + "nPa": nanopascals, + "pPa": picopascals, + "fPa": femtopascals, + "aPa": attopascals, + "J": joules, + "EJ": exajoules, + "PJ": petajoules, + "TJ": terajoules, + "GJ": gigajoules, + "MJ": megajoules, + "kJ": kilojoules, + "mJ": millijoules, + "uJ": microjoules, + "µJ": microjoules, + "nJ": nanojoules, + "pJ": picojoules, + "fJ": femtojoules, + "aJ": attojoules, + "W": watts, + "EW": exawatts, + "PW": petawatts, + "TW": terawatts, + "GW": gigawatts, + "MW": megawatts, + "kW": kilowatts, + "mW": milliwatts, + "uW": microwatts, + "µW": microwatts, + "nW": nanowatts, + "pW": picowatts, + "fW": femtowatts, + "aW": attowatts, + "C": kelvin, + "EC": exacoulombs, + "PC": petacoulombs, + "TC": teracoulombs, + "GC": gigacoulombs, + "MC": megacoulombs, + "kC": kilocoulombs, + "mC": millicoulombs, + "uC": microcoulombs, + "µC": microcoulombs, + "nC": nanocoulombs, + "pC": picocoulombs, + "fC": femtocoulombs, + "aC": attocoulombs, + "V": volts, + "EV": exavolts, + "PV": petavolts, + "TV": teravolts, + "GV": gigavolts, + "MV": megavolts, + "kV": kilovolts, + "mV": millivolts, + "uV": microvolts, + "µV": microvolts, + "nV": nanovolts, + "pV": picovolts, + "fV": femtovolts, + "aV": attovolts, + "Ohm": ohms, + "Ω": ohms, + "EOhm": exaohms, + "EΩ": exaohms, + "POhm": petaohms, + "PΩ": petaohms, + "TOhm": teraohms, + "TΩ": teraohms, + "GOhm": gigaohms, + "GΩ": gigaohms, + "MOhm": megaohms, + "MΩ": megaohms, + "kOhm": kiloohms, + "kΩ": kiloohms, + "mOhm": milliohms, + "mΩ": milliohms, + "uOhm": microohms, + "µΩ": microohms, + "nOhm": nanoohms, + "nΩ": nanoohms, + "pOhm": picoohms, + "pΩ": picoohms, + "fOhm": femtoohms, + "fΩ": femtoohms, + "aOhm": attoohms, + "aΩ": attoohms, + "F": farads, + "EF": exafarads, + "PF": petafarads, + "TF": terafarads, + "GF": gigafarads, + "MF": megafarads, + "kF": kilofarads, + "mF": millifarads, + "uF": microfarads, + "µF": microfarads, + "nF": nanofarads, + "pF": picofarads, + "fF": femtofarads, + "aF": attofarads, + "S": siemens, + "ES": exasiemens, + "PS": petasiemens, + "TS": terasiemens, + "GS": gigasiemens, + "MS": megasiemens, + "kS": kilosiemens, + "mS": millisiemens, + "uS": microsiemens, + "µS": microsiemens, + "nS": nanosiemens, + "pS": picosiemens, + "fS": femtosiemens, + "aS": attosiemens, + "Wb": webers, + "EWb": exawebers, + "PWb": petawebers, + "TWb": terawebers, + "GWb": gigawebers, + "MWb": megawebers, + "kWb": kilowebers, + "mWb": milliwebers, + "uWb": microwebers, + "µWb": microwebers, + "nWb": nanowebers, + "pWb": picowebers, + "fWb": femtowebers, + "aWb": attowebers, + "T": tesla, + "ET": exatesla, + "PT": petatesla, + "TT": teratesla, + "GT": gigatesla, + "MT": megatesla, + "kT": kilotesla, + "mT": millitesla, + "uT": microtesla, + "µT": microtesla, + "nT": nanotesla, + "pT": picotesla, + "fT": femtotesla, + "aT": attotesla, + "H": henry, + "EH": exahenry, + "PH": petahenry, + "TH": terahenry, + "GH": gigahenry, + "MH": megahenry, + "kH": kilohenry, + "mH": millihenry, + "uH": microhenry, + "µH": microhenry, + "nH": nanohenry, + "pH": picohenry, + "fH": femtohenry, + "aH": attohenry, + "Ang": angstroms, + "Å": angstroms, + "min": minutes, + "h": hours, + "d": days, + "y": years, + "deg": degrees, + "rad": radians, + "sr": stradians, + "l": litres, + "eV": electronvolts, + "EeV": exaelectronvolts, + "PeV": petaelectronvolts, + "TeV": teraelectronvolts, + "GeV": gigaelectronvolts, + "MeV": megaelectronvolts, + "keV": kiloelectronvolts, + "meV": millielectronvolts, + "ueV": microelectronvolts, + "µeV": microelectronvolts, + "neV": nanoelectronvolts, + "peV": picoelectronvolts, + "feV": femtoelectronvolts, + "aeV": attoelectronvolts, + "au": atomic_mass_units, + "mol": moles, + "mmol": millimoles, + "umol": micromoles, + "µmol": micromoles, + "nmol": nanomoles, + "pmol": picomoles, + "fmol": femtomoles, + "amol": attomoles, + "kgForce": kg_force, + "miles": miles, + "yrd": yards, + "ft": feet, + "in": inches, + "lb": pounds, + "lbf": pounds_force, + "oz": ounces, + "psi": pounds_force_per_square_inch, + "percent": percent, + "%": percent, + "Amps": amperes, + "amps": amperes, + "Coulombs": degrees_celsius, + "coulombs": degrees_celsius, + "yr": years, + "year": years, + "day": days, + "hr": hours, + "hour": hours, + "amu": atomic_mass_units, + "degr": degrees, + "Deg": degrees, + "degrees": degrees, + "Degrees": degrees, + "Counts": none, + "counts": none, + "cnts": none, + "Cnts": none, + "a.u.": none, + "fraction": none, + "Fraction": none, +} + + +# +# Units by type +# + + +length = UnitGroup( + name = 'length', + units = [ + meters, + exameters, + petameters, + terameters, + gigameters, + megameters, + kilometers, + millimeters, + micrometers, + nanometers, + picometers, + femtometers, + attometers, + decimeters, + centimeters, + angstroms, + miles, + yards, + feet, + inches, +]) + +area = UnitGroup( + name = 'area', + units = [ + square_meters, + square_exameters, + square_petameters, + square_terameters, + square_gigameters, + square_megameters, + square_kilometers, + square_millimeters, + square_micrometers, + square_nanometers, + square_picometers, + square_femtometers, + square_attometers, + square_decimeters, + square_centimeters, + square_angstroms, + square_miles, + square_yards, + square_feet, + square_inches, +]) + +volume = UnitGroup( + name = 'volume', + units = [ + litres, + cubic_meters, + cubic_exameters, + cubic_petameters, + cubic_terameters, + cubic_gigameters, + cubic_megameters, + cubic_kilometers, + cubic_millimeters, + cubic_micrometers, + cubic_nanometers, + cubic_picometers, + cubic_femtometers, + cubic_attometers, + cubic_decimeters, + cubic_centimeters, + cubic_angstroms, + cubic_miles, + cubic_yards, + cubic_feet, + cubic_inches, +]) + +inverse_length = UnitGroup( + name = 'inverse_length', + units = [ + per_meter, + per_exameter, + per_petameter, + per_terameter, + per_gigameter, + per_megameter, + per_kilometer, + per_millimeter, + per_micrometer, + per_nanometer, + per_picometer, + per_femtometer, + per_attometer, + per_decimeter, + per_centimeter, + per_angstrom, + per_mile, + per_yard, + per_foot, + per_inch, +]) + +inverse_area = UnitGroup( + name = 'inverse_area', + units = [ + per_square_meter, + per_square_exameter, + per_square_petameter, + per_square_terameter, + per_square_gigameter, + per_square_megameter, + per_square_kilometer, + per_square_millimeter, + per_square_micrometer, + per_square_nanometer, + per_square_picometer, + per_square_femtometer, + per_square_attometer, + per_square_decimeter, + per_square_centimeter, + per_square_angstrom, + per_square_mile, + per_square_yard, + per_square_foot, + per_square_inch, +]) + +inverse_volume = UnitGroup( + name = 'inverse_volume', + units = [ + per_cubic_meter, + per_cubic_exameter, + per_cubic_petameter, + per_cubic_terameter, + per_cubic_gigameter, + per_cubic_megameter, + per_cubic_kilometer, + per_cubic_millimeter, + per_cubic_micrometer, + per_cubic_nanometer, + per_cubic_picometer, + per_cubic_femtometer, + per_cubic_attometer, + per_cubic_decimeter, + per_cubic_centimeter, + per_cubic_angstrom, + per_cubic_mile, + per_cubic_yard, + per_cubic_foot, + per_cubic_inch, +]) + +time = UnitGroup( + name = 'time', + units = [ + seconds, + milliseconds, + microseconds, + nanoseconds, + picoseconds, + femtoseconds, + attoseconds, + minutes, + hours, + days, + years, +]) + +rate = UnitGroup( + name = 'rate', + units = [ + hertz, + exahertz, + petahertz, + terahertz, + gigahertz, + megahertz, + kilohertz, + millihertz, + microhertz, + nanohertz, + picohertz, + femtohertz, + attohertz, +]) + +speed = UnitGroup( + name = 'speed', + units = [ + meters_per_second, + meters_per_millisecond, + meters_per_microsecond, + meters_per_nanosecond, + meters_per_picosecond, + meters_per_femtosecond, + meters_per_attosecond, + meters_per_minute, + meters_per_hour, + meters_per_day, + meters_per_year, + exameters_per_second, + exameters_per_millisecond, + exameters_per_microsecond, + exameters_per_nanosecond, + exameters_per_picosecond, + exameters_per_femtosecond, + exameters_per_attosecond, + exameters_per_minute, + exameters_per_hour, + exameters_per_day, + exameters_per_year, + petameters_per_second, + petameters_per_millisecond, + petameters_per_microsecond, + petameters_per_nanosecond, + petameters_per_picosecond, + petameters_per_femtosecond, + petameters_per_attosecond, + petameters_per_minute, + petameters_per_hour, + petameters_per_day, + petameters_per_year, + terameters_per_second, + terameters_per_millisecond, + terameters_per_microsecond, + terameters_per_nanosecond, + terameters_per_picosecond, + terameters_per_femtosecond, + terameters_per_attosecond, + terameters_per_minute, + terameters_per_hour, + terameters_per_day, + terameters_per_year, + gigameters_per_second, + gigameters_per_millisecond, + gigameters_per_microsecond, + gigameters_per_nanosecond, + gigameters_per_picosecond, + gigameters_per_femtosecond, + gigameters_per_attosecond, + gigameters_per_minute, + gigameters_per_hour, + gigameters_per_day, + gigameters_per_year, + megameters_per_second, + megameters_per_millisecond, + megameters_per_microsecond, + megameters_per_nanosecond, + megameters_per_picosecond, + megameters_per_femtosecond, + megameters_per_attosecond, + megameters_per_minute, + megameters_per_hour, + megameters_per_day, + megameters_per_year, + kilometers_per_second, + kilometers_per_millisecond, + kilometers_per_microsecond, + kilometers_per_nanosecond, + kilometers_per_picosecond, + kilometers_per_femtosecond, + kilometers_per_attosecond, + kilometers_per_minute, + kilometers_per_hour, + kilometers_per_day, + kilometers_per_year, + millimeters_per_second, + millimeters_per_millisecond, + millimeters_per_microsecond, + millimeters_per_nanosecond, + millimeters_per_picosecond, + millimeters_per_femtosecond, + millimeters_per_attosecond, + millimeters_per_minute, + millimeters_per_hour, + millimeters_per_day, + millimeters_per_year, + micrometers_per_second, + micrometers_per_millisecond, + micrometers_per_microsecond, + micrometers_per_nanosecond, + micrometers_per_picosecond, + micrometers_per_femtosecond, + micrometers_per_attosecond, + micrometers_per_minute, + micrometers_per_hour, + micrometers_per_day, + micrometers_per_year, + nanometers_per_second, + nanometers_per_millisecond, + nanometers_per_microsecond, + nanometers_per_nanosecond, + nanometers_per_picosecond, + nanometers_per_femtosecond, + nanometers_per_attosecond, + nanometers_per_minute, + nanometers_per_hour, + nanometers_per_day, + nanometers_per_year, + picometers_per_second, + picometers_per_millisecond, + picometers_per_microsecond, + picometers_per_nanosecond, + picometers_per_picosecond, + picometers_per_femtosecond, + picometers_per_attosecond, + picometers_per_minute, + picometers_per_hour, + picometers_per_day, + picometers_per_year, + femtometers_per_second, + femtometers_per_millisecond, + femtometers_per_microsecond, + femtometers_per_nanosecond, + femtometers_per_picosecond, + femtometers_per_femtosecond, + femtometers_per_attosecond, + femtometers_per_minute, + femtometers_per_hour, + femtometers_per_day, + femtometers_per_year, + attometers_per_second, + attometers_per_millisecond, + attometers_per_microsecond, + attometers_per_nanosecond, + attometers_per_picosecond, + attometers_per_femtosecond, + attometers_per_attosecond, + attometers_per_minute, + attometers_per_hour, + attometers_per_day, + attometers_per_year, + decimeters_per_second, + decimeters_per_millisecond, + decimeters_per_microsecond, + decimeters_per_nanosecond, + decimeters_per_picosecond, + decimeters_per_femtosecond, + decimeters_per_attosecond, + decimeters_per_minute, + decimeters_per_hour, + decimeters_per_day, + decimeters_per_year, + centimeters_per_second, + centimeters_per_millisecond, + centimeters_per_microsecond, + centimeters_per_nanosecond, + centimeters_per_picosecond, + centimeters_per_femtosecond, + centimeters_per_attosecond, + centimeters_per_minute, + centimeters_per_hour, + centimeters_per_day, + centimeters_per_year, + angstroms_per_second, + angstroms_per_millisecond, + angstroms_per_microsecond, + angstroms_per_nanosecond, + angstroms_per_picosecond, + angstroms_per_femtosecond, + angstroms_per_attosecond, + angstroms_per_minute, + angstroms_per_hour, + angstroms_per_day, + angstroms_per_year, + miles_per_second, + miles_per_millisecond, + miles_per_microsecond, + miles_per_nanosecond, + miles_per_picosecond, + miles_per_femtosecond, + miles_per_attosecond, + miles_per_minute, + miles_per_hour, + miles_per_day, + miles_per_year, + yards_per_second, + yards_per_millisecond, + yards_per_microsecond, + yards_per_nanosecond, + yards_per_picosecond, + yards_per_femtosecond, + yards_per_attosecond, + yards_per_minute, + yards_per_hour, + yards_per_day, + yards_per_year, + feet_per_second, + feet_per_millisecond, + feet_per_microsecond, + feet_per_nanosecond, + feet_per_picosecond, + feet_per_femtosecond, + feet_per_attosecond, + feet_per_minute, + feet_per_hour, + feet_per_day, + feet_per_year, + inches_per_second, + inches_per_millisecond, + inches_per_microsecond, + inches_per_nanosecond, + inches_per_picosecond, + inches_per_femtosecond, + inches_per_attosecond, + inches_per_minute, + inches_per_hour, + inches_per_day, + inches_per_year, +]) + +acceleration = UnitGroup( + name = 'acceleration', + units = [ + meters_per_square_second, + meters_per_square_millisecond, + meters_per_square_microsecond, + meters_per_square_nanosecond, + meters_per_square_picosecond, + meters_per_square_femtosecond, + meters_per_square_attosecond, + meters_per_square_minute, + meters_per_square_hour, + meters_per_square_day, + meters_per_square_year, + exameters_per_square_second, + exameters_per_square_millisecond, + exameters_per_square_microsecond, + exameters_per_square_nanosecond, + exameters_per_square_picosecond, + exameters_per_square_femtosecond, + exameters_per_square_attosecond, + exameters_per_square_minute, + exameters_per_square_hour, + exameters_per_square_day, + exameters_per_square_year, + petameters_per_square_second, + petameters_per_square_millisecond, + petameters_per_square_microsecond, + petameters_per_square_nanosecond, + petameters_per_square_picosecond, + petameters_per_square_femtosecond, + petameters_per_square_attosecond, + petameters_per_square_minute, + petameters_per_square_hour, + petameters_per_square_day, + petameters_per_square_year, + terameters_per_square_second, + terameters_per_square_millisecond, + terameters_per_square_microsecond, + terameters_per_square_nanosecond, + terameters_per_square_picosecond, + terameters_per_square_femtosecond, + terameters_per_square_attosecond, + terameters_per_square_minute, + terameters_per_square_hour, + terameters_per_square_day, + terameters_per_square_year, + gigameters_per_square_second, + gigameters_per_square_millisecond, + gigameters_per_square_microsecond, + gigameters_per_square_nanosecond, + gigameters_per_square_picosecond, + gigameters_per_square_femtosecond, + gigameters_per_square_attosecond, + gigameters_per_square_minute, + gigameters_per_square_hour, + gigameters_per_square_day, + gigameters_per_square_year, + megameters_per_square_second, + megameters_per_square_millisecond, + megameters_per_square_microsecond, + megameters_per_square_nanosecond, + megameters_per_square_picosecond, + megameters_per_square_femtosecond, + megameters_per_square_attosecond, + megameters_per_square_minute, + megameters_per_square_hour, + megameters_per_square_day, + megameters_per_square_year, + kilometers_per_square_second, + kilometers_per_square_millisecond, + kilometers_per_square_microsecond, + kilometers_per_square_nanosecond, + kilometers_per_square_picosecond, + kilometers_per_square_femtosecond, + kilometers_per_square_attosecond, + kilometers_per_square_minute, + kilometers_per_square_hour, + kilometers_per_square_day, + kilometers_per_square_year, + millimeters_per_square_second, + millimeters_per_square_millisecond, + millimeters_per_square_microsecond, + millimeters_per_square_nanosecond, + millimeters_per_square_picosecond, + millimeters_per_square_femtosecond, + millimeters_per_square_attosecond, + millimeters_per_square_minute, + millimeters_per_square_hour, + millimeters_per_square_day, + millimeters_per_square_year, + micrometers_per_square_second, + micrometers_per_square_millisecond, + micrometers_per_square_microsecond, + micrometers_per_square_nanosecond, + micrometers_per_square_picosecond, + micrometers_per_square_femtosecond, + micrometers_per_square_attosecond, + micrometers_per_square_minute, + micrometers_per_square_hour, + micrometers_per_square_day, + micrometers_per_square_year, + nanometers_per_square_second, + nanometers_per_square_millisecond, + nanometers_per_square_microsecond, + nanometers_per_square_nanosecond, + nanometers_per_square_picosecond, + nanometers_per_square_femtosecond, + nanometers_per_square_attosecond, + nanometers_per_square_minute, + nanometers_per_square_hour, + nanometers_per_square_day, + nanometers_per_square_year, + picometers_per_square_second, + picometers_per_square_millisecond, + picometers_per_square_microsecond, + picometers_per_square_nanosecond, + picometers_per_square_picosecond, + picometers_per_square_femtosecond, + picometers_per_square_attosecond, + picometers_per_square_minute, + picometers_per_square_hour, + picometers_per_square_day, + picometers_per_square_year, + femtometers_per_square_second, + femtometers_per_square_millisecond, + femtometers_per_square_microsecond, + femtometers_per_square_nanosecond, + femtometers_per_square_picosecond, + femtometers_per_square_femtosecond, + femtometers_per_square_attosecond, + femtometers_per_square_minute, + femtometers_per_square_hour, + femtometers_per_square_day, + femtometers_per_square_year, + attometers_per_square_second, + attometers_per_square_millisecond, + attometers_per_square_microsecond, + attometers_per_square_nanosecond, + attometers_per_square_picosecond, + attometers_per_square_femtosecond, + attometers_per_square_attosecond, + attometers_per_square_minute, + attometers_per_square_hour, + attometers_per_square_day, + attometers_per_square_year, + decimeters_per_square_second, + decimeters_per_square_millisecond, + decimeters_per_square_microsecond, + decimeters_per_square_nanosecond, + decimeters_per_square_picosecond, + decimeters_per_square_femtosecond, + decimeters_per_square_attosecond, + decimeters_per_square_minute, + decimeters_per_square_hour, + decimeters_per_square_day, + decimeters_per_square_year, + centimeters_per_square_second, + centimeters_per_square_millisecond, + centimeters_per_square_microsecond, + centimeters_per_square_nanosecond, + centimeters_per_square_picosecond, + centimeters_per_square_femtosecond, + centimeters_per_square_attosecond, + centimeters_per_square_minute, + centimeters_per_square_hour, + centimeters_per_square_day, + centimeters_per_square_year, + angstroms_per_square_second, + angstroms_per_square_millisecond, + angstroms_per_square_microsecond, + angstroms_per_square_nanosecond, + angstroms_per_square_picosecond, + angstroms_per_square_femtosecond, + angstroms_per_square_attosecond, + angstroms_per_square_minute, + angstroms_per_square_hour, + angstroms_per_square_day, + angstroms_per_square_year, + miles_per_square_second, + miles_per_square_millisecond, + miles_per_square_microsecond, + miles_per_square_nanosecond, + miles_per_square_picosecond, + miles_per_square_femtosecond, + miles_per_square_attosecond, + miles_per_square_minute, + miles_per_square_hour, + miles_per_square_day, + miles_per_square_year, + yards_per_square_second, + yards_per_square_millisecond, + yards_per_square_microsecond, + yards_per_square_nanosecond, + yards_per_square_picosecond, + yards_per_square_femtosecond, + yards_per_square_attosecond, + yards_per_square_minute, + yards_per_square_hour, + yards_per_square_day, + yards_per_square_year, + feet_per_square_second, + feet_per_square_millisecond, + feet_per_square_microsecond, + feet_per_square_nanosecond, + feet_per_square_picosecond, + feet_per_square_femtosecond, + feet_per_square_attosecond, + feet_per_square_minute, + feet_per_square_hour, + feet_per_square_day, + feet_per_square_year, + inches_per_square_second, + inches_per_square_millisecond, + inches_per_square_microsecond, + inches_per_square_nanosecond, + inches_per_square_picosecond, + inches_per_square_femtosecond, + inches_per_square_attosecond, + inches_per_square_minute, + inches_per_square_hour, + inches_per_square_day, + inches_per_square_year, +]) + +density = UnitGroup( + name = 'density', + units = [ + grams_per_cubic_meter, + exagrams_per_cubic_meter, + petagrams_per_cubic_meter, + teragrams_per_cubic_meter, + gigagrams_per_cubic_meter, + megagrams_per_cubic_meter, + kilograms_per_cubic_meter, + milligrams_per_cubic_meter, + micrograms_per_cubic_meter, + nanograms_per_cubic_meter, + picograms_per_cubic_meter, + femtograms_per_cubic_meter, + attograms_per_cubic_meter, + atomic_mass_units_per_cubic_meter, + pounds_per_cubic_meter, + ounces_per_cubic_meter, + grams_per_cubic_exameter, + exagrams_per_cubic_exameter, + petagrams_per_cubic_exameter, + teragrams_per_cubic_exameter, + gigagrams_per_cubic_exameter, + megagrams_per_cubic_exameter, + kilograms_per_cubic_exameter, + milligrams_per_cubic_exameter, + micrograms_per_cubic_exameter, + nanograms_per_cubic_exameter, + picograms_per_cubic_exameter, + femtograms_per_cubic_exameter, + attograms_per_cubic_exameter, + atomic_mass_units_per_cubic_exameter, + pounds_per_cubic_exameter, + ounces_per_cubic_exameter, + grams_per_cubic_petameter, + exagrams_per_cubic_petameter, + petagrams_per_cubic_petameter, + teragrams_per_cubic_petameter, + gigagrams_per_cubic_petameter, + megagrams_per_cubic_petameter, + kilograms_per_cubic_petameter, + milligrams_per_cubic_petameter, + micrograms_per_cubic_petameter, + nanograms_per_cubic_petameter, + picograms_per_cubic_petameter, + femtograms_per_cubic_petameter, + attograms_per_cubic_petameter, + atomic_mass_units_per_cubic_petameter, + pounds_per_cubic_petameter, + ounces_per_cubic_petameter, + grams_per_cubic_terameter, + exagrams_per_cubic_terameter, + petagrams_per_cubic_terameter, + teragrams_per_cubic_terameter, + gigagrams_per_cubic_terameter, + megagrams_per_cubic_terameter, + kilograms_per_cubic_terameter, + milligrams_per_cubic_terameter, + micrograms_per_cubic_terameter, + nanograms_per_cubic_terameter, + picograms_per_cubic_terameter, + femtograms_per_cubic_terameter, + attograms_per_cubic_terameter, + atomic_mass_units_per_cubic_terameter, + pounds_per_cubic_terameter, + ounces_per_cubic_terameter, + grams_per_cubic_gigameter, + exagrams_per_cubic_gigameter, + petagrams_per_cubic_gigameter, + teragrams_per_cubic_gigameter, + gigagrams_per_cubic_gigameter, + megagrams_per_cubic_gigameter, + kilograms_per_cubic_gigameter, + milligrams_per_cubic_gigameter, + micrograms_per_cubic_gigameter, + nanograms_per_cubic_gigameter, + picograms_per_cubic_gigameter, + femtograms_per_cubic_gigameter, + attograms_per_cubic_gigameter, + atomic_mass_units_per_cubic_gigameter, + pounds_per_cubic_gigameter, + ounces_per_cubic_gigameter, + grams_per_cubic_megameter, + exagrams_per_cubic_megameter, + petagrams_per_cubic_megameter, + teragrams_per_cubic_megameter, + gigagrams_per_cubic_megameter, + megagrams_per_cubic_megameter, + kilograms_per_cubic_megameter, + milligrams_per_cubic_megameter, + micrograms_per_cubic_megameter, + nanograms_per_cubic_megameter, + picograms_per_cubic_megameter, + femtograms_per_cubic_megameter, + attograms_per_cubic_megameter, + atomic_mass_units_per_cubic_megameter, + pounds_per_cubic_megameter, + ounces_per_cubic_megameter, + grams_per_cubic_kilometer, + exagrams_per_cubic_kilometer, + petagrams_per_cubic_kilometer, + teragrams_per_cubic_kilometer, + gigagrams_per_cubic_kilometer, + megagrams_per_cubic_kilometer, + kilograms_per_cubic_kilometer, + milligrams_per_cubic_kilometer, + micrograms_per_cubic_kilometer, + nanograms_per_cubic_kilometer, + picograms_per_cubic_kilometer, + femtograms_per_cubic_kilometer, + attograms_per_cubic_kilometer, + atomic_mass_units_per_cubic_kilometer, + pounds_per_cubic_kilometer, + ounces_per_cubic_kilometer, + grams_per_cubic_millimeter, + exagrams_per_cubic_millimeter, + petagrams_per_cubic_millimeter, + teragrams_per_cubic_millimeter, + gigagrams_per_cubic_millimeter, + megagrams_per_cubic_millimeter, + kilograms_per_cubic_millimeter, + milligrams_per_cubic_millimeter, + micrograms_per_cubic_millimeter, + nanograms_per_cubic_millimeter, + picograms_per_cubic_millimeter, + femtograms_per_cubic_millimeter, + attograms_per_cubic_millimeter, + atomic_mass_units_per_cubic_millimeter, + pounds_per_cubic_millimeter, + ounces_per_cubic_millimeter, + grams_per_cubic_micrometer, + exagrams_per_cubic_micrometer, + petagrams_per_cubic_micrometer, + teragrams_per_cubic_micrometer, + gigagrams_per_cubic_micrometer, + megagrams_per_cubic_micrometer, + kilograms_per_cubic_micrometer, + milligrams_per_cubic_micrometer, + micrograms_per_cubic_micrometer, + nanograms_per_cubic_micrometer, + picograms_per_cubic_micrometer, + femtograms_per_cubic_micrometer, + attograms_per_cubic_micrometer, + atomic_mass_units_per_cubic_micrometer, + pounds_per_cubic_micrometer, + ounces_per_cubic_micrometer, + grams_per_cubic_nanometer, + exagrams_per_cubic_nanometer, + petagrams_per_cubic_nanometer, + teragrams_per_cubic_nanometer, + gigagrams_per_cubic_nanometer, + megagrams_per_cubic_nanometer, + kilograms_per_cubic_nanometer, + milligrams_per_cubic_nanometer, + micrograms_per_cubic_nanometer, + nanograms_per_cubic_nanometer, + picograms_per_cubic_nanometer, + femtograms_per_cubic_nanometer, + attograms_per_cubic_nanometer, + atomic_mass_units_per_cubic_nanometer, + pounds_per_cubic_nanometer, + ounces_per_cubic_nanometer, + grams_per_cubic_picometer, + exagrams_per_cubic_picometer, + petagrams_per_cubic_picometer, + teragrams_per_cubic_picometer, + gigagrams_per_cubic_picometer, + megagrams_per_cubic_picometer, + kilograms_per_cubic_picometer, + milligrams_per_cubic_picometer, + micrograms_per_cubic_picometer, + nanograms_per_cubic_picometer, + picograms_per_cubic_picometer, + femtograms_per_cubic_picometer, + attograms_per_cubic_picometer, + atomic_mass_units_per_cubic_picometer, + pounds_per_cubic_picometer, + ounces_per_cubic_picometer, + grams_per_cubic_femtometer, + exagrams_per_cubic_femtometer, + petagrams_per_cubic_femtometer, + teragrams_per_cubic_femtometer, + gigagrams_per_cubic_femtometer, + megagrams_per_cubic_femtometer, + kilograms_per_cubic_femtometer, + milligrams_per_cubic_femtometer, + micrograms_per_cubic_femtometer, + nanograms_per_cubic_femtometer, + picograms_per_cubic_femtometer, + femtograms_per_cubic_femtometer, + attograms_per_cubic_femtometer, + atomic_mass_units_per_cubic_femtometer, + pounds_per_cubic_femtometer, + ounces_per_cubic_femtometer, + grams_per_cubic_attometer, + exagrams_per_cubic_attometer, + petagrams_per_cubic_attometer, + teragrams_per_cubic_attometer, + gigagrams_per_cubic_attometer, + megagrams_per_cubic_attometer, + kilograms_per_cubic_attometer, + milligrams_per_cubic_attometer, + micrograms_per_cubic_attometer, + nanograms_per_cubic_attometer, + picograms_per_cubic_attometer, + femtograms_per_cubic_attometer, + attograms_per_cubic_attometer, + atomic_mass_units_per_cubic_attometer, + pounds_per_cubic_attometer, + ounces_per_cubic_attometer, + grams_per_cubic_decimeter, + exagrams_per_cubic_decimeter, + petagrams_per_cubic_decimeter, + teragrams_per_cubic_decimeter, + gigagrams_per_cubic_decimeter, + megagrams_per_cubic_decimeter, + kilograms_per_cubic_decimeter, + milligrams_per_cubic_decimeter, + micrograms_per_cubic_decimeter, + nanograms_per_cubic_decimeter, + picograms_per_cubic_decimeter, + femtograms_per_cubic_decimeter, + attograms_per_cubic_decimeter, + atomic_mass_units_per_cubic_decimeter, + pounds_per_cubic_decimeter, + ounces_per_cubic_decimeter, + grams_per_cubic_centimeter, + exagrams_per_cubic_centimeter, + petagrams_per_cubic_centimeter, + teragrams_per_cubic_centimeter, + gigagrams_per_cubic_centimeter, + megagrams_per_cubic_centimeter, + kilograms_per_cubic_centimeter, + milligrams_per_cubic_centimeter, + micrograms_per_cubic_centimeter, + nanograms_per_cubic_centimeter, + picograms_per_cubic_centimeter, + femtograms_per_cubic_centimeter, + attograms_per_cubic_centimeter, + atomic_mass_units_per_cubic_centimeter, + pounds_per_cubic_centimeter, + ounces_per_cubic_centimeter, + grams_per_cubic_angstrom, + exagrams_per_cubic_angstrom, + petagrams_per_cubic_angstrom, + teragrams_per_cubic_angstrom, + gigagrams_per_cubic_angstrom, + megagrams_per_cubic_angstrom, + kilograms_per_cubic_angstrom, + milligrams_per_cubic_angstrom, + micrograms_per_cubic_angstrom, + nanograms_per_cubic_angstrom, + picograms_per_cubic_angstrom, + femtograms_per_cubic_angstrom, + attograms_per_cubic_angstrom, + atomic_mass_units_per_cubic_angstrom, + pounds_per_cubic_angstrom, + ounces_per_cubic_angstrom, + grams_per_cubic_mile, + exagrams_per_cubic_mile, + petagrams_per_cubic_mile, + teragrams_per_cubic_mile, + gigagrams_per_cubic_mile, + megagrams_per_cubic_mile, + kilograms_per_cubic_mile, + milligrams_per_cubic_mile, + micrograms_per_cubic_mile, + nanograms_per_cubic_mile, + picograms_per_cubic_mile, + femtograms_per_cubic_mile, + attograms_per_cubic_mile, + atomic_mass_units_per_cubic_mile, + pounds_per_cubic_mile, + ounces_per_cubic_mile, + grams_per_cubic_yard, + exagrams_per_cubic_yard, + petagrams_per_cubic_yard, + teragrams_per_cubic_yard, + gigagrams_per_cubic_yard, + megagrams_per_cubic_yard, + kilograms_per_cubic_yard, + milligrams_per_cubic_yard, + micrograms_per_cubic_yard, + nanograms_per_cubic_yard, + picograms_per_cubic_yard, + femtograms_per_cubic_yard, + attograms_per_cubic_yard, + atomic_mass_units_per_cubic_yard, + pounds_per_cubic_yard, + ounces_per_cubic_yard, + grams_per_cubic_foot, + exagrams_per_cubic_foot, + petagrams_per_cubic_foot, + teragrams_per_cubic_foot, + gigagrams_per_cubic_foot, + megagrams_per_cubic_foot, + kilograms_per_cubic_foot, + milligrams_per_cubic_foot, + micrograms_per_cubic_foot, + nanograms_per_cubic_foot, + picograms_per_cubic_foot, + femtograms_per_cubic_foot, + attograms_per_cubic_foot, + atomic_mass_units_per_cubic_foot, + pounds_per_cubic_foot, + ounces_per_cubic_foot, + grams_per_cubic_inch, + exagrams_per_cubic_inch, + petagrams_per_cubic_inch, + teragrams_per_cubic_inch, + gigagrams_per_cubic_inch, + megagrams_per_cubic_inch, + kilograms_per_cubic_inch, + milligrams_per_cubic_inch, + micrograms_per_cubic_inch, + nanograms_per_cubic_inch, + picograms_per_cubic_inch, + femtograms_per_cubic_inch, + attograms_per_cubic_inch, + atomic_mass_units_per_cubic_inch, + pounds_per_cubic_inch, + ounces_per_cubic_inch, +]) + +force = UnitGroup( + name = 'force', + units = [ + newtons, + exanewtons, + petanewtons, + teranewtons, + giganewtons, + meganewtons, + kilonewtons, + millinewtons, + micronewtons, + nanonewtons, + piconewtons, + femtonewtons, + attonewtons, + kg_force, + pounds_force, +]) + +pressure = UnitGroup( + name = 'pressure', + units = [ + pascals, + exapascals, + petapascals, + terapascals, + gigapascals, + megapascals, + kilopascals, + millipascals, + micropascals, + nanopascals, + picopascals, + femtopascals, + attopascals, + pounds_force_per_square_inch, +]) + +energy = UnitGroup( + name = 'energy', + units = [ + joules, + exajoules, + petajoules, + terajoules, + gigajoules, + megajoules, + kilojoules, + millijoules, + microjoules, + nanojoules, + picojoules, + femtojoules, + attojoules, + electronvolts, + exaelectronvolts, + petaelectronvolts, + teraelectronvolts, + gigaelectronvolts, + megaelectronvolts, + kiloelectronvolts, + millielectronvolts, + microelectronvolts, + nanoelectronvolts, + picoelectronvolts, + femtoelectronvolts, + attoelectronvolts, +]) + +power = UnitGroup( + name = 'power', + units = [ + watts, + exawatts, + petawatts, + terawatts, + gigawatts, + megawatts, + kilowatts, + milliwatts, + microwatts, + nanowatts, + picowatts, + femtowatts, + attowatts, +]) + +charge = UnitGroup( + name = 'charge', + units = [ + coulombs, + exacoulombs, + petacoulombs, + teracoulombs, + gigacoulombs, + megacoulombs, + kilocoulombs, + millicoulombs, + microcoulombs, + nanocoulombs, + picocoulombs, + femtocoulombs, + attocoulombs, +]) + +potential = UnitGroup( + name = 'potential', + units = [ + volts, + exavolts, + petavolts, + teravolts, + gigavolts, + megavolts, + kilovolts, + millivolts, + microvolts, + nanovolts, + picovolts, + femtovolts, + attovolts, +]) + +resistance = UnitGroup( + name = 'resistance', + units = [ + ohms, + exaohms, + petaohms, + teraohms, + gigaohms, + megaohms, + kiloohms, + milliohms, + microohms, + nanoohms, + picoohms, + femtoohms, + attoohms, +]) + +capacitance = UnitGroup( + name = 'capacitance', + units = [ + farads, + exafarads, + petafarads, + terafarads, + gigafarads, + megafarads, + kilofarads, + millifarads, + microfarads, + nanofarads, + picofarads, + femtofarads, + attofarads, +]) + +conductance = UnitGroup( + name = 'conductance', + units = [ + siemens, + exasiemens, + petasiemens, + terasiemens, + gigasiemens, + megasiemens, + kilosiemens, + millisiemens, + microsiemens, + nanosiemens, + picosiemens, + femtosiemens, + attosiemens, +]) + +magnetic_flux = UnitGroup( + name = 'magnetic_flux', + units = [ + webers, + exawebers, + petawebers, + terawebers, + gigawebers, + megawebers, + kilowebers, + milliwebers, + microwebers, + nanowebers, + picowebers, + femtowebers, + attowebers, +]) + +magnetic_flux_density = UnitGroup( + name = 'magnetic_flux_density', + units = [ + tesla, + exatesla, + petatesla, + teratesla, + gigatesla, + megatesla, + kilotesla, + millitesla, + microtesla, + nanotesla, + picotesla, + femtotesla, + attotesla, +]) + +inductance = UnitGroup( + name = 'inductance', + units = [ + henry, + exahenry, + petahenry, + terahenry, + gigahenry, + megahenry, + kilohenry, + millihenry, + microhenry, + nanohenry, + picohenry, + femtohenry, + attohenry, +]) + +temperature = UnitGroup( + name = 'temperature', + units = [ + kelvin, + exakelvin, + petakelvin, + terakelvin, + gigakelvin, + megakelvin, + kilokelvin, + millikelvin, + microkelvin, + nanokelvin, + picokelvin, + femtokelvin, + attokelvin, + degrees_celsius, +]) + +dimensionless = UnitGroup( + name = 'dimensionless', + units = [ + none, + percent, +]) + +angle = UnitGroup( + name = 'angle', + units = [ + degrees, + radians, +]) + +solid_angle = UnitGroup( + name = 'solid_angle', + units = [ + stradians, +]) + +amount = UnitGroup( + name = 'amount', + units = [ + moles, + millimoles, + micromoles, + nanomoles, + picomoles, + femtomoles, + attomoles, +]) + +concentration = UnitGroup( + name = 'concentration', + units = [ + moles_per_cubic_meter, + millimoles_per_cubic_meter, + micromoles_per_cubic_meter, + nanomoles_per_cubic_meter, + picomoles_per_cubic_meter, + femtomoles_per_cubic_meter, + attomoles_per_cubic_meter, + moles_per_cubic_exameter, + millimoles_per_cubic_exameter, + micromoles_per_cubic_exameter, + nanomoles_per_cubic_exameter, + picomoles_per_cubic_exameter, + femtomoles_per_cubic_exameter, + attomoles_per_cubic_exameter, + moles_per_cubic_petameter, + millimoles_per_cubic_petameter, + micromoles_per_cubic_petameter, + nanomoles_per_cubic_petameter, + picomoles_per_cubic_petameter, + femtomoles_per_cubic_petameter, + attomoles_per_cubic_petameter, + moles_per_cubic_terameter, + millimoles_per_cubic_terameter, + micromoles_per_cubic_terameter, + nanomoles_per_cubic_terameter, + picomoles_per_cubic_terameter, + femtomoles_per_cubic_terameter, + attomoles_per_cubic_terameter, + moles_per_cubic_gigameter, + millimoles_per_cubic_gigameter, + micromoles_per_cubic_gigameter, + nanomoles_per_cubic_gigameter, + picomoles_per_cubic_gigameter, + femtomoles_per_cubic_gigameter, + attomoles_per_cubic_gigameter, + moles_per_cubic_megameter, + millimoles_per_cubic_megameter, + micromoles_per_cubic_megameter, + nanomoles_per_cubic_megameter, + picomoles_per_cubic_megameter, + femtomoles_per_cubic_megameter, + attomoles_per_cubic_megameter, + moles_per_cubic_kilometer, + millimoles_per_cubic_kilometer, + micromoles_per_cubic_kilometer, + nanomoles_per_cubic_kilometer, + picomoles_per_cubic_kilometer, + femtomoles_per_cubic_kilometer, + attomoles_per_cubic_kilometer, + moles_per_cubic_millimeter, + millimoles_per_cubic_millimeter, + micromoles_per_cubic_millimeter, + nanomoles_per_cubic_millimeter, + picomoles_per_cubic_millimeter, + femtomoles_per_cubic_millimeter, + attomoles_per_cubic_millimeter, + moles_per_cubic_micrometer, + millimoles_per_cubic_micrometer, + micromoles_per_cubic_micrometer, + nanomoles_per_cubic_micrometer, + picomoles_per_cubic_micrometer, + femtomoles_per_cubic_micrometer, + attomoles_per_cubic_micrometer, + moles_per_cubic_nanometer, + millimoles_per_cubic_nanometer, + micromoles_per_cubic_nanometer, + nanomoles_per_cubic_nanometer, + picomoles_per_cubic_nanometer, + femtomoles_per_cubic_nanometer, + attomoles_per_cubic_nanometer, + moles_per_cubic_picometer, + millimoles_per_cubic_picometer, + micromoles_per_cubic_picometer, + nanomoles_per_cubic_picometer, + picomoles_per_cubic_picometer, + femtomoles_per_cubic_picometer, + attomoles_per_cubic_picometer, + moles_per_cubic_femtometer, + millimoles_per_cubic_femtometer, + micromoles_per_cubic_femtometer, + nanomoles_per_cubic_femtometer, + picomoles_per_cubic_femtometer, + femtomoles_per_cubic_femtometer, + attomoles_per_cubic_femtometer, + moles_per_cubic_attometer, + millimoles_per_cubic_attometer, + micromoles_per_cubic_attometer, + nanomoles_per_cubic_attometer, + picomoles_per_cubic_attometer, + femtomoles_per_cubic_attometer, + attomoles_per_cubic_attometer, + moles_per_cubic_decimeter, + millimoles_per_cubic_decimeter, + micromoles_per_cubic_decimeter, + nanomoles_per_cubic_decimeter, + picomoles_per_cubic_decimeter, + femtomoles_per_cubic_decimeter, + attomoles_per_cubic_decimeter, + moles_per_cubic_centimeter, + millimoles_per_cubic_centimeter, + micromoles_per_cubic_centimeter, + nanomoles_per_cubic_centimeter, + picomoles_per_cubic_centimeter, + femtomoles_per_cubic_centimeter, + attomoles_per_cubic_centimeter, + moles_per_cubic_angstrom, + millimoles_per_cubic_angstrom, + micromoles_per_cubic_angstrom, + nanomoles_per_cubic_angstrom, + picomoles_per_cubic_angstrom, + femtomoles_per_cubic_angstrom, + attomoles_per_cubic_angstrom, + moles_per_cubic_mile, + millimoles_per_cubic_mile, + micromoles_per_cubic_mile, + nanomoles_per_cubic_mile, + picomoles_per_cubic_mile, + femtomoles_per_cubic_mile, + attomoles_per_cubic_mile, + moles_per_cubic_yard, + millimoles_per_cubic_yard, + micromoles_per_cubic_yard, + nanomoles_per_cubic_yard, + picomoles_per_cubic_yard, + femtomoles_per_cubic_yard, + attomoles_per_cubic_yard, + moles_per_cubic_foot, + millimoles_per_cubic_foot, + micromoles_per_cubic_foot, + nanomoles_per_cubic_foot, + picomoles_per_cubic_foot, + femtomoles_per_cubic_foot, + attomoles_per_cubic_foot, + moles_per_cubic_inch, + millimoles_per_cubic_inch, + micromoles_per_cubic_inch, + nanomoles_per_cubic_inch, + picomoles_per_cubic_inch, + femtomoles_per_cubic_inch, + attomoles_per_cubic_inch, +]) + + +unit_group_names = [ + 'length', + 'area', + 'volume', + 'inverse_length', + 'inverse_area', + 'inverse_volume', + 'time', + 'rate', + 'speed', + 'acceleration', + 'density', + 'force', + 'pressure', + 'energy', + 'power', + 'charge', + 'potential', + 'resistance', + 'capacitance', + 'conductance', + 'magnetic_flux', + 'magnetic_flux_density', + 'inductance', + 'temperature', + 'dimensionless', + 'angle', + 'solid_angle', + 'amount', + 'concentration', +] + +unit_groups = { + 'length': length, + 'area': area, + 'volume': volume, + 'inverse_length': inverse_length, + 'inverse_area': inverse_area, + 'inverse_volume': inverse_volume, + 'time': time, + 'rate': rate, + 'speed': speed, + 'acceleration': acceleration, + 'density': density, + 'force': force, + 'pressure': pressure, + 'energy': energy, + 'power': power, + 'charge': charge, + 'potential': potential, + 'resistance': resistance, + 'capacitance': capacitance, + 'conductance': conductance, + 'magnetic_flux': magnetic_flux, + 'magnetic_flux_density': magnetic_flux_density, + 'inductance': inductance, + 'temperature': temperature, + 'dimensionless': dimensionless, + 'angle': angle, + 'solid_angle': solid_angle, + 'amount': amount, + 'concentration': concentration, +} + diff --git a/sasdata/quantities/units_tests.py b/sasdata/quantities/units_tests.py new file mode 100644 index 0000000..9fea2a6 --- /dev/null +++ b/sasdata/quantities/units_tests.py @@ -0,0 +1,46 @@ +import sasdata.quantities.units as units +from sasdata.quantities.units import Unit + +class EqualUnits: + def __init__(self, test_name: str, *units): + self.test_name = "Equality: " + test_name + self.units: list[Unit] = list(units) + + def run_test(self): + for i, unit_1 in enumerate(self.units): + for unit_2 in self.units[i+1:]: + assert unit_1.equivalent(unit_2), "Units should be equivalent" + assert unit_1 == unit_2, "Units should be equal" + + +class EquivalentButUnequalUnits: + def __init__(self, test_name: str, *units): + self.test_name = "Equivalence: " + test_name + self.units: list[Unit] = list(units) + + def run_test(self): + for i, unit_1 in enumerate(self.units): + for unit_2 in self.units[i+1:]: + assert unit_1.equivalent(unit_2), "Units should be equivalent" + assert unit_1 != unit_2, "Units should not be equal" + + +tests = [ + + EqualUnits("Pressure", + units.pascals, + units.newtons / units.meters ** 2, + units.micronewtons * units.millimeters ** -2), + + EqualUnits("Resistance", + units.ohms, + units.volts / units.amperes, + 1e-3/units.millisiemens) + + +] + + +for test in tests: + print(test.test_name) + test.run_test() diff --git a/sasdata/slicing/__init__.py b/sasdata/slicing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/slicing/geometry.py b/sasdata/slicing/geometry.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/slicing/meshes/__init__.py b/sasdata/slicing/meshes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/slicing/meshes/delaunay_mesh.py b/sasdata/slicing/meshes/delaunay_mesh.py new file mode 100644 index 0000000..a19c2ac --- /dev/null +++ b/sasdata/slicing/meshes/delaunay_mesh.py @@ -0,0 +1,32 @@ +import numpy as np +from scipy.spatial import Delaunay + +from sasdata.slicing.meshes.mesh import Mesh + +def delaunay_mesh(x, y) -> Mesh: + """ Create a triangulated mesh based on input points """ + + input_data = np.array((x, y)).T + delaunay = Delaunay(input_data) + + return Mesh(points=input_data, cells=delaunay.simplices) + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + + points = np.random.random((100, 2)) + mesh = delaunay_mesh(points[:,0], points[:,1]) + mesh.show(actually_show=False) + + print(mesh.cells[50]) + + # pick random cell to show + for cell in mesh.cells_to_edges[10]: + a, b = mesh.edges[cell] + plt.plot( + [mesh.points[a][0], mesh.points[b][0]], + [mesh.points[a][1], mesh.points[b][1]], + color='r') + + plt.show() diff --git a/sasdata/slicing/meshes/mesh.py b/sasdata/slicing/meshes/mesh.py new file mode 100644 index 0000000..8176633 --- /dev/null +++ b/sasdata/slicing/meshes/mesh.py @@ -0,0 +1,242 @@ +from typing import Sequence + +import numpy as np + +import matplotlib.pyplot as plt +from matplotlib import cm +from matplotlib.collections import LineCollection + +from sasdata.slicing.meshes.util import closed_loop_edges + +class Mesh: + def __init__(self, + points: np.ndarray, + cells: Sequence[Sequence[int]]): + + """ + Object representing a mesh. + + Parameters are the values: + mesh points + map from edge to points + map from cells to edges + + it is done this way to ensure a non-redundant representation of cells and edges, + however there are no checks for the topology of the mesh, this is assumed to be done by + whatever creates it. There are also no checks for ordering of cells. + + :param points: points in 2D forming vertices of the mesh + :param cells: ordered lists of indices of points forming each cell (face) + + """ + + self.points = points + self.cells = cells + + # Get edges + + edges = set() + for cell_index, cell in enumerate(cells): + + for a, b in closed_loop_edges(cell): + # make sure the representation is unique + if a > b: + edges.add((a, b)) + else: + edges.add((b, a)) + + self.edges = list(edges) + + # Associate edges with faces + + edge_lookup = {edge: i for i, edge in enumerate(self.edges)} + self.cells_to_edges = [] + self.cells_to_edges_signs = [] + + for cell in cells: + + this_cell_data = [] + this_sign_data = [] + + for a, b in closed_loop_edges(cell): + # make sure the representation is unique + if a > b: + this_cell_data.append(edge_lookup[(a, b)]) + this_sign_data.append(1) + else: + this_cell_data.append(edge_lookup[(b, a)]) + this_sign_data.append(-1) + + self.cells_to_edges.append(this_cell_data) + self.cells_to_edges_signs.append(this_sign_data) + + # Counts for elements + self.n_points = self.points.shape[0] + self.n_edges = len(self.edges) + self.n_cells = len(self.cells) + + # Areas + self._areas = None + + + @property + def areas(self): + """ Areas of cells """ + + if self._areas is None: + # Calculate areas + areas = [] + for cell in self.cells: + # Use triangle shoelace formula, basically calculate the + # determinant based on of triangles with one point at 0,0 + a_times_2 = 0.0 + for i1, i2 in closed_loop_edges(cell): + p1 = self.points[i1, :] + p2 = self.points[i2, :] + a_times_2 += p1[0]*p2[1] - p1[1]*p2[0] + + areas.append(0.5*np.abs(a_times_2)) + + # Save in cache + self._areas = np.array(areas) + + # Return cache + return self._areas + + + def show(self, actually_show=True, show_labels=False, **kwargs): + """ Show on a plot """ + ax = plt.gca() + segments = [[self.points[edge[0]], self.points[edge[1]]] for edge in self.edges] + line_collection = LineCollection(segments=segments, **kwargs) + ax.add_collection(line_collection) + + if show_labels: + text_color = kwargs["color"] if "color" in kwargs else 'k' + for i, cell in enumerate(self.cells): + xy = np.sum(self.points[cell, :], axis=0)/len(cell) + ax.text(xy[0], xy[1], str(i), horizontalalignment="center", verticalalignment="center", color=text_color) + + x_limits = [np.min(self.points[:,0]), np.max(self.points[:,0])] + y_limits = [np.min(self.points[:,1]), np.max(self.points[:,1])] + + plt.xlim(x_limits) + plt.ylim(y_limits) + + if actually_show: + plt.show() + + def locate_points(self, x: np.ndarray, y: np.ndarray): + """ Find the cells that contain the specified points""" + + x = x.reshape(-1) + y = y.reshape(-1) + + xy = np.concatenate(([x], [y]), axis=1) + + # The most simple implementation is not particularly fast, especially in python + # + # Less obvious, but hopefully faster strategy + # + # Ultimately, checking the inclusion of a point within a polygon + # requires checking the crossings of a half line with the polygon's + # edges. + # + # A fairly efficient thing to do is to check every edge for crossing + # the axis parallel lines x=point_x. + # Then these edges that cross can map back to the polygons they're in + # and a final check for inclusion can be done with the edge sign property + # and some explicit checking of the + # + # Basic idea is: + # 1) build a matrix for each point-edge pair + # True if the edge crosses the half-line above a point + # 2) for each cell get the winding number by evaluating the + # sum of the component edges, weighted 1/-1 according to direction + + + edges = np.array(self.edges) + + edge_xy_1 = self.points[edges[:, 0], :] + edge_xy_2 = self.points[edges[:, 1], :] + + edge_x_1 = edge_xy_1[:, 0] + edge_x_2 = edge_xy_2[:, 0] + + + + # Make an n_edges-by-n_inputs boolean matrix that indicates which of the + # edges cross x=points_x line + crossers = np.logical_xor( + edge_x_1.reshape(-1, 1) < x.reshape(1, -1), + edge_x_2.reshape(-1, 1) < x.reshape(1, -1)) + + # Calculate the gradients, some might be infs, but none that matter will be + # TODO: Disable warnings + gradients = (edge_xy_2[:, 1] - edge_xy_1[:, 1]) / (edge_xy_2[:, 0] - edge_xy_1[:, 0]) + + # Distance to crossing points edge 0 + delta_x = x.reshape(1, -1) - edge_x_1.reshape(-1, 1) + + # Signed distance from point to y (doesn't really matter which sign) + delta_y = gradients.reshape(-1, 1) * delta_x + edge_xy_1[:, 1:] - y.reshape(1, -1) + + score_matrix = np.logical_and(delta_y > 0, crossers) + + output = -np.ones(len(x), dtype=int) + for cell_index, (cell_edges, sign) in enumerate(zip(self.cells_to_edges, self.cells_to_edges_signs)): + cell_score = np.sum(score_matrix[cell_edges, :] * np.array(sign).reshape(-1, 1), axis=0) + points_in_cell = np.abs(cell_score) == 1 + output[points_in_cell] = cell_index + + return output + + def show_data(self, + data: np.ndarray, + cmap='winter', + mesh_color='white', + show_mesh=False, + actually_show=True, + density=False): + + """ Show with data """ + + colormap = cm.get_cmap(cmap, 256) + + data = data.reshape(-1) + + if density: + data = data / self.areas + + cmin = np.min(data) + cmax = np.max(data) + + color_index_map = np.array(255 * (data - cmin) / (cmax - cmin), dtype=int) + + for cell, color_index in zip(self.cells, color_index_map): + + color = colormap(color_index) + + plt.fill(self.points[cell, 0], self.points[cell, 1], color=color, edgecolor=None) + + if show_mesh: + self.show(actually_show=False, color=mesh_color) + + if actually_show: + self.show() + + +if __name__ == "__main__": + from test.slicers.meshes_for_testing import location_test_mesh, location_test_points_x, location_test_points_y + + cell_indices = location_test_mesh.locate_points(location_test_points_x, location_test_points_y) + + print(cell_indices) + + for i in range(location_test_mesh.n_cells): + inds = cell_indices == i + plt.scatter( + location_test_points_x.reshape(-1)[inds], + location_test_points_y.reshape(-1)[inds]) + + location_test_mesh.show() \ No newline at end of file diff --git a/sasdata/slicing/meshes/meshmerge.py b/sasdata/slicing/meshes/meshmerge.py new file mode 100644 index 0000000..2060cc7 --- /dev/null +++ b/sasdata/slicing/meshes/meshmerge.py @@ -0,0 +1,154 @@ +import numpy as np + +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.meshes.delaunay_mesh import delaunay_mesh + +import time + +def meshmerge(mesh_a: Mesh, mesh_b: Mesh) -> tuple[Mesh, np.ndarray, np.ndarray]: + """ Take two lists of polygons and find their intersections + + Polygons in each of the input variables should not overlap i.e. a point in space should be assignable to + at most one polygon in mesh_a and at most one polygon in mesh_b + + Mesh topology should be sensible, otherwise bad things might happen, also, the cells of the input meshes + must be in order (which is assumed by the mesh class constructor anyway). + + :returns: + 1) A triangulated mesh based on both sets of polygons together + 2) The indices of the mesh_a polygon that corresponds to each triangle, -1 for nothing + 3) The indices of the mesh_b polygon that corresponds to each triangle, -1 for nothing + + """ + + t0 = time.time() + + # Find intersections of all edges in mesh one with edges in mesh two + + # Fastest way might just be to calculate the intersections of all lines on edges, + # see whether we need filtering afterwards + + edges_a = np.array(mesh_a.edges, dtype=int) + edges_b = np.array(mesh_b.edges, dtype=int) + + edge_a_1 = mesh_a.points[edges_a[:, 0], :] + edge_a_2 = mesh_a.points[edges_a[:, 1], :] + edge_b_1 = mesh_b.points[edges_b[:, 0], :] + edge_b_2 = mesh_b.points[edges_b[:, 1], :] + + a_grid, b_grid = np.mgrid[0:mesh_a.n_edges, 0:mesh_b.n_edges] + a_grid = a_grid.reshape(-1) + b_grid = b_grid.reshape(-1) + + p1 = edge_a_1[a_grid, :] + p2 = edge_a_2[a_grid, :] + p3 = edge_b_1[b_grid, :] + p4 = edge_b_2[b_grid, :] + + # + # TODO: Investigate whether adding a bounding box check will help with speed, seems likely as most edges wont cross + # + + # + # Solve the equations + # + # z_a1 + s delta_z_a = z_b1 + t delta_z_b + # + # for z = (x, y) + # + + start_point_diff = p1 - p3 + + delta1 = p2 - p1 + delta3 = p4 - p3 + + deltas = np.concatenate(([-delta1], [delta3]), axis=0) + deltas = np.moveaxis(deltas, 0, 2) + + non_singular = np.linalg.det(deltas) != 0 + + st = np.linalg.solve(deltas[non_singular], start_point_diff[non_singular]) + + # Find the points where s and t are in (0, 1) + + intersection_inds = np.logical_and( + np.logical_and(0 < st[:, 0], st[:, 0] < 1), + np.logical_and(0 < st[:, 1], st[:, 1] < 1)) + + start_points_for_intersections = p1[non_singular][intersection_inds, :] + deltas_for_intersections = delta1[non_singular][intersection_inds, :] + + points_to_add = start_points_for_intersections + st[intersection_inds, 0].reshape(-1,1) * deltas_for_intersections + + t1 = time.time() + print("Edge intersections:", t1 - t0) + + # Build list of all input points, in a way that we can check for coincident points + + + points = np.concatenate(( + mesh_a.points, + mesh_b.points, + points_to_add + )) + + + # Remove coincident points + + points = np.unique(points, axis=0) + + # Triangulate based on these intersections + + output_mesh = delaunay_mesh(points[:, 0], points[:, 1]) + + + t2 = time.time() + print("Delaunay:", t2 - t1) + + + # Find centroids of all output triangles, and find which source cells they belong to + + ## step 1) Assign -1 to all cells of original meshes + assignments_a = -np.ones(output_mesh.n_cells, dtype=int) + assignments_b = -np.ones(output_mesh.n_cells, dtype=int) + + ## step 2) Find centroids of triangulated mesh (just needs to be a point inside, but this is a good one) + centroids = [] + for cell in output_mesh.cells: + centroid = np.sum(output_mesh.points[cell, :]/3, axis=0) + centroids.append(centroid) + + centroids = np.array(centroids) + + t3 = time.time() + print("Centroids:", t3 - t2) + + + ## step 3) Find where points belong based on Mesh classes point location algorithm + + assignments_a = mesh_a.locate_points(centroids[:, 0], centroids[:, 1]) + assignments_b = mesh_b.locate_points(centroids[:, 0], centroids[:, 1]) + + t4 = time.time() + print("Assignments:", t4 - t3) + + return output_mesh, assignments_a, assignments_b + + +def main(): + from voronoi_mesh import voronoi_mesh + + n1 = 100 + n2 = 100 + + m1 = voronoi_mesh(np.random.random(n1), np.random.random(n1)) + m2 = voronoi_mesh(np.random.random(n2), np.random.random(n2)) + + + mesh, assignement1, assignement2 = meshmerge(m1, m2) + + mesh.show() + + +if __name__ == "__main__": + main() diff --git a/sasdata/slicing/meshes/util.py b/sasdata/slicing/meshes/util.py new file mode 100644 index 0000000..b78a9e0 --- /dev/null +++ b/sasdata/slicing/meshes/util.py @@ -0,0 +1,10 @@ +from typing import Sequence, TypeVar + +T = TypeVar("T") + +def closed_loop_edges(values: Sequence[T]) -> tuple[T, T]: + """ Generator for a closed loop of edge pairs """ + for pair in zip(values, values[1:]): + yield pair + + yield values[-1], values[0] \ No newline at end of file diff --git a/sasdata/slicing/meshes/voronoi_mesh.py b/sasdata/slicing/meshes/voronoi_mesh.py new file mode 100644 index 0000000..d47dc2c --- /dev/null +++ b/sasdata/slicing/meshes/voronoi_mesh.py @@ -0,0 +1,96 @@ +import numpy as np +from scipy.spatial import Voronoi + + +from sasdata.slicing.meshes.mesh import Mesh + +def voronoi_mesh(x, y, debug_plot=False) -> Mesh: + """ Create a mesh based on a voronoi diagram of points """ + + input_data = np.array((x.reshape(-1), y.reshape(-1))).T + + # Need to make sure mesh covers a finite region, probably not important for + # much data stuff, but is important for plotting + # + # * We want the cells at the edge of the mesh to have a reasonable size, definitely not infinite + # * The exact size doesn't matter that much + # * It should work well with a grid, but also + # * ...it should be robust so that if the data isn't on a grid, it doesn't cause any serious problems + # + # Plan: Create a square border of points that are totally around the points, this is + # at the distance it would be if it was an extra row of grid points + # to do this we'll need + # 1) an estimate of the grid spacing + # 2) the bounding box of the grid + # + + + # Use the median area of finite voronoi cells as an estimate + voronoi = Voronoi(input_data) + finite_cells = [region for region in voronoi.regions if -1 not in region and len(region) > 0] + premesh = Mesh(points=voronoi.vertices, cells=finite_cells) + + area_spacing = np.median(premesh.areas) + gap = np.sqrt(area_spacing) + + # Bounding box is easy + x_min, y_min = np.min(input_data, axis=0) + x_max, y_max = np.max(input_data, axis=0) + + # Create a border + n_x = int(np.round((x_max - x_min)/gap)) + n_y = int(np.round((y_max - y_min)/gap)) + + top_bottom_xs = np.linspace(x_min - gap, x_max + gap, n_x + 3) + left_right_ys = np.linspace(y_min, y_max, n_y + 1) + + top = np.array([top_bottom_xs, (y_max + gap) * np.ones_like(top_bottom_xs)]) + bottom = np.array([top_bottom_xs, (y_min - gap) * np.ones_like(top_bottom_xs)]) + left = np.array([(x_min - gap) * np.ones_like(left_right_ys), left_right_ys]) + right = np.array([(x_max + gap) * np.ones_like(left_right_ys), left_right_ys]) + + added_points = np.concatenate((top, bottom, left, right), axis=1).T + + if debug_plot: + import matplotlib.pyplot as plt + plt.scatter(x, y) + plt.scatter(added_points[:, 0], added_points[:, 1]) + plt.show() + + new_points = np.concatenate((input_data, added_points), axis=0) + voronoi = Voronoi(new_points) + + # Remove the cells that correspond to the added edge points, + # Because the points on the edge of the square are (weakly) convex, these + # regions be infinite + + # finite_cells = [region for region in voronoi.regions if -1 not in region and len(region) > 0] + + # ... however, we can just use .region_points + input_regions = voronoi.point_region[:input_data.shape[0]] + cells = [voronoi.regions[region_index] for region_index in input_regions] + + return Mesh(points=voronoi.vertices, cells=cells) + + +def square_grid_check(): + values = np.linspace(-10, 10, 21) + x, y = np.meshgrid(values, values) + + mesh = voronoi_mesh(x, y) + + mesh.show(show_labels=True) + +def random_grid_check(): + import matplotlib.pyplot as plt + points = np.random.random((100, 2)) + mesh = voronoi_mesh(points[:, 0], points[:, 1], True) + mesh.show(actually_show=False) + plt.scatter(points[:, 0], points[:, 1]) + plt.show() + + +if __name__ == "__main__": + square_grid_check() + # random_grid_check() + diff --git a/sasdata/slicing/rebinning.py b/sasdata/slicing/rebinning.py new file mode 100644 index 0000000..f2c76de --- /dev/null +++ b/sasdata/slicing/rebinning.py @@ -0,0 +1,149 @@ +from abc import ABC, abstractmethod +from typing import Optional +from dataclasses import dataclass + +import numpy as np + +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh +from sasdata.slicing.meshes.meshmerge import meshmerge + +import time + +@dataclass +class CacheData: + """ Data cached for repeated calculations with the same coordinates """ + input_coordinates: np.ndarray # Input data + input_coordinates_mesh: Mesh # Mesh of the input data + merged_mesh_data: tuple[Mesh, np.ndarray, np.ndarray] # mesh information about the merging + + +class Rebinner(ABC): + + + def __init__(self): + """ Base class for rebinning methods""" + + self._bin_mesh_cache: Optional[Mesh] = None # cached version of the output bin mesh + + # Output dependent caching + self._input_cache: Optional[CacheData] = None + + + @abstractmethod + def _bin_coordinates(self) -> np.ndarray: + """ Coordinates for the output bins """ + + @abstractmethod + def _bin_mesh(self) -> Mesh: + """ Get the meshes used for binning """ + + @property + def allowable_orders(self) -> list[int]: + return [-1, 0, 1] + + @property + def bin_mesh(self) -> Mesh: + + if self._bin_mesh_cache is None: + bin_mesh = self._bin_mesh() + self._bin_mesh_cache = bin_mesh + + return self._bin_mesh_cache + + def _post_processing(self, coordinates, values) -> tuple[np.ndarray, np.ndarray]: + """ Perform post-processing on the mesh binned values """ + # Default is to do nothing, override if needed + return coordinates, values + + def _calculate(self, input_coordinates: np.ndarray, input_data: np.ndarray, order: int) -> np.ndarray: + """ Main calculation """ + + if order == -1: + # Construct the input output mapping just based on input points being the output cells, + # Equivalent to the original binning method + + mesh = self.bin_mesh + bin_identities = mesh.locate_points(input_coordinates[:,0], input_coordinates[:, 1]) + output_data = np.zeros(mesh.n_cells, dtype=float) + + for index, bin in enumerate(bin_identities): + if bin >= 0: + output_data[bin] += input_data[index] + + return output_data + + else: + # Use a mapping based on meshes + + # Either create de-cache the appropriate mesh + # Why not use a hash? Hashing takes time, equality checks are pretty fast, need to check equality + # when there is a hit anyway in case of very rare chance of collision, hits are the most common case, + # we want it to work 100% of the time, not 99.9999% + if self._input_cache is not None and np.all(self._input_cache.input_coordinates == input_coordinates): + + input_coordinate_mesh = self._input_cache.input_coordinates_mesh + merge_data = self._input_cache.merged_mesh_data + + else: + # Calculate mesh data + input_coordinate_mesh = voronoi_mesh(input_coordinates[:,0], input_coordinates[:, 1]) + self._data_mesh_cache = input_coordinate_mesh + + merge_data = meshmerge(self.bin_mesh, input_coordinate_mesh) + + # Cache mesh data + self._input_cache = CacheData( + input_coordinates=input_coordinates, + input_coordinates_mesh=input_coordinate_mesh, + merged_mesh_data=merge_data) + + merged_mesh, merged_to_output, merged_to_input = merge_data + + # Calculate values according to the order parameter + t0 = time.time() + if order == 0: + # Based on the overlap of cells only + + input_areas = input_coordinate_mesh.areas + output = np.zeros(self.bin_mesh.n_cells, dtype=float) + + for input_index, output_index, area in zip(merged_to_input, merged_to_output, merged_mesh.areas): + if input_index == -1 or output_index == -1: + # merged region does not correspond to anything of interest + continue + + output[output_index] += input_data[input_index] * area / input_areas[input_index] + + print("Main calc:", time.time() - t0) + + return output + + elif order == 1: + # Linear interpolation requires the following relationship with the data, + # as the input data is the total over the whole input cell, the linear + # interpolation requires continuity at the vertices, and a constraint on the + # integral. + # + # We can take each of the input points, and the associated values, and solve a system + # of linear equations that gives a total value. + + raise NotImplementedError("1st order (linear) interpolation currently not implemented") + + else: + raise ValueError(f"Expected order to be in {self.allowable_orders}, got {order}") + + def sum(self, x: np.ndarray, y: np.ndarray, data: np.ndarray, order: int = 0) -> np.ndarray: + """ Return the summed data in the output bins """ + return self._calculate(np.array((x.reshape(-1), y.reshape(-1))).T, data.reshape(-1), order) + + def error_propagate(self, input_coordinates: np.ndarray, data: np.ndarray, errors) -> np.ndarray: + raise NotImplementedError("Error propagation not implemented yet") + + def resolution_propagate(self, input_coordinates: np.ndarray, data: np.ndarray, errors) -> np.ndarray: + raise NotImplementedError("Resolution propagation not implemented yet") + + def average(self, x: np.ndarray, y: np.ndarray, data: np.ndarray, order: int = 0) -> np.ndarray: + """ Return the averaged data in the output bins """ + return self._calculate(np.array((x, y)).T, data.reshape(-1), order) / self.bin_mesh.areas + diff --git a/sasdata/slicing/sample_polygons.py b/sasdata/slicing/sample_polygons.py new file mode 100644 index 0000000..e12fb1e --- /dev/null +++ b/sasdata/slicing/sample_polygons.py @@ -0,0 +1,31 @@ +import numpy as np + +def wedge(q0, q1, theta0, theta1, clockwise=False, n_points_per_degree=2): + + # Traverse a rectangle in curvilinear coordinates (q0, theta0), (q0, theta1), (q1, theta1), (q1, theta0) + if clockwise: + if theta1 > theta0: + theta0 += 2*np.pi + + else: + if theta0 > theta1: + theta1 += 2*np.pi + + subtended_angle = np.abs(theta1 - theta0) + n_points = int(subtended_angle*180*n_points_per_degree/np.pi)+1 + + angles = np.linspace(theta0, theta1, n_points) + + xs = np.concatenate((q0*np.cos(angles), q1*np.cos(angles[::-1]))) + ys = np.concatenate((q0*np.sin(angles), q1*np.sin(angles[::-1]))) + + return np.array((xs, ys)).T + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + xy = wedge(0.3, 0.6, 2, 3) + + plt.plot(xy[:,0], xy[:,1]) + plt.show() + diff --git a/sasdata/slicing/slicer_demo.py b/sasdata/slicing/slicer_demo.py new file mode 100644 index 0000000..af3ee98 --- /dev/null +++ b/sasdata/slicing/slicer_demo.py @@ -0,0 +1,120 @@ +""" Dev docs: Demo to show the behaviour of the re-binning methods """ + +import numpy as np + +import matplotlib.pyplot as plt + +from sasdata.slicing.slicers.AnularSector import AnularSector +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh + + + +if __name__ == "__main__": + q_range = 1.5 + demo1 = True + demo2 = True + + # Demo of sums, annular sector over some not very circular data + + if demo1: + + x = (2 * q_range) * (np.random.random(400) - 0.5) + y = (2 * q_range) * (np.random.random(400) - 0.5) + + display_mesh = voronoi_mesh(x, y) + + + def lobe_test_function(x, y): + return 1 + np.sin(x*np.pi/q_range)*np.sin(y*np.pi/q_range) + + + random_lobe_data = lobe_test_function(x, y) + + plt.figure("Input Dataset 1") + display_mesh.show_data(random_lobe_data, actually_show=False) + + data_order_0 = [] + data_order_neg1 = [] + + sizes = np.linspace(0.1, 1, 100) + + for index, size in enumerate(sizes): + q0 = 0.75 - 0.6*size + q1 = 0.75 + 0.6*size + phi0 = np.pi/2 - size + phi1 = np.pi/2 + size + + rebinner = AnularSector(q0, q1, phi0, phi1) + + data_order_neg1.append(rebinner.sum(x, y, random_lobe_data, order=-1)) + data_order_0.append(rebinner.sum(x, y, random_lobe_data, order=0)) + + if index % 10 == 0: + plt.figure("Regions 1") + rebinner.bin_mesh.show(actually_show=False) + + plt.title("Regions") + + plt.figure("Sum of region, dataset 1") + + plt.plot(sizes, data_order_neg1) + plt.plot(sizes, data_order_0) + + plt.legend(["Order -1", "Order 0"]) + plt.title("Sum over region") + + + # Demo of averaging, annular sector over ring shaped data + + if demo2: + + x, y = np.meshgrid(np.linspace(-q_range, q_range, 41), np.linspace(-q_range, q_range, 41)) + x = x.reshape(-1) + y = y.reshape(-1) + + display_mesh = voronoi_mesh(x, y) + + + def ring_test_function(x, y): + r = np.sqrt(x**2 + y**2) + return np.log(np.sinc(r*1.5)**2) + + + grid_ring_data = ring_test_function(x, y) + + plt.figure("Input Dataset 2") + display_mesh.show_data(grid_ring_data, actually_show=False) + + data_order_0 = [] + data_order_neg1 = [] + + sizes = np.linspace(0.1, 1, 100) + + for index, size in enumerate(sizes): + q0 = 0.25 + q1 = 1.25 + + phi0 = np.pi/2 - size + phi1 = np.pi/2 + size + + rebinner = AnularSector(q0, q1, phi0, phi1) + + data_order_neg1.append(rebinner.average(x, y, grid_ring_data, order=-1)) + data_order_0.append(rebinner.average(x, y, grid_ring_data, order=0)) + + if index % 10 == 0: + plt.figure("Regions 2") + rebinner.bin_mesh.show(actually_show=False) + + plt.title("Regions") + + plt.figure("Average of region 2") + + plt.plot(sizes, data_order_neg1) + plt.plot(sizes, data_order_0) + + plt.legend(["Order -1", "Order 0"]) + plt.title("Sum over region") + + plt.show() + diff --git a/sasdata/slicing/slicers/AnularSector.py b/sasdata/slicing/slicers/AnularSector.py new file mode 100644 index 0000000..4ace344 --- /dev/null +++ b/sasdata/slicing/slicers/AnularSector.py @@ -0,0 +1,43 @@ +import numpy as np + +from sasdata.slicing.rebinning import Rebinner +from sasdata.slicing.meshes.mesh import Mesh + +class AnularSector(Rebinner): + """ A single annular sector (wedge sum)""" + def __init__(self, q0: float, q1: float, phi0: float, phi1: float, points_per_degree: int=2): + super().__init__() + + self.q0 = q0 + self.q1 = q1 + self.phi0 = phi0 + self.phi1 = phi1 + + self.points_per_degree = points_per_degree + + def _bin_mesh(self) -> Mesh: + + n_points = np.max([int(1 + 180*self.points_per_degree*(self.phi1 - self.phi0) / np.pi), 2]) + + angles = np.linspace(self.phi0, self.phi1, n_points) + + row1 = self.q0 * np.array([np.cos(angles), np.sin(angles)]) + row2 = self.q1 * np.array([np.cos(angles), np.sin(angles)])[:, ::-1] + + points = np.concatenate((row1, row2), axis=1).T + + cells = [[i for i in range(2*n_points)]] + + return Mesh(points=points, cells=cells) + + def _bin_coordinates(self) -> np.ndarray: + return np.array([], dtype=float) + + +def main(): + """ Just show a random example""" + AnularSector(1, 2, 1, 2).bin_mesh.show() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sasdata/slicing/slicers/__init__.py b/sasdata/slicing/slicers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/slicing/transforms.py b/sasdata/slicing/transforms.py new file mode 100644 index 0000000..d04742d --- /dev/null +++ b/sasdata/slicing/transforms.py @@ -0,0 +1,58 @@ +import numpy as np +from scipy.spatial import Voronoi, Delaunay +import matplotlib.pyplot as plt +from matplotlib import cm + + +# Some test data + +qx_base_values = np.linspace(-10, 10, 21) +qy_base_values = np.linspace(-10, 10, 21) + +qx, qy = np.meshgrid(qx_base_values, qy_base_values) + +include = np.logical_not((np.abs(qx) < 2) & (np.abs(qy) < 2)) + +qx = qx[include] +qy = qy[include] + +r = np.sqrt(qx**2 + qy**2) + +data = np.log((1+np.cos(3*r))*np.exp(-r*r)) + +colormap = cm.get_cmap('winter', 256) + +def get_data_mesh(x, y, data): + + input_data = np.array((x, y)).T + voronoi = Voronoi(input_data) + + # plt.scatter(voronoi.vertices[:,0], voronoi.vertices[:,1]) + # plt.scatter(voronoi.points[:,0], voronoi.points[:,1]) + + cmin = np.min(data) + cmax = np.max(data) + + color_index_map = np.array(255 * (data - cmin) / (cmax - cmin), dtype=int) + + for point_index, points in enumerate(voronoi.points): + + region_index = voronoi.point_region[point_index] + region = voronoi.regions[region_index] + + if len(region) > 0: + + if -1 in region: + + pass + + else: + + color = colormap(color_index_map[point_index]) + + circly = region + [region[0]] + plt.fill(voronoi.vertices[circly, 0], voronoi.vertices[circly, 1], color=color, edgecolor="white") + + plt.show() + +get_data_mesh(qx.reshape(-1), qy.reshape(-1), data) \ No newline at end of file diff --git a/sasdata/temp_hdf5_reader.py b/sasdata/temp_hdf5_reader.py new file mode 100644 index 0000000..6583d19 --- /dev/null +++ b/sasdata/temp_hdf5_reader.py @@ -0,0 +1,154 @@ +import os +import h5py + + +import logging + +import numpy as np + + +from h5py._hl.dataset import Dataset as HDF5Dataset +from h5py._hl.group import Group as HDF5Group + + +from sasdata.data import SasData +from sasdata.data_backing import Dataset as SASDataDataset, Group as SASDataGroup + +from sasdata.quantities.quantity import NamedQuantity +from sasdata.quantities import units +from sasdata.quantities.unit_parser import parse + +# test_file = "./example_data/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5" +# test_file = "./example_data/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5" +# test_file = "./example_data/2d_data/BAM_2D.h5" +test_file = "./example_data/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5" +# test_file = "./example_data/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5" + +logger = logging.getLogger(__name__) + + +def recurse_hdf5(hdf5_entry): + if isinstance(hdf5_entry, HDF5Dataset): + # + # print(hdf5_entry.dtype) + # print(type(hdf5_entry.dtype)) + + attributes = {name: hdf5_entry.attrs[name] for name in hdf5_entry.attrs} + + if isinstance(hdf5_entry.dtype, np.dtypes.BytesDType): + data = hdf5_entry[()][0].decode("utf-8") + + return SASDataDataset[str]( + name=hdf5_entry.name, + data=data, + attributes=attributes) + + else: + data = np.array(hdf5_entry, dtype=hdf5_entry.dtype) + + return SASDataDataset[np.ndarray]( + name=hdf5_entry.name, + data=data, + attributes=attributes) + + elif isinstance(hdf5_entry, HDF5Group): + return SASDataGroup( + name=hdf5_entry.name, + children={key: recurse_hdf5(hdf5_entry[key]) for key in hdf5_entry.keys()}) + + else: + raise TypeError(f"Unknown type found during HDF5 parsing: {type(hdf5_entry)} ({hdf5_entry})") + +GET_UNITS_FROM_ELSEWHERE = units.meters +def connected_data(node: SASDataGroup, name_prefix="") -> list[NamedQuantity]: + """ In the context of NeXus files, load a group of data entries that are organised together + match up the units and errors with their values""" + # Gather together data with its error terms + + uncertainty_map = {} + uncertainties = set() + entries = {} + + for name in node.children: + + child = node.children[name] + + if "units" in child.attributes: + units = parse(child.attributes["units"]) + else: + units = GET_UNITS_FROM_ELSEWHERE + + quantity = NamedQuantity(name=name_prefix+child.name, + value=child.data, + units=units) + + # Turns out people can't be trusted to use the same keys here + if "uncertainty" in child.attributes or "uncertainties" in child.attributes: + try: + uncertainty_name = child.attributes["uncertainty"] + except: + uncertainty_name = child.attributes["uncertainties"] + uncertainty_map[name] = uncertainty_name + uncertainties.add(uncertainty_name) + + entries[name] = quantity + + output = [] + + for name, entry in entries.items(): + if name not in uncertainties: + if name in uncertainty_map: + uncertainty = entries[uncertainty_map[name]] + new_entry = entry.with_standard_error(uncertainty) + output.append(new_entry) + else: + output.append(entry) + + return output + + +def load_data(filename) -> list[SasData]: + with h5py.File(filename, 'r') as f: + + loaded_data: list[SasData] = [] + + for root_key in f.keys(): + + entry = f[root_key] + + data_contents = [] + raw_metadata = {} + + entry_keys = [key for key in entry.keys()] + + if "sasdata" not in entry_keys and "data" not in entry_keys: + logger.warning("No sasdata or data key") + + for key in entry_keys: + component = entry[key] + lower_key = key.lower() + if lower_key == "sasdata" or lower_key == "data": + datum = recurse_hdf5(component) + # TODO: Use named identifier + data_contents = connected_data(datum, "FILE_ID_HERE") + + else: + raw_metadata[key] = recurse_hdf5(component) + + + loaded_data.append( + SasData( + name=root_key, + data_contents=data_contents, + raw_metadata=SASDataGroup("root", raw_metadata), + verbose=False)) + + return loaded_data + + + + +data = load_data(test_file) + +for dataset in data: + print(dataset.summary(include_raw=False)) \ No newline at end of file diff --git a/sasdata/transforms/post_process.py b/sasdata/transforms/post_process.py new file mode 100644 index 0000000..e69de29 diff --git a/sasdata/transforms/rebinning.py b/sasdata/transforms/rebinning.py new file mode 100644 index 0000000..fe96bcb --- /dev/null +++ b/sasdata/transforms/rebinning.py @@ -0,0 +1,205 @@ +""" Algorithms for interpolation and rebinning """ +from typing import TypeVar + +import numpy as np +from numpy._typing import ArrayLike +from scipy.interpolate import interp1d + +from sasdata.quantities.quantity import Quantity +from scipy.sparse import coo_matrix + +from enum import Enum + +class InterpolationOptions(Enum): + NEAREST_NEIGHBOUR = 0 + LINEAR = 1 + CUBIC = 3 + +class InterpolationError(Exception): + """ We probably want to raise exceptions because interpolation is not appropriate/well-defined, + not the same as numerical issues that will raise ValueErrors""" + + +def calculate_interpolation_matrix_1d(input_axis: Quantity[ArrayLike], + output_axis: Quantity[ArrayLike], + mask: ArrayLike | None = None, + order: InterpolationOptions = InterpolationOptions.LINEAR, + is_density=False): + + """ Calculate the matrix that converts values recorded at points specified by input_axis to + values recorded at points specified by output_axis""" + + # We want the input values in terms of the output units, will implicitly check compatability + # TODO: incorporate mask + + working_units = output_axis.units + + input_x = input_axis.in_units_of(working_units) + output_x = output_axis.in_units_of(working_units) + + # Get the array indices that will map the array to a sorted one + input_sort = np.argsort(input_x) + output_sort = np.argsort(output_x) + + input_unsort = np.arange(len(input_x), dtype=int)[input_sort] + output_unsort = np.arange(len(output_x), dtype=int)[output_sort] + + sorted_in = input_x[input_sort] + sorted_out = output_x[output_sort] + + n_in = len(sorted_in) + n_out = len(sorted_out) + + conversion_matrix = None # output + + match order: + case InterpolationOptions.NEAREST_NEIGHBOUR: + + # COO Sparse matrix definition data + i_entries = [] + j_entries = [] + + crossing_points = 0.5*(sorted_out[1:] + sorted_out[:-1]) + + # Find the output values nearest to each of the input values + i=0 + for k, crossing_point in enumerate(crossing_points): + while i < n_in and sorted_in[i] < crossing_point: + i_entries.append(i) + j_entries.append(k) + i += 1 + + # All the rest in the last bin + while i < n_in: + i_entries.append(i) + j_entries.append(n_out-1) + i += 1 + + i_entries = input_unsort[np.array(i_entries, dtype=int)] + j_entries = output_unsort[np.array(j_entries, dtype=int)] + values = np.ones_like(i_entries, dtype=float) + + conversion_matrix = coo_matrix((values, (i_entries, j_entries)), shape=(n_in, n_out)) + + case InterpolationOptions.LINEAR: + + # Leverage existing linear interpolation methods to get the mapping + # do a linear interpolation on indices + # the floor should give the left bin + # the ceil should give the right bin + # the fractional part should give the relative weightings + + input_indices = np.arange(n_in, dtype=int) + output_indices = np.arange(n_out, dtype=int) + + fractional = np.interp(x=sorted_out, xp=sorted_in, fp=input_indices, left=0, right=n_in-1) + + left_bins = np.floor(fractional).astype(int) + right_bins = np.ceil(fractional).astype(int) + + right_weight = fractional % 1 + left_weight = 1 - right_weight + + # There *should* be no repeated entries for both i and j in the main part, but maybe at the ends + # If left bin is the same as right bin, then we only want one entry, and the weight should be 1 + + same = left_bins == right_bins + not_same = ~same + + same_bins = left_bins[same] # could equally be right bins, they're the same + + same_indices = output_indices[same] + not_same_indices = output_indices[not_same] + + j_entries_sorted = np.concatenate((same_indices, not_same_indices, not_same_indices)) + i_entries_sorted = np.concatenate((same_bins, left_bins[not_same], right_bins[not_same])) + + i_entries = input_unsort[i_entries_sorted] + j_entries = output_unsort[j_entries_sorted] + + # weights don't need to be unsorted # TODO: check this is right, it should become obvious if we use unsorted data + weights = np.concatenate((np.ones_like(same_bins, dtype=float), left_weight[not_same], right_weight[not_same])) + + conversion_matrix = coo_matrix((weights, (i_entries, j_entries)), shape=(n_in, n_out)) + + case InterpolationOptions.CUBIC: + # Cubic interpolation, much harder to implement because we can't just cheat and use numpy + raise NotImplementedError("Cubic interpolation not implemented yet") + + case _: + raise InterpolationError(f"Unsupported interpolation order: {order}") + + + if mask is None: + return conversion_matrix, None + + else: + # Create a new mask + + # Convert to numerical values + # Conservative masking: anything touched by the previous mask is now masked + new_mask = (np.array(mask, dtype=float) @ conversion_matrix) != 0.0 + + return conversion_matrix, new_mask + + +def calculate_interpolation_matrix_2d_axis_axis(input_1: Quantity[ArrayLike], + input_2: Quantity[ArrayLike], + output_1: Quantity[ArrayLike], + output_2: Quantity[ArrayLike], + mask, + order: InterpolationOptions = InterpolationOptions.LINEAR, + is_density: bool = False): + + # This is just the same 1D matrices things + + match order: + case InterpolationOptions.NEAREST_NEIGHBOUR: + pass + + case InterpolationOptions.LINEAR: + pass + + case InterpolationOptions.CUBIC: + pass + + case _: + pass + + +def calculate_interpolation_matrix(input_axes: list[Quantity[ArrayLike]], + output_axes: list[Quantity[ArrayLike]], + data: ArrayLike | None = None, + mask: ArrayLike | None = None): + + # TODO: We probably should delete this, but lets keep it for now + + if len(input_axes) not in (1, 2): + raise InterpolationError("Interpolation is only supported for 1D and 2D data") + + if len(input_axes) == 1 and len(output_axes) == 1: + # Check for dimensionality + input_axis = input_axes[0] + output_axis = output_axes[0] + + if len(input_axis.value.shape) == 1: + if len(output_axis.value.shape) == 1: + calculate_interpolation_matrix_1d() + + if len(output_axes) != len(input_axes): + # Input or output axes might be 2D matrices + pass + + + +def rebin(data: Quantity[ArrayLike], + axes: list[Quantity[ArrayLike]], + new_axes: list[Quantity[ArrayLike]], + mask: ArrayLike | None = None, + interpolation_order: int = 1): + + """ This algorithm is only for operations that preserve dimensionality, + i.e. non-projective rebinning. + """ + + pass \ No newline at end of file diff --git a/sasdata/transforms/test_interpolation.py b/sasdata/transforms/test_interpolation.py new file mode 100644 index 0000000..97b4f79 --- /dev/null +++ b/sasdata/transforms/test_interpolation.py @@ -0,0 +1,91 @@ +import pytest +import numpy as np +from matplotlib import pyplot as plt +from numpy.typing import ArrayLike +from typing import Callable + +from sasdata.quantities.plotting import quantity_plot +from sasdata.quantities.quantity import NamedQuantity, Quantity +from sasdata.quantities import units + +from sasdata.transforms.rebinning import calculate_interpolation_matrix_1d, InterpolationOptions + +test_functions = [ + lambda x: x**2, + lambda x: 2*x, + lambda x: x**3 +] + + +@pytest.mark.parametrize("fun", test_functions) +def test_linear_interpolate_matrix_inside(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]]): + original_points = NamedQuantity("x_base", np.linspace(-10,10, 31), units.meters) + test_points = NamedQuantity("x_test", np.linspace(-5, 5, 11), units.meters) + + + mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=InterpolationOptions.LINEAR) + + y_original = fun(original_points) + y_test = y_original @ mapping + y_expected = fun(test_points) + + test_units = y_expected.units + + y_values_test = y_test.in_units_of(test_units) + y_values_expected = y_expected.in_units_of(test_units) + + # print(y_values_test) + # print(y_values_expected) + # + # quantity_plot(original_points, y_original) + # quantity_plot(test_points, y_test) + # quantity_plot(test_points, y_expected) + # plt.show() + + assert len(y_values_test) == len(y_values_expected) + + for t, e in zip(y_values_test, y_values_expected): + assert t == pytest.approx(e, abs=2) + + +@pytest.mark.parametrize("fun", test_functions) +def test_linear_interpolate_different_units(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]]): + original_points = NamedQuantity("x_base", np.linspace(-10,10, 107), units.meters) + test_points = NamedQuantity("x_test", np.linspace(-5000, 5000, 11), units.millimeters) + + mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=InterpolationOptions.LINEAR) + + y_original = fun(original_points) + y_test = y_original @ mapping + y_expected = fun(test_points) + + test_units = y_expected.units + + y_values_test = y_test.in_units_of(test_units) + y_values_expected = y_expected.in_units_of(test_units) + # + # print(y_values_test) + # print(y_test.in_si()) + # print(y_values_expected) + # + # plt.plot(original_points.in_si(), y_original.in_si()) + # plt.plot(test_points.in_si(), y_test.in_si(), "x") + # plt.plot(test_points.in_si(), y_expected.in_si(), "o") + # plt.show() + + assert len(y_values_test) == len(y_values_expected) + + for t, e in zip(y_values_test, y_values_expected): + assert t == pytest.approx(e, rel=5e-2) + +def test_linearity_linear(): + """ Test linear interpolation between two points""" + x_and_y = NamedQuantity("x_base", np.linspace(-10, 10, 2), units.meters) + new_x = NamedQuantity("x_test", np.linspace(-5000, 5000, 101), units.millimeters) + + mapping, _ = calculate_interpolation_matrix_1d(x_and_y, new_x, order=InterpolationOptions.LINEAR) + + linear_points = x_and_y @ mapping + + for t, e in zip(new_x.in_si(), linear_points.in_si()): + assert t == pytest.approx(e, rel=1e-3) \ No newline at end of file diff --git a/sasdata/util.py b/sasdata/util.py new file mode 100644 index 0000000..2cd6e3f --- /dev/null +++ b/sasdata/util.py @@ -0,0 +1,17 @@ +from typing import TypeVar, Callable + +T = TypeVar("T") + +def cache[T](fun: Callable[[], T]): + """ Decorator to store values """ + + cache_state = [False, None] + + def wrapper() -> T: + if not cache_state[0]: + cache_state[0] = True + cache_state[1] = fun() + + return cache_state[1] + + return wrapper \ No newline at end of file diff --git a/test/slicers/__init__.py b/test/slicers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/slicers/meshes_for_testing.py b/test/slicers/meshes_for_testing.py new file mode 100644 index 0000000..fb346e7 --- /dev/null +++ b/test/slicers/meshes_for_testing.py @@ -0,0 +1,115 @@ +""" +Meshes used in testing along with some expected values +""" + +import numpy as np + +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.meshes.meshmerge import meshmerge + +coords = np.arange(-4, 5) +grid_mesh = voronoi_mesh(*np.meshgrid(coords, coords)) + + +item_1 = np.array([ + [-3.5, -0.5], + [-0.5, 3.5], + [ 0.5, 3.5], + [ 3.5, -0.5], + [ 0.0, 1.5]], dtype=float) + +item_2 = np.array([ + [-1.0, -2.0], + [-2.0, -2.0], + [-2.0, -1.0], + [-1.0, -1.0]], dtype=float) + +mesh_points = np.concatenate((item_1, item_2), axis=0) +cells = [[0,1,2,3,4],[5,6,7,8]] + +shape_mesh = Mesh(mesh_points, cells) + +# Subset of the mappings that meshmerge should include +# This can be read off the plots generated below + + +expected_shape_mappings = [ + (100, -1), + (152, -1), + (141, -1), + (172, -1), + (170, -1), + (0, -1), + (1, -1), + (8, 0), + (9, 0), + (37, 0), + (83, 0), + (190, 1), + (186, 1), + (189, 1), + (193, 1) +] + +expected_grid_mappings = [ + (89, 0), + (90, 1), + (148, 16), + (175, 35), + (60, 47), + (44, 47), + (80, 60) +] + +# +# Mesh location tests +# + +location_test_mesh_points = np.array([ + [0, 0], # 0 + [0, 1], # 1 + [0, 2], # 2 + [1, 0], # 3 + [1, 1], # 4 + [1, 2], # 5 + [2, 0], # 6 + [2, 1], # 7 + [2, 2]], dtype=float) + +location_test_mesh_cells = [ + [0, 1, 4, 3], + [1, 2, 5, 4], + [3, 4, 7, 6], + [4, 5, 8, 7]] + +location_test_mesh = Mesh(location_test_mesh_points, location_test_mesh_cells) + +test_coords = 0.25 + 0.5*np.arange(4) +location_test_points_x, location_test_points_y = np.meshgrid(test_coords, test_coords) + +if __name__ == "__main__": + + import matplotlib.pyplot as plt + + combined_mesh, _, _ = meshmerge(grid_mesh, shape_mesh) + + plt.figure() + combined_mesh.show(actually_show=False, show_labels=True, color='k') + grid_mesh.show(actually_show=False, show_labels=True, color='r') + + plt.xlim([-5, 5]) + plt.ylim([-5, 5]) + + plt.figure() + combined_mesh.show(actually_show=False, show_labels=True, color='k') + shape_mesh.show(actually_show=False, show_labels=True, color='r') + + plt.xlim([-5, 5]) + plt.ylim([-5, 5]) + + plt.figure() + location_test_mesh.show(actually_show=False, show_labels=True) + plt.scatter(location_test_points_x, location_test_points_y) + + plt.show() diff --git a/test/slicers/utest_meshmerge.py b/test/slicers/utest_meshmerge.py new file mode 100644 index 0000000..d83892d --- /dev/null +++ b/test/slicers/utest_meshmerge.py @@ -0,0 +1,32 @@ +""" +Tests for mesh merging operations. + +It's pretty hard to test componentwise, but we can do some tests of the general behaviour +""" + +from sasdata.slicing.meshes.meshmerge import meshmerge +from test.slicers.meshes_for_testing import ( + grid_mesh, shape_mesh, expected_grid_mappings, expected_shape_mappings) + + +def test_meshmerge_mappings(): + """ Test the output of meshmerge is correct + + IMPORTANT IF TESTS FAIL!!!... The docs for scipy.spatial.Voronoi and Delaunay + say that the ordering of faces might depend on machine precession. Thus, these + tests might not be reliable... we'll see how they play out + """ + + import sys + if sys.platform == "darwin": + # It does indeed rely on machine precision, only run on windows and linux + return + + combined_mesh, grid_mappings, shape_mappings = meshmerge(grid_mesh, shape_mesh) + + for triangle_cell, grid_cell in expected_grid_mappings: + assert grid_mappings[triangle_cell] == grid_cell + + for triangle_cell, shape_cell in expected_shape_mappings: + assert shape_mappings[triangle_cell] == shape_cell + diff --git a/test/slicers/utest_point_assignment.py b/test/slicers/utest_point_assignment.py new file mode 100644 index 0000000..4ff53e7 --- /dev/null +++ b/test/slicers/utest_point_assignment.py @@ -0,0 +1,5 @@ + +from test.slicers.meshes_for_testing import location_test_mesh, location_test_points_x, location_test_points_y + +def test_location_assignment(): + pass \ No newline at end of file diff --git a/test/utest_unit_parser.py b/test/utest_unit_parser.py new file mode 100644 index 0000000..afce93f --- /dev/null +++ b/test/utest_unit_parser.py @@ -0,0 +1,61 @@ +from sasdata.quantities.unit_parser import parse_named_unit, parse_named_unit_from_group, parse_unit +from sasdata.quantities import units +from sasdata.quantities.units import Unit + +import pytest + +named_units_for_testing = [ + ('m', units.meters), + ('A-1', units.per_angstrom), + ('1/A', units.per_angstrom), + ('kmh-2', units.kilometers_per_square_hour), + ('km/h2', units.kilometers_per_square_hour), + ('kgm/s2', units.newtons), + ('m m', units.square_meters), + ('mm', units.millimeters), + ('A^-1', units.per_angstrom), + ('V/Amps', units.ohms), + ('Ω', units.ohms), + ('Å', units.angstroms), + ('%', units.percent) +] + +unnamed_units_for_testing = [ + ('m13', units.meters**13), + ('kW/sr', units.kilowatts/units.stradians) +] + + +@pytest.mark.parametrize("string, expected_units", named_units_for_testing) +def test_name_parse(string: str, expected_units: Unit): + """ Test basic parsing""" + assert parse_named_unit(string) == expected_units + +@pytest.mark.parametrize("string, expected_units", named_units_for_testing + unnamed_units_for_testing) +def test_equivalent(string: str, expected_units: Unit): + """ Check dimensions of parsed units""" + assert parse_unit(string).equivalent(expected_units) + + +@pytest.mark.parametrize("string, expected_units", named_units_for_testing + unnamed_units_for_testing) +def test_scale_same(string: str, expected_units: Unit): + """ Test basic parsing""" + assert parse_unit(string).scale == pytest.approx(expected_units.scale, rel=1e-14) + + +def test_parse_from_group(): + """ Test group based disambiguation""" + parsed_metres_per_second = parse_named_unit_from_group('ms-1', units.speed) + assert parsed_metres_per_second == units.meters_per_second + + +def test_parse_errors(): + # Fails because the unit is not in that specific group. + with pytest.raises(ValueError, match='That unit cannot be parsed from the specified group.'): + parse_named_unit_from_group('km', units.speed) + # Fails because part of the unit matches but there is an unknown unit '@' + with pytest.raises(ValueError, match='unit_str contains forbidden characters.'): + parse_unit('km@-1') + # Fails because 'da' is not a unit. + with pytest.raises(ValueError, match='Unit string contains an unrecognised pattern.'): + parse_unit('mmda2')