def translate(self, var): """Returns TranslatedVarlistEntry instance, with populated coordinate axes. Units of scalar coord slices are translated to the units of the conventions' coordinates. Includes logic to translate and rename scalar coords/slices, e.g. VarlistEntry for 'ua' (intrinsically 4D) @ 500mb could produce a TranslatedVarlistEntry for 'u500' (3D slice), depending on naming convention. """ if var.use_exact_name: # HACK; dataclass.asdict says VarlistEntry has no _id attribute & not sure why fl_entry = {f.name: getattr(var, f.name, util.NOTSET) \ for f in dc.fields(TranslatedVarlistEntry) if hasattr(var, f.name)} new_name = var.name else: fl_entry = self.from_CF(var.standard_name, var.axes_set) new_name = fl_entry.name new_dims = [self.translate_coord(dim) for dim in var.dims] new_scalars = [self.translate_coord(dim) for dim in var.scalar_coords] if len(new_scalars) > 1: raise NotImplementedError() elif len(new_scalars) == 1: assert not var.use_exact_name # change translated name to request the slice instead of the full var # keep the scalar_coordinate value attribute on the translated var new_name = fl_entry.scalar_name(var.scalar_coords[0], new_scalars[0]) return util.coerce_to_dataclass( fl_entry, TranslatedVarlistEntry, name=new_name, coords=(new_dims + new_scalars), convention=self.name )
def coordinate_from_struct(d, class_dict=None, **kwargs): """Attempt to instantiate the correct :class:`DMCoordinate` class based on information in dict *d* (read from JSON file). *class_dict* is an optional dict mapping axes identifiers to the :class:`DMCoordinate` child classes to instantiate. Default is to use :class:`DMLongitudeCoordinate` for 'X', etc. TODO: implement full cf_xarray/MetPy heuristics. """ if class_dict is None: class_dict = { 'X': DMLongitudeCoordinate, 'Y': DMLatitudeCoordinate, 'Z': DMVerticalCoordinate, 'T': DMGenericTimeCoordinate, 'OTHER': DMCoordinate } standard_names = { 'longitude': 'X', 'latitude': 'Y', 'time': 'T' } try: ax = 'OTHER' if 'axis' in d: ax = d['axis'] elif d.get('standard_name', "") in standard_names: ax = standard_names[d['standard_name']] return util.coerce_to_dataclass(d, class_dict[ax], **kwargs) except Exception: raise ValueError(f"Couldn't parse coordinate: {repr(d)}")
def from_struct(cls, d, parent): """Parse the "dimensions", "data" and "varlist" sections of the POD's settings.jsonc file when instantiating a new :class:`Diagnostic` object. Args: d (:py:obj:`dict`): Contents of the POD's settings.jsonc file. Returns: :py:obj:`dict`, keys are names of the dimensions in POD's convention, values are :class:`PodDataDimension` objects. """ def _pod_dimension_from_struct(name, dd, v_settings): class_dict = { 'X': VarlistLongitudeCoordinate, 'Y': VarlistLatitudeCoordinate, 'Z': VarlistVerticalCoordinate, 'T': VarlistPlaceholderTimeCoordinate, 'OTHER': VarlistCoordinate } try: return data_model.coordinate_from_struct( dd, class_dict=class_dict, name=name, **(v_settings.time_settings) ) except Exception: raise ValueError(f"Couldn't parse dimension entry for {name}: {dd}") def _iter_shallow_alternates(var): """Iterator over all VarlistEntries referenced as alternates. Doesn't traverse alternates of alternates, etc. """ for alt_vs in var.alternates: yield from alt_vs vlist_settings = util.coerce_to_dataclass( d.get('data', dict()), VarlistSettings) globals_d = vlist_settings.global_settings assert 'dimensions' in d dims_d = {k: _pod_dimension_from_struct(k, v, vlist_settings) \ for k,v in d['dimensions'].items()} assert 'varlist' in d vlist_vars = { k: VarlistEntry.from_struct(globals_d, dims_d, name=k, parent=parent, **v) \ for k,v in d['varlist'].items() } for v in vlist_vars.values(): # validate & replace names of alt vars with references to VE objects for altv_name in _iter_shallow_alternates(v): if altv_name not in vlist_vars: raise ValueError((f"Unknown variable name {altv_name} listed " f"in alternates for varlist entry {v.name}.")) linked_alts = [] for alts in v.alternates: linked_alts.append([vlist_vars[v_name] for v_name in alts]) v.alternates = linked_alts return cls(contents = list(vlist_vars.values()))
def from_instances(cls, *t_coords): """Create new instance from "union" of attributes of t_coords. """ if not t_coords: raise ValueError() t_coords = [util.coerce_to_dataclass(t, cls) for t in t_coords] t0 = t_coords.pop(0) if any(t != t0 for t in t_coords): raise ValueError("mismatch") return t0