Source code for epygram.formats.fafields

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) Météo France (2014-)
# This software is governed by the CeCILL-C license under French law.
# http://www.cecill.info
"""
FA fields utilities
"""

import os
import re
import io

from epygram.extra.util import init_before
from epygram import config, epygramError
from epygram.extra.griberies.definitions.fa import fagribdef


[docs] def find_wind_pair(fieldname): """For a wind **fieldname**, find and return the pair.""" pairs = {'U':'V', 'V':'U', 'ZONAL':'MERIDIEN', 'MERIDIEN':'ZONAL', 'MERID':'ZONAL'} patterns = [r'S\d+WIND\.(?P<d>[U,V])\.PHYS', r'[P,H,V]\d+VENT_(?P<d>(ZONAL)|(MERID)|(MERIDIEN))', r'CLSVENTNEUTRE.(?P<d>[U,V])', r'CLSVENT.(?P<d>(ZONAL)|(MERIDIEN))', r'CLS(?P<d>[U,V]).RAF.MOD.XFU'] axes = {'U':'x', 'ZONAL':'x', 'V':'y', 'MERIDIEN':'y', 'MERID':'y'} pair = None for pattern in patterns: re_ok = re.match(pattern, fieldname) if re_ok: pair = (axes[pairs[re_ok.group(1)]], fieldname.replace(re_ok.group('d'), pairs[re_ok.group('d')])) break if pair is None: raise epygramError('not a wind field') else: return pair
[docs] def get_generic_fid(fieldname): """Return a generic fid from **fieldname** (via FaGribDef).""" try: fid = fagribdef.FA2GRIB(fieldname, include_comments=False, fatal=True) except ValueError: # not found if sfxflddesc.is_metadata(fieldname): raise else: fid = fagribdef.FA2GRIB(fieldname, include_comments=False, fatal=False) return fid
[docs] class SfxFldDesc_Mod(object): """Handle fields catalog from sfxflddesc.F90 source file.""" _pattern = re.compile(r'"\.(?P<name>[\w\d%]+)\.+(?P<gridtype>\d)\.{2}(?P<type>\w\d)\.{2}(?P<comment>.+)\.{2}(?P<mask>.{20})\.{2}",? ?(&|/)') _unit = re.compile(r'(?P<comment>.*)\((?P<unit>.+)\)') _fortran_sourcename = 'sfxflddesc_mod.F90' type2nature = {'X':'float', 'L':'bool', 'C':'str', 'N':'int', 'Y':'float', 'T':'int'} # FIXME: T: cf mode_write_surf_fa.F90 def __init__(self, actual_init=True): self.table = {} if actual_init: self._actual_init() else: self._initialized = False def _actual_init(self): """Read official file and, if existing, user local file.""" # official one filename = os.path.join(config.installdir, 'data', self._fortran_sourcename) self.read(filename) # local user one user_sfxflddesc = os.path.join(config.userlocaldir, self._fortran_sourcename) if os.path.exists(user_sfxflddesc): self.read(user_sfxflddesc) self._initialized = True
[docs] def read(self, filename): """Parse a sfxflddesc_mod.F90 file.""" with io.open(filename, 'r') as f: lines = f.readlines() for line in lines: m = self._pattern.match(line) if m: info = {} name = m.group('name').replace('.', '') info['gridtype'] = int(m.group('gridtype')) info['type'] = m.group('type') info['comment'] = m.group('comment').replace('.', ' ').strip() u = self._unit.match(info['comment']) if u: info['unit'] = u.group('unit').replace('.', ' ') info['comment'] = u.group('comment').strip() mask = m.group('mask').replace('.', '') if mask: info['mask'] = mask self.table[name] = info self.table['S1D_' + name] = info self.table['SFX.' + name] = info
[docs] def update(self, field_dict): """Update with a dict of field {fieldname:{}, ...}.""" self.table.update(field_dict)
@init_before def nature(self, fieldname, default=None): """Return type of data in field.""" try: return self.type2nature[self.table[fieldname]['type'][0]] except KeyError: if default is None: raise else: return default @init_before def dim(self, fieldname, default=None): """Return number of dimensions of field.""" try: return int(self.table[fieldname]['type'][1]) except KeyError: if default is None: raise else: return default @init_before def __getitem__(self, fieldname): return self.table[fieldname] @init_before def get(self, fieldname, default=None): return self.table.get(fieldname, default) @init_before def is_metadata(self, fieldname): """True if field is not a H2D field but metadata (Misc).""" if fieldname in self.table: if self.table[fieldname]['type'] in ('X1', 'X2'): return False else: return True elif '_FBUF_' in fieldname: return True else: return None @init_before def __contains__(self, fieldname): return fieldname in self.table
sfxflddesc = SfxFldDesc_Mod(actual_init=False)