def save(self, resave=False): """Save the precomputation to disk, and overwrite existing file in case *resave* is true. """ if (not os.path.exists(self._filename)) or resave: LOG.info("Saving projection to " + self._filename) np.savez(self._filename, **self._cache)
def _set_reader(self, pformat): """Gets the reader for *pformat* format, and puts it in the `reader` attribute. """ elements = pformat.split(".") if len(elements) == 1: reader_module = pformat reader = "mpop.satin."+reader_module # Loading old style plugins reader_module = pformat LOG.info("old style plugin: " + pformat) try: # Look for builtin reader loader = __import__(reader, globals(), locals(), ['load']) except ImportError: # Look for custom reader loader = __import__(reader_module, globals(), locals(), ['load']) # Build a custom Reader plugin on the fly... from mpop.plugin_base import Reader reader_class = type(elements[-1].capitalize() + "Reader", (Reader,), {"pformat": elements[-1]}) reader_instance = reader_class(self) # ... and set its "load" attribute with the "load" function of the # loader module loader = getattr(loader, "load") setattr(reader_instance, "load", loader) setattr(self, elements[-1] + "_reader", reader_instance) else: reader_module = ".".join(elements[:-1]) reader_class = elements[-1] reader = "mpop.satin."+reader_module try: # Look for builtin reader loader = __import__(reader, globals(), locals(), [reader_class]) except ImportError: # Look for custom reader loader = __import__(reader_module, globals(), locals(), [reader_class]) loader = getattr(loader, reader_class) reader_instance = loader(self) setattr(self, loader.pformat + "_reader", reader_instance) return reader_instance
def project(self, coverage_instance): """Make a projected copy of the current channel using the given *coverage_instance*. See also the :mod:`mpop.projector` module. """ res = copy.copy(self) res.area = coverage_instance.out_area res.data = None if self.is_loaded(): LOG.info("Projecting channel %s (%fμm)..." %(self.name, self.wavelength_range[1])) data = coverage_instance.project_array(self._data) res.data = data return res else: raise NotLoadedError("Can't project, channel %s (%fμm) not loaded." %(self.name, self.wavelength_range[1]))
def project(self, dest_area, channels=None, precompute=False, mode=None, radius=None): """Make a copy of the current snapshot projected onto the *dest_area*. Available areas are defined in the region configuration file (ACPG). *channels* tells which channels are to be projected, and if None, all channels are projected and copied over to the return snapshot. If *precompute* is set to true, the projecting data is saved on disk for reusage. *mode* sets the mode to project in: 'quick' which works between cartographic projections, and, as its denomination indicates, is quick (but lower quality), and 'nearest' which uses nearest neighbour for best projection. A *mode* set to None uses 'quick' when possible, 'nearest' otherwise. *radius* defines the radius of influence for neighbour search in 'nearest' mode. Setting it to None, or omitting it will fallback to default values (5 times the channel resolution) or 10km if the resolution is not available. Note: channels have to be loaded to be projected, otherwise an exception is raised. """ if not is_pyresample_loaded: # Not much point in proceeding then return self _channels = set([]) if channels is None: for chn in self.loaded_channels(): _channels |= set([chn]) elif(isinstance(channels, (list, tuple, set))): for chn in channels: try: _channels |= set([self[chn]]) except KeyError: LOG.warning("Channel "+str(chn)+" not found," "thus not projected.") else: raise TypeError("Channels must be a list/" "tuple/set of channel keys!") res = copy.copy(self) if isinstance(dest_area, str): dest_area = mpop.projector.get_area_def(dest_area) res.area = dest_area res.channels = [] if not _channels <= self.loaded_channels(): LOG.warning("Cannot project nonloaded channels: %s." %(_channels - self.loaded_channels())) LOG.info("Will project the other channels though.") _channels = _channels and self.loaded_channels() cov = {} for chn in _channels: if chn.area is None: if self.area is None: area_name = ("swath_" + self.fullname + "_" + str(self.time_slot) + "_" + str(chn.shape)) chn.area = area_name else: if is_pyresample_loaded: try: chn.area = AreaDefinition( self.area.area_id + str(chn.shape), self.area.name, self.area.proj_id, self.area.proj_dict, chn.shape[1], chn.shape[0], self.area.area_extent, self.area.nprocs) except AttributeError: try: dummy = self.area.lons dummy = self.area.lats chn.area = self.area area_name = ("swath_" + self.fullname + "_" + str(self.time_slot) + "_" + str(chn.shape)) chn.area.area_id = area_name except AttributeError: chn.area = self.area + str(chn.shape) else: chn.area = self.area + str(chn.shape) else: #chn.area is not None if is_pyresample_loaded and isinstance(chn.area, SwathDefinition): area_name = ("swath_" + self.fullname + "_" + str(self.time_slot) + "_" + str(chn.shape) + "_" + str(chn.name)) chn.area.area_id = area_name if chn.area == dest_area: res.channels.append(chn) else: if isinstance(chn.area, str): area_id = chn.area else: area_id = chn.area_id or chn.area.area_id if area_id not in cov: if radius is None: if chn.resolution > 0: radius = 5 * chn.resolution else: radius = 10000 cov[area_id] = mpop.projector.Projector(chn.area, dest_area, mode=mode, radius=radius) if precompute: try: cov[area_id].save() except IOError: LOG.exception("Could not save projection.") try: res.channels.append(chn.project(cov[area_id])) except NotLoadedError: LOG.warning("Channel "+str(chn.name)+" not loaded, " "thus not projected.") # Compose with image object try: if res._CompositerClass is not None: # Pass weak ref to compositor to allow garbage collection res.image = res._CompositerClass(weakref.proxy(res)) except AttributeError: pass return res
def __init__(self, in_area, out_area, in_latlons=None, mode=None, radius=10000): # TODO: # - Rework so that in_area and out_area can be lonlats. # - Add a recompute flag ? # Setting up the input area try: self.in_area = get_area_def(in_area) in_id = in_area except (utils.AreaNotFound, AttributeError): if isinstance(in_area, geometry.AreaDefinition): self.in_area = in_area in_id = in_area.area_id elif isinstance(in_area, geometry.SwathDefinition): self.in_area = in_area in_id = in_area.area_id elif in_latlons is not None: self.in_area = geometry.SwathDefinition(lons=in_latlons[0], lats=in_latlons[1]) in_id = in_area else: raise utils.AreaNotFound("Input area " + str(in_area) + " must be defined in " + AREA_FILE + ", be an area object" " or longitudes/latitudes must be " "provided.") # Setting up the output area try: self.out_area = get_area_def(out_area) out_id = out_area except (utils.AreaNotFound, AttributeError): if isinstance(out_area, (geometry.AreaDefinition, geometry.SwathDefinition)): self.out_area = out_area out_id = out_area.area_id else: raise utils.AreaNotFound("Output area " + str(out_area) + " must be defined in " + AREA_FILE + " or " "be an area object.") if self.in_area == self.out_area: return # choosing the right mode if necessary if(mode is None): if (isinstance(in_area, geometry.AreaDefinition) and isinstance(out_area, geometry.AreaDefinition)): self.mode = "quick" else: self.mode = "nearest" else: self.mode = mode filename = (in_id + "2" + out_id + "_" + self.mode + ".npz") projections_directory = "/var/tmp" try: projections_directory = CONF.get("projector", "projections_directory") except ConfigParser.NoSectionError: pass self._filename = os.path.join(projections_directory, filename) if(not os.path.exists(self._filename)): LOG.info("Computing projection from %s to %s..." %(in_id, out_id)) if self.mode == "nearest": valid_index, valid_output_index, index_array, distance_array = \ kd_tree.get_neighbour_info(self.in_area, self.out_area, radius, neighbours=1) del distance_array self._cache = {} self._cache['valid_index'] = valid_index self._cache['valid_output_index'] = valid_output_index self._cache['index_array'] = index_array elif self.mode == "quick": ridx, cidx = \ utils.generate_quick_linesample_arrays(self.in_area, self.out_area) self._cache = {} self._cache['row_idx'] = ridx self._cache['col_idx'] = cidx else: raise ValueError("Unrecognised mode " + str(self.mode) + ".") else: self._cache = {} self._file_cache = np.load(self._filename)
def load(self, channels=None, load_again=False, area_extent=None, **kwargs): """Load instrument data into the *channels*. *Channels* is a list or a tuple containing channels we will load data into, designated by there center wavelength (float), resolution (integer) or name (string). If None, all channels are loaded. The *load_again* boolean flag allows to reload the channels even they have already been loaded, to mirror changes on disk for example. This is false by default. The *area_extent* keyword lets you specify which part of the data to load. Given as a 4-element sequence, it defines the area extent to load in satellite projection. The other keyword arguments are passed as is to the reader plugin. Check the corresponding documentation for more details. """ # Set up the list of channels to load. if channels is None: for chn in self.channels: self.channels_to_load |= set([chn.name]) elif(isinstance(channels, (list, tuple, set))): self.channels_to_load = set() for chn in channels: try: self.channels_to_load |= set([self[chn].name]) except KeyError: self.channels_to_load |= set([chn]) else: raise TypeError("Channels must be a list/" "tuple/set of channel keys!") loaded_channels = [chn.name for chn in self.loaded_channels()] if load_again: for chn in self.channels_to_load: if chn in loaded_channels: self.unload(chn) loaded_channels = [] else: for chn in loaded_channels: self.channels_to_load -= set([chn]) # find the plugin to use from the config file conf = ConfigParser.ConfigParser() try: conf.read(os.path.join(CONFIG_PATH, self.fullname + ".cfg")) if len(conf.sections()) == 0: raise ConfigParser.NoSectionError(("Config file did " "not make sense")) levels = [section for section in conf.sections() if section.startswith(self.instrument_name+"-level")] except ConfigParser.NoSectionError: LOG.warning("Can't load data, no config file for " + self.fullname) self.channels_to_load = set() return levels.sort() if levels[0] == self.instrument_name+"-level1": levels = levels[1:] if len(levels) == 0: raise ConfigParser.NoSectionError( self.instrument_name+"-levelN (N>1) to tell me how to"+ " read data... Not reading anything.") for level in levels: if len(self.channels_to_load) == 0: return LOG.debug("Looking for sources in section "+level) reader_name = conf.get(level, 'format') try: reader_name = eval(reader_name) except NameError: reader_name = str(reader_name) LOG.debug("Using plugin mpop.satin."+reader_name) # read the data reader = "mpop.satin."+reader_name try: reader_instance = self._set_reader(reader_name) if area_extent is not None: if(isinstance(area_extent, (tuple, list)) and len(area_extent) == 4): kwargs["area_extent"] = area_extent else: raise ValueError("Area extent must be a sequence of " "four numbers.") reader_instance.load(self, **kwargs) except ImportError, e: LOG.exception("ImportError while loading "+reader_name+": " + str(e)) continue loaded_channels = set([chn.name for chn in self.loaded_channels()]) just_loaded = loaded_channels & self.channels_to_load if len(just_loaded) == 0: LOG.info("No channels loaded with " + reader + ".") self.channels_to_load -= loaded_channels LOG.debug("Successfully loaded: "+str(just_loaded))
def average(self, downscaling_factor=2, average_window=None): """ Makes a mean convolution of an image. :Parameters: `downscaling_factor` : int image downscaling factor, default is a factor 2. `average_window` : int window size for calculating mean values, default is the same as downscaling_factor. :Returns: `image` : GeoImage mean convoluted image. """ from mpop.imageo.geo_image import GeoImage from pyresample import geometry import scipy.ndimage as ndi self.check_channels(9.65) if average_window == None: average_window = downscaling_factor LOG.info("Downsampling a factor %d and averaging "%downscaling_factor + "in a window of %dx%d"%(average_window, average_window)) ch = self[9.65] # If average window and downscale factor is the same # the following could be used: # # data = data.reshape([shight, hight/shight, # swidth, width/swidth]).mean(3).mean(1) # avg kernel kernel = np.ones((average_window, average_window), dtype=np.float) / \ (average_window*average_window) # do convolution data = ndi.filters.correlate(ch.data.astype(np.float), kernel, mode='nearest') # downscale data = data[1::downscaling_factor, 1::downscaling_factor] # New area, and correct for integer truncation. p_size_x, p_size_y = (ch.area.pixel_size_x*downscaling_factor, ch.area.pixel_size_y*downscaling_factor) area_extent = (ch.area.area_extent[0], ch.area.area_extent[1], ch.area.area_extent[0] + data.shape[1]*p_size_x, ch.area.area_extent[1] + data.shape[0]*p_size_y) area = geometry.AreaDefinition(self._data_holder.satname + self._data_holder.instrument_name + str(area_extent) + str(data.shape), "On-the-fly area", ch.area.proj_id, ch.area.proj_dict, data.shape[1], data.shape[0], area_extent) return GeoImage(data, area, self.time_slot, fill_value=(0,), mode='L')