def compute_vel_mag(prefix, inGridName, inDir): config = MpasAnalysisConfigParser() config.read('mpas_analysis/config.default') outDescriptor = get_comparison_descriptor(config, 'antarctic') outGridName = outDescriptor.meshName description = 'Monthly velocity magnitude climatologies from ' \ '2005-2010 average of the Southern Ocean State ' \ 'Estimate (SOSE)' botDescription = 'Monthly velocity magnitude climatologies at sea ' \ 'floor from 2005-2010 average from SOSE' for gridName in [outGridName]: outFileName = '{}_vel_mag_{}.nc'.format(prefix, gridName) uFileName = '{}_zonal_vel_{}.nc'.format(prefix, gridName) vFileName = '{}_merid_vel_{}.nc'.format(prefix, gridName) if not os.path.exists(outFileName): with xarray.open_dataset(uFileName) as dsU: with xarray.open_dataset(vFileName) as dsV: dsVelMag = dsU.drop(['zonalVel', 'botZonalVel']) dsVelMag['velMag'] = xarray.ufuncs.sqrt(dsU.zonalVel**2 + dsV.meridVel**2) dsVelMag.velMag.attrs['units'] = 'm s$^{-1}$' dsVelMag.velMag.attrs['description'] = description dsVelMag['botVelMag'] = xarray.ufuncs.sqrt( dsU.botZonalVel**2 + dsV.botMeridVel**2) dsVelMag.botVelMag.attrs['units'] = 'm s$^{-1}$' dsVelMag.botVelMag.attrs['description'] = botDescription write_netcdf(dsVelMag, outFileName)
def _cache_individual_climatologies(ds, cacheInfo, printProgress, yearsPerCacheFile, monthValues, calendar): # {{{ ''' Cache individual climatologies for later aggregation. ''' # Authors # ------- # Xylar Asay-Davis for cacheIndex, info in enumerate(cacheInfo): outputFileClimo, done, yearString = info if done: continue dsYear = ds.where(ds.cacheIndices == cacheIndex, drop=True) if printProgress: print(' {}'.format(yearString)) totalDays = dsYear.daysInMonth.sum(dim='Time').values monthCount = dsYear.dims['Time'] climatology = compute_climatology(dsYear, monthValues, calendar, maskVaries=False) climatology.attrs['totalDays'] = totalDays climatology.attrs['totalMonths'] = monthCount climatology.attrs['fingerprintClimo'] = fingerprint_generator() write_netcdf(climatology, outputFileClimo) climatology.close()
def compute_vel_mag(prefix, inGridName, inDir, outGridName): description = 'Monthly velocity magnitude climatologies from ' \ '2005-2010 average of the Southern Ocean State ' \ 'Estimate (SOSE)' botDescription = 'Monthly velocity magnitude climatologies at sea ' \ 'floor from 2005-2010 average from SOSE' for gridName in [outGridName]: outFileName = '{}_vel_mag_{}.nc'.format(prefix, gridName) uFileName = '{}_zonal_vel_{}.nc'.format(prefix, gridName) vFileName = '{}_merid_vel_{}.nc'.format(prefix, gridName) if not os.path.exists(outFileName): with xarray.open_dataset(uFileName) as dsU: with xarray.open_dataset(vFileName) as dsV: dsVelMag = dsU.drop(['zonalVel', 'botZonalVel']) dsVelMag['velMag'] = numpy.sqrt(dsU.zonalVel**2 + dsV.meridVel**2) dsVelMag.velMag.attrs['units'] = 'm s$^{-1}$' dsVelMag.velMag.attrs['description'] = description dsVelMag['botVelMag'] = numpy.sqrt(dsU.botZonalVel**2 + dsV.botMeridVel**2) dsVelMag.botVelMag.attrs['units'] = 'm s$^{-1}$' dsVelMag.botVelMag.attrs['description'] = botDescription write_netcdf(dsVelMag, outFileName)
def run_task(self): # {{{ """ Combine the time series """ # Authors # ------- # Xylar Asay-Davis outputDirectory = '{}/transport/'.format( build_config_full_path(self.config, 'output', 'timeseriesSubdirectory')) outFileName = '{}/transport_{:04d}-{:04d}.nc'.format( outputDirectory, self.startYears[0], self.endYears[-1]) if not os.path.exists(outFileName): inFileNames = [] for startYear, endYear in zip(self.startYears, self.endYears): inFileName = '{}/transport_{:04d}-{:04d}.nc'.format( outputDirectory, startYear, endYear) inFileNames.append(inFileName) ds = xarray.open_mfdataset(inFileNames, combine='nested', concat_dim='Time', decode_times=False) ds.load() write_netcdf(ds, outFileName)
def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. """ # Authors # ------- # Xylar Asay-Davis # call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, # self.namelist, self.runStreams, self.historyStreams, # self.calendar super(RemapObservedClimatologySubtask, self).setup_and_check() # we set up the remappers here because ESFM_RegridWeightGen seems to # have trouble if it runs in another process (or in several at once) self._setup_remappers(self.fileName) # build the observational data set and write it out to a file, to # be read back in during the run_task() phase obsFileName = self.get_file_name(stage='original') if not os.path.exists(obsFileName): ds = self.build_observational_dataset(self.fileName) write_netcdf(ds, obsFileName)
def run_task(self): # {{{ """ Performs analysis of ocean heat content (OHC) from time-series output. """ # Authors # ------- # Xylar Asay-Davis, Milena Veneziani, Greg Streletz self.logger.info("\nComputing anomalies...") config = self.config ds = xarray.open_dataset(self.inFileName) dsStart = ds.isel(Time=slice(0, self.movingAverageMonths)).mean('Time') for variable in ds.data_vars: ds[variable] = ds[variable] - dsStart[variable] outFileName = self.outFileName if not os.path.isabs(outFileName): baseDirectory = build_config_full_path(config, 'output', 'timeSeriesSubdirectory') outFileName = '{}/{}'.format(baseDirectory, outFileName) write_netcdf(ds, outFileName) # }}}
def compute_lon_lat_region_masks(geojsonFileName, lon, lat, maskFileName, featureList=None, logger=None, processCount=1, chunkSize=1000, showProgress=True, lonDim='lon', latDim='lat'): """ Build a region mask file from the given lon, lat and geojson file defining a set of regions. """ if os.path.exists(maskFileName): return nLon = len(lon) nLat = len(lat) # make sure -180 <= lon < 180 lon = numpy.mod(lon + 180., 360.) - 180. if lonDim != latDim: lon, lat = numpy.meshgrid(lon, lat) # create shapely geometry for lonCell and latCell cellPoints = [shapely.geometry.Point(x, y) for x, y in zip(lon.ravel(), lat.ravel())] regionNames, masks, properties, nChar = compute_region_masks( geojsonFileName, cellPoints, maskFileName, featureList, logger, processCount, chunkSize, showProgress) # create a new data array for masks and another for mask names if logger is not None: logger.info(' Creating and writing masks dataset...') nRegions = len(regionNames) dsMasks = xr.Dataset() if lonDim == latDim: dsMasks['regionCellMasks'] = (('nRegions', lonDim), numpy.zeros((nRegions, nLon), dtype=bool)) else: dsMasks['regionCellMasks'] = (('nRegions', latDim, lonDim), numpy.zeros((nRegions, nLat, nLon), dtype=bool)) dsMasks['regionNames'] = (('nRegions'), numpy.zeros((nRegions), dtype='|S{}'.format(nChar))) for index in range(nRegions): regionName = regionNames[index] mask = masks[index] if lonDim == latDim: dsMasks['regionCellMasks'][index, :] = mask else: dsMasks['regionCellMasks'][index, :] = mask.reshape([nLat, nLon]) dsMasks['regionNames'][index] = regionName for propertyName in properties: dsMasks['{}Regions'.format(propertyName)] = \ (('nRegions'), properties[propertyName]) write_netcdf(dsMasks, maskFileName)
def _remap(self, inFileName, outFileName, remapper, comparisonGridName, season): # {{{ """ Performs remapping either using ``ncremap`` or the native python code, depending on the requested setting and the comparison grid Parameters ---------- inFileName : str The name of the input file to be remapped. outFileName : str The name of the output file to which the remapped data set should be written. remapper : ``Remapper`` object A remapper that can be used to remap files or data sets to a comparison grid. comparisonGridNames : {'latlon', 'antarctic'} The name of the comparison grid to use for remapping. season : str The name of the season to be remapped """ # Authors # ------- # Xylar Asay-Davis if remapper.mappingFileName is None: # no remapping is needed return renormalizationThreshold = self.config.getfloat( 'climatology', 'renormalizationThreshold') # ncremap doesn't support grids other than lat/lon if self.useNcremap and comparisonGridName == 'latlon': remapper.remap_file(inFileName=inFileName, outFileName=outFileName, overwrite=True, renormalize=renormalizationThreshold, logger=self.logger) remappedClimatology = xr.open_dataset(outFileName) remappedClimatology.load() remappedClimatology.close() else: climatologyDataSet = xr.open_dataset(inFileName) remappedClimatology = remapper.remap(climatologyDataSet, renormalizationThreshold) # customize (if this function has been overridden) remappedClimatology = self.customize_remapped_climatology( remappedClimatology, comparisonGridName, season) write_netcdf(remappedClimatology, outFileName) # }}}
def sose_volume_to_nc(prefix, inGridName, inGridFileName, inDir): outFileName = '{}_volume_{}.nc'.format(prefix, inGridName) matGrid = loadmat(inGridFileName) # lat/lon is a tensor grid so we can use 1-D arrays lon = matGrid['XC'][:, 0] lat = matGrid['YC'][0, :] z = matGrid['RC'][:, 0] area = matGrid['RAC'] dz = matGrid['DRF'][:, 0] cellFraction = matGrid['hFacC'] volume = numpy.zeros(cellFraction.shape) for zIndex in range(len(dz)): volume[:, :, zIndex] = cellFraction[:, :, zIndex] * dz[zIndex] * area volume = volume.transpose(1, 0, 2) dictonary = { 'dims': ['lon', 'lat', 'z'], 'coords': { 'lon': { 'dims': ('lon'), 'data': lon, 'attrs': { 'units': 'degrees' } }, 'lat': { 'dims': ('lat'), 'data': lat, 'attrs': { 'units': 'degrees' } }, 'z': { 'dims': ('z'), 'data': z, 'attrs': { 'units': 'm' } } }, 'data_vars': { 'volume': { 'dims': ('lat', 'lon', 'z'), 'data': volume, 'attrs': { 'units': 'm$^3$', 'description': 'cell volumes' } } } } dsVolume = xarray.Dataset.from_dict(dictonary) write_netcdf(dsVolume, outFileName)
def _compute_area_vol(self): # {{{ ''' Compute part of the time series of sea ice volume and area, given time indices to process. ''' outFileNames = {} for hemisphere in ['NH', 'SH']: baseDirectory = build_config_full_path(self.config, 'output', 'timeSeriesSubdirectory') make_directories(baseDirectory) outFileName = '{}/seaIceAreaVol{}.nc'.format( baseDirectory, hemisphere) outFileNames[hemisphere] = outFileName dsTimeSeries = {} dsMesh = xr.open_dataset(self.restartFileName) dsMesh = subset_variables(dsMesh, variableList=['latCell', 'areaCell']) # Load data ds = open_mpas_dataset(fileName=self.inputFile, calendar=self.calendar, variableList=self.variableList, startDate=self.startDate, endDate=self.endDate) for hemisphere in ['NH', 'SH']: if hemisphere == 'NH': mask = dsMesh.latCell > 0 else: mask = dsMesh.latCell < 0 dsAreaSum = (ds.where(mask) * dsMesh.areaCell).sum('nCells') dsAreaSum = dsAreaSum.rename({ 'timeMonthly_avg_iceAreaCell': 'iceArea', 'timeMonthly_avg_iceVolumeCell': 'iceVolume' }) dsAreaSum['iceThickness'] = (dsAreaSum.iceVolume / dsMesh.areaCell.sum('nCells')) dsAreaSum['iceArea'].attrs['units'] = 'm$^2$' dsAreaSum['iceArea'].attrs['description'] = \ 'Total {} sea ice area'.format(hemisphere) dsAreaSum['iceVolume'].attrs['units'] = 'm$^3$' dsAreaSum['iceVolume'].attrs['description'] = \ 'Total {} sea ice volume'.format(hemisphere) dsAreaSum['iceThickness'].attrs['units'] = 'm' dsAreaSum['iceThickness'].attrs['description'] = \ 'Mean {} sea ice volume'.format(hemisphere) dsTimeSeries[hemisphere] = dsAreaSum write_netcdf(dsAreaSum, outFileNames[hemisphere]) return dsTimeSeries # }}}
def compute_mpas_region_masks(geojsonFileName, meshFileName, maskFileName, featureList=None, logger=None, processCount=1, chunkSize=1000, showProgress=True, useMpasMaskCreator=False, dir=None): """ Build a region mask file from the given MPAS mesh and geojson file defining a set of regions. """ if os.path.exists(maskFileName): return if useMpasMaskCreator: dsMesh = xr.open_dataset(meshFileName) fcMask = read_feature_collection(geojsonFileName) dsMasks = mpas_tools.conversion.mask(dsMesh=dsMesh, fcMask=fcMask, logger=logger, dir=dir) else: with xr.open_dataset(meshFileName) as dsMesh: dsMesh = dsMesh[['lonCell', 'latCell']] latCell = numpy.rad2deg(dsMesh.latCell.values) # transform longitudes to [-180, 180) lonCell = numpy.mod(numpy.rad2deg(dsMesh.lonCell.values) + 180., 360.) - 180. # create shapely geometry for lonCell and latCell cellPoints = [shapely.geometry.Point(x, y) for x, y in zip(lonCell, latCell)] regionNames, masks, properties, nChar = compute_region_masks( geojsonFileName, cellPoints, maskFileName, featureList, logger, processCount, chunkSize, showProgress) nCells = len(cellPoints) # create a new data array for masks and another for mask names if logger is not None: logger.info(' Creating and writing masks dataset...') nRegions = len(regionNames) dsMasks = xr.Dataset() dsMasks['regionCellMasks'] = (('nRegions', 'nCells'), numpy.zeros((nRegions, nCells), dtype=bool)) dsMasks['regionNames'] = (('nRegions'), numpy.zeros((nRegions), dtype='|S{}'.format(nChar))) for index in range(nRegions): regionName = regionNames[index] mask = masks[index] dsMasks['regionCellMasks'][index, :] = mask dsMasks['regionNames'][index] = regionName for propertyName in properties: dsMasks[propertyName] = (('nRegions'), properties[propertyName]) write_netcdf(dsMasks, maskFileName)
def run_task(self): # {{{ """ Performs remapping of obsrevations to the comparsion grid """ # Authors # ------- # Xylar Asay-Davis config = self.config obsFileName = self.get_file_name(stage='original') if not os.path.isfile(obsFileName): raise OSError('Obs file {} not found.'.format(obsFileName)) for comparisonGridName in self.comparisonGridNames: for season in self.seasons: remappedFileName = self.get_file_name( stage='remapped', season=season, comparisonGridName=comparisonGridName) if not os.path.exists(remappedFileName): ds = xr.open_dataset(obsFileName) climatologyFileName = self.get_file_name( stage='climatology', season=season, comparisonGridName=comparisonGridName) if 'month' in ds.variables.keys() and \ 'year' in ds.variables.keys(): # this data set is not yet a climatology, so compute # the climatology monthValues = constants.monthDictionary[season] seasonalClimatology = compute_climatology( ds, monthValues, maskVaries=True) else: # We don't have month or year arrays to compute a # climatology so assume this already is one seasonalClimatology = ds write_netcdf(seasonalClimatology, climatologyFileName) remapper = self.remappers[comparisonGridName] if remapper.mappingFileName is None: # no need to remap because the observations are on the # comparison grid already os.symlink(climatologyFileName, remappedFileName) else: remap_and_write_climatology(config, seasonalClimatology, climatologyFileName, remappedFileName, remapper, logger=self.logger)
def _mask_climatologies(self, season, dsMask): # {{{ ''' For each season, creates a masked version of the climatology Parameters ---------- season : str The name of the season to be masked dsMask : ``xarray.Dataset`` object A data set (from the first input file) that can be used to determine the mask in MPAS output files. Author ------ Xylar Asay-Davis ''' climatologyFileName = self.mpasClimatologyTask.get_file_name(season) maskedClimatologyFileName = self.get_masked_file_name(season) if not os.path.exists(maskedClimatologyFileName): # slice and mask the data set climatology = xr.open_dataset(climatologyFileName) climatology = mpas_xarray.subset_variables(climatology, self.variableList) iselValues = {} if 'Time' in climatology.dims: iselValues['Time'] = 0 if self.iselValues is not None: iselValues.update(self.iselValues) # select only Time=0 and possibly only the desired vertical # slice if len(iselValues.keys()) > 0: climatology = climatology.isel(**iselValues) # add valid mask as a variable, useful for remapping later climatology['validMask'] = \ xr.DataArray(numpy.ones(climatology.dims['nCells']), dims=['nCells']) # mask the data set for variableName in self.variableList: climatology[variableName] = \ climatology[variableName].where( dsMask[variableName] != self._fillValue) # customize (if this function has been overridden) climatology = self.customize_masked_climatology( climatology, season) write_netcdf(climatology, maskedClimatologyFileName)
def compute_pot_density(prefix, inGridName, inDir): config = MpasAnalysisConfigParser() config.read('mpas_analysis/config.default') outDescriptor = get_comparison_descriptor(config, 'antarctic') outGridName = outDescriptor.meshName description = 'Monthly potential density climatologies from ' \ '2005-2010 average of the Southern Ocean State ' \ 'Estimate (SOSE)' botDescription = 'Monthly potential density climatologies at sea ' \ 'floor from 2005-2010 average from SOSE' for gridName in [inGridName, outGridName]: outFileName = '{}_pot_den_{}.nc'.format(prefix, gridName) TFileName = '{}_pot_temp_{}.nc'.format(prefix, gridName) SFileName = '{}_salinity_{}.nc'.format(prefix, gridName) if not os.path.exists(outFileName): with xarray.open_dataset(TFileName) as dsT: with xarray.open_dataset(SFileName) as dsS: dsPotDensity = dsT.drop(['theta', 'botTheta']) lat, lon, z = xarray.broadcast(dsS.lat, dsS.lon, dsS.z) pressure = gsw.p_from_z(z.values, lat.values) SA = gsw.SA_from_SP(dsS.salinity.values, pressure, lon.values, lat.values) CT = gsw.CT_from_pt(SA, dsT.theta.values) dsPotDensity['potentialDensity'] = (dsS.salinity.dims, gsw.rho(SA, CT, 0.)) dsPotDensity.potentialDensity.attrs['units'] = \ 'kg m$^{-3}$' dsPotDensity.potentialDensity.attrs['description'] = \ description lat, lon, z = xarray.broadcast(dsS.lat, dsS.lon, dsS.zBot) pressure = gsw.p_from_z(z.values, lat.values) SA = gsw.SA_from_SP(dsS.botSalinity.values, pressure, lon.values, lat.values) CT = gsw.CT_from_pt(SA, dsT.botTheta.values) dsPotDensity['botPotentialDensity'] = \ (dsS.botSalinity.dims, gsw.rho(SA, CT, 0.)) dsPotDensity.botPotentialDensity.attrs['units'] = \ 'kg m$^{-3}$' dsPotDensity.botPotentialDensity.attrs['description'] = \ botDescription write_netcdf(dsPotDensity, outFileName)
def compute_mpas_transect_masks(geojsonFileName, meshFileName, maskFileName, logger=None): """ Build a transect mask file from the given MPAS mesh and geojson file \ defining a set of transects. """ if os.path.exists(maskFileName): return dsMesh = xr.open_dataset(meshFileName) fcMask = read_feature_collection(geojsonFileName) dsMask = mpas_tools.conversion.mask(dsMesh=dsMesh, fcMask=fcMask, logger=logger) write_netcdf(dsMask, maskFileName)
def run_task(self): # {{{ """ Performs analysis of ocean heat content (OHC) from time-series output. """ # Authors # ------- # Xylar Asay-Davis, Milena Veneziani, Greg Streletz self.logger.info("\nComputing anomalies...") config = self.config startDate = config.get('timeSeries', 'startDate') endDate = config.get('timeSeries', 'endDate') if config.has_option('timeSeries', 'anomalyRefYear'): anomalyYear = config.getint('timeSeries', 'anomalyRefYear') anomalyRefDate = '{:04d}-01-01_00:00:00'.format(anomalyYear) anomalyEndDate = '{:04d}-12-31_23:59:59'.format(anomalyYear) else: anomalyRefDate = get_simulation_start_time(self.runStreams) anomalyYear = int(anomalyRefDate[0:4]) anomalyEndDate = '{:04d}-12-31_23:59:59'.format(anomalyYear) ds = compute_moving_avg_anomaly_from_start( timeSeriesFileName=self.inputFile, variableList=self.variableList, anomalyStartTime=anomalyRefDate, anomalyEndTime=anomalyEndDate, startDate=startDate, endDate=endDate, calendar=self.calendar, movingAveragePoints=self.movingAveragePoints, alter_dataset=self.alter_dataset) outFileName = self.outFileName if not os.path.isabs(outFileName): baseDirectory = build_config_full_path( config, 'output', 'timeSeriesSubdirectory') outFileName = '{}/{}'.format(baseDirectory, outFileName) write_netcdf(ds, outFileName) # }}}
def remap_v(prefix, inGridName, inGridFileName, inDir, inVPrefix): cacheVFileName = '{}_merid_vel_{}.nc'.format(prefix, inGridName) config = MpasAnalysisConfigParser() config.read('mpas_analysis/config.default') matGrid = loadmat(inGridFileName) # lat/lon is a tensor grid so we can use 1-D arrays lon = matGrid['XC'][:, 0] lat = matGrid['YG'][0, :] z = matGrid['RC'][:, 0] cellFraction = matGrid['hFacS'] botIndices = get_bottom_indices(cellFraction) with sose_v_to_nc('{}/{}'.format(inDir, inVPrefix), cacheVFileName, lon, lat, z, cellFraction, botIndices) \ as dsV: inDescriptor = LatLonGridDescriptor() inDescriptor = LatLonGridDescriptor.read(cacheVFileName, latVarName='lat', lonVarName='lon') outDescriptor = get_comparison_descriptor(config, 'antarctic') outGridName = outDescriptor.meshName outVFileName = '{}_merid_vel_{}.nc'.format(prefix, outGridName) mappingFileName = '{}/map_V_{}_to_{}.nc'.format( inDir, inGridName, outGridName) remapper = Remapper(inDescriptor, outDescriptor, mappingFileName) remapper.build_mapping_file(method='bilinear') if not os.path.exists(outVFileName): print('Remapping meridional velocity...') with remapper.remap(dsV, renormalizationThreshold=0.01) \ as remappedV: print('Done.') remappedV.attrs['history'] = ' '.join(sys.argv) write_netcdf(remappedV, outVFileName)
def remap(ds, outDescriptor, mappingFileName, inDir, outFileName): tempFileName1 = '{}/temp_transpose.nc'.format(inDir) tempFileName2 = '{}/temp_remap.nc'.format(inDir) if 'z' in ds: print(' transposing and fixing periodicity...') ds = ds.chunk({'Time': 4}) ds = ds.transpose('Time', 'z', 'lat', 'lon') ds = add_periodic_lon(ds) write_netcdf(ds, tempFileName1) ds.close() inDescriptor = LatLonGridDescriptor.read(tempFileName1, latVarName='lat', lonVarName='lon') remapper = Remapper(inDescriptor, outDescriptor, mappingFileName) remapper.build_mapping_file(method='bilinear') remapper.remap_file(inFileName=tempFileName1, outFileName=tempFileName2, overwrite=True, renormalize=0.01) ds = xarray.open_dataset(tempFileName2) if 'z' in ds: print(' transposing back...') ds = ds.chunk({'Time': 4}) ds = ds.transpose('Time', 'x', 'y', 'z', 'nvertices') ds.attrs['meshName'] = outDescriptor.meshName for coord in ['x', 'y']: ds.coords[coord] = xarray.DataArray.from_dict( outDescriptor.coords[coord]) ds = ds.set_coords(names=['month', 'year']) write_netcdf(ds, outFileName) ds.close()
def run_task(self): # {{{ """ Combine the time series """ # Authors # ------- # Xylar Asay-Davis regionGroup = self.regionGroup timeSeriesName = regionGroup[0].lower() + \ regionGroup[1:].replace(' ', '') outputDirectory = '{}/{}/'.format( build_config_full_path(self.config, 'output', 'timeseriesSubdirectory'), timeSeriesName) outFileName = '{}/{}_{:04d}-{:04d}.nc'.format(outputDirectory, timeSeriesName, self.startYears[0], self.endYears[-1]) if not os.path.exists(outFileName): inFileNames = [] for startYear, endYear in zip(self.startYears, self.endYears): inFileName = '{}/{}_{:04d}-{:04d}.nc'.format( outputDirectory, timeSeriesName, startYear, endYear) inFileNames.append(inFileName) ds = xarray.open_mfdataset(inFileNames, combine='nested', concat_dim='Time', decode_times=False) ds.load() # a few variables have become time dependent and shouldn't be for var in ['totalArea', 'zbounds']: ds[var] = ds[var].isel(Time=0, drop=True) write_netcdf(ds, outFileName)
def get_observations(self): # {{{ ''' Read in and set up the observations. Returns ------- obsDatasets : OrderedDict The observational dataset ''' # Authors # ------- # Xylar Asay-Davis obsDatasets = OrderedDict() for name in self.obsFileNames: outFileName = self.get_out_file_name(name) if os.path.exists(outFileName): dsObs = xr.open_dataset(outFileName) dsObs.load() else: dsObs = self.build_observational_dataset( self.obsFileNames[name], name) dsObs.load() # make sure lat and lon are coordinates for coord in ['lon', 'lat']: dsObs.coords[coord] = dsObs[coord] if self.horizontalResolution == 'obs': dsObs = self._add_distance(dsObs) else: dsObs = self._subdivide_observations(dsObs) write_netcdf(dsObs, outFileName) obsDatasets[name] = dsObs return obsDatasets # }}}
def remap(inDir, outDir): inGridName = 'SouthernOcean_0.25x0.125degree' inFileName = '{}/Schmidtko_et_al_2014_bottom_PT_S_PD_{}.nc'.format( inDir, inGridName) config = MpasAnalysisConfigParser() config.read('mpas_analysis/config.default') inDescriptor = LatLonGridDescriptor() inDescriptor = LatLonGridDescriptor.read(inFileName, latVarName='lat', lonVarName='lon') outDescriptor = get_comparison_descriptor(config, 'antarctic') outGridName = outDescriptor.meshName outFileName = '{}/Schmidtko_et_al_2014_bottom_PT_S_PD_{}.nc'.format( outDir, outGridName) mappingFileName = '{}/map_{}_to_{}.nc'.format(inDir, inGridName, outGridName) remapper = Remapper(inDescriptor, outDescriptor, mappingFileName) remapper.build_mapping_file(method='bilinear') if not os.path.exists(outFileName): print('Remapping...') with xarray.open_dataset(inFileName) as dsIn: with remapper.remap(dsIn, renormalizationThreshold=0.01) \ as remappedMLD: print('Done.') remappedMLD.attrs['history'] = ' '.join(sys.argv) write_netcdf(remappedMLD, outFileName)
def _write_obs_t_s(self, obsDict, zmin, zmax): # {{{ obsSection = '{}Observations'.format(self.componentName) climatologyDirectory = build_config_full_path( config=self.config, section='output', relativePathOption='climatologySubdirectory', relativePathSection=obsSection) outFileName = '{}/TS_{}_{}_{}.nc'.format(climatologyDirectory, obsDict['suffix'], self.prefix, self.season) if os.path.exists(outFileName): return with dask.config.set(schedular='threads', pool=ThreadPool(self.daskThreads)): chunk = {obsDict['latVar']: 400, obsDict['lonVar']: 400} regionMaskFileName = obsDict['maskTask'].maskFileName dsRegionMask = \ xarray.open_dataset(regionMaskFileName).chunk(chunk).stack( nCells=(obsDict['latVar'], obsDict['lonVar'])) dsRegionMask = dsRegionMask.reset_index('nCells').drop_vars( [obsDict['latVar'], obsDict['lonVar']]) maskRegionNames = decode_strings(dsRegionMask.regionNames) regionIndex = maskRegionNames.index(self.regionName) dsMask = dsRegionMask.isel(nRegions=regionIndex) cellMask = dsMask.regionCellMasks == 1 TVarName = obsDict['TVar'] SVarName = obsDict['SVar'] zVarName = obsDict['zVar'] volVarName = obsDict['volVar'] obsFileName = obsDict['climatologyTask'][self.season].fileName ds = xarray.open_dataset(obsFileName, chunks=chunk) ds = ds.stack(nCells=(obsDict['latVar'], obsDict['lonVar'])) ds = ds.reset_index('nCells').drop_vars( [obsDict['latVar'], obsDict['lonVar']]) ds = ds.where(cellMask, drop=True) cellsChunk = 32768 chunk = {'nCells': cellsChunk} ds = ds.chunk(chunk) depthMask = numpy.logical_and(ds[zVarName] >= zmin, ds[zVarName] <= zmax) ds = ds.where(depthMask) ds.compute() T = ds[TVarName].values.ravel() mask = numpy.isfinite(T) T = T[mask] S = ds[SVarName].values.ravel()[mask] z = ds['zBroadcast'].values.ravel()[mask] volume = ds[volVarName].values.ravel()[mask] dsOut = xarray.Dataset() dsOut['T'] = ('nPoints', T) dsOut['S'] = ('nPoints', S) dsOut['z'] = ('nPoints', z) dsOut['volume'] = ('nPoints', volume) dsOut['zbounds'] = ('nBounds', [zmin, zmax]) write_netcdf(dsOut, outFileName)
def remap_pt_s(prefix, inGridName, inGridFileName, inDir, inTPrefix, inSPrefix, inGammaNPrefix): cacheTFileName = '{}_pot_temp_{}.nc'.format(prefix, inGridName) cacheSFileName = '{}_salinity_{}.nc'.format(prefix, inGridName) cacheGammaNFileName = '{}_neut_den_{}.nc'.format(prefix, inGridName) config = MpasAnalysisConfigParser() config.read('mpas_analysis/config.default') matGrid = loadmat(inGridFileName) # lat/lon is a tensor grid so we can use 1-D arrays lon = matGrid['XC'][:, 0] lat = matGrid['YC'][0, :] z = matGrid['RC'][:, 0] cellFraction = matGrid['hFacC'] botIndices = get_bottom_indices(cellFraction) with sose_pt_to_nc('{}/{}'.format(inDir, inTPrefix), cacheTFileName, lon, lat, z, cellFraction, botIndices) \ as dsT: inDescriptor = LatLonGridDescriptor() inDescriptor = LatLonGridDescriptor.read(cacheTFileName, latVarName='lat', lonVarName='lon') outDescriptor = get_comparison_descriptor(config, 'antarctic') outGridName = outDescriptor.meshName outTFileName = '{}_pot_temp_{}.nc'.format(prefix, outGridName) outSFileName = '{}_salinity_{}.nc'.format(prefix, outGridName) outGammaNFileName = '{}_neut_den_{}.nc'.format(prefix, outGridName) mappingFileName = '{}/map_C_{}_to_{}.nc'.format( inDir, inGridName, outGridName) remapper = Remapper(inDescriptor, outDescriptor, mappingFileName) remapper.build_mapping_file(method='bilinear') if not os.path.exists(outTFileName): dsT.reset_coords(names='zBot', inplace=True) print('Remapping potential temperature...') with remapper.remap(dsT, renormalizationThreshold=0.01) \ as remappedT: print('Done.') remappedT.attrs['history'] = ' '.join(sys.argv) remappedT.set_coords(names='zBot', inplace=True) write_netcdf(remappedT, outTFileName) with sose_s_to_nc('{}/{}'.format(inDir, inSPrefix), cacheSFileName, lon, lat, z, cellFraction, botIndices) \ as dsS: if not os.path.exists(outSFileName): dsS.reset_coords(names='zBot', inplace=True) print('Remapping salinity...') with remapper.remap(dsS, renormalizationThreshold=0.01) \ as remappedS: print('Done.') remappedS.attrs['history'] = ' '.join(sys.argv) remappedS.set_coords(names='zBot', inplace=True) write_netcdf(remappedS, outSFileName) with sose_gammaN_to_nc('{}/{}'.format(inDir, inGammaNPrefix), cacheGammaNFileName, lon, lat, z, cellFraction, botIndices) \ as dsGammaN: if not os.path.exists(outGammaNFileName): dsGammaN.reset_coords(names='zBot', inplace=True) print('Remapping neutral density...') with remapper.remap(dsGammaN, renormalizationThreshold=0.01) \ as remappedGammaN: print('Done.') remappedGammaN.attrs['history'] = ' '.join(sys.argv) remappedGammaN.set_coords(names='zBot', inplace=True) write_netcdf(remappedGammaN, outGammaNFileName)
def sose_v_to_nc(inPrefix, outFileName, lon, lat, z, cellFraction, botIndices): if os.path.exists(outFileName): dsV = xarray.open_dataset(outFileName) else: print('Building climatology of meridional velocity...') field, botField = get_monthly_average_3d(inPrefix, cellFraction, botIndices) print('Done.') zBot = numpy.ma.masked_array(z[botIndices], mask=(botIndices == -1)) zBot = zBot.transpose(1, 0) description = 'Monthly meridional velocity climatologies from ' \ '2005-2010 average of the Southern Ocean State ' \ 'Estimate (SOSE)' botDescription = 'Monthly meridional velocity climatologies at sea ' \ 'floor from 2005-2010 average from SOSE' dictonary = { 'dims': ['Time', 'lon', 'lat', 'z'], 'coords': { 'month': { 'dims': ('Time'), 'data': range(1, 13), 'attrs': { 'units': 'months' } }, 'year': { 'dims': ('Time'), 'data': numpy.ones(12), 'attrs': { 'units': 'years' } }, 'lon': { 'dims': ('lon'), 'data': lon, 'attrs': { 'units': 'degrees' } }, 'lat': { 'dims': ('lat'), 'data': lat, 'attrs': { 'units': 'degrees' } }, 'z': { 'dims': ('z'), 'data': z, 'attrs': { 'units': 'm' } }, 'zBot': { 'dims': ('lat', 'lon'), 'data': zBot, 'attrs': { 'units': 'm' } } }, 'data_vars': { 'meridVel': { 'dims': ('Time', 'lat', 'lon', 'z'), 'data': field, 'attrs': { 'units': 'm s$^{-1}$', 'description': description } }, 'botMeridVel': { 'dims': ('Time', 'lat', 'lon'), 'data': botField, 'attrs': { 'units': 'm s$^{-1}$', 'description': botDescription } } } } dsV = xarray.Dataset.from_dict(dictonary) write_netcdf(dsV, outFileName) return dsV
def sose_mld_to_nc(inPrefix, outFileName, lon, lat, botIndices): if os.path.exists(outFileName): dsMLD = xarray.open_dataset(outFileName) else: print('Building climatology of mixed layer depth...') field = get_monthly_average_2d(inPrefix, botIndices) # make MLD positive field = -field print('Done.') description = 'Monthly mixed layer depth climatologies from ' \ '2005-2010 average of the Southern Ocean State ' \ 'Estimate (SOSE)' dictonary = { 'dims': ['Time', 'lon', 'lat'], 'coords': { 'month': { 'dims': ('Time'), 'data': range(1, 13), 'attrs': { 'units': 'months' } }, 'year': { 'dims': ('Time'), 'data': numpy.ones(12), 'attrs': { 'units': 'years' } }, 'lon': { 'dims': ('lon'), 'data': lon, 'attrs': { 'units': 'degrees' } }, 'lat': { 'dims': ('lat'), 'data': lat, 'attrs': { 'units': 'degrees' } } }, 'data_vars': { 'mld': { 'dims': ('Time', 'lat', 'lon'), 'data': field, 'attrs': { 'units': 'm', 'description': description } } } } dsMLD = xarray.Dataset.from_dict(dictonary) write_netcdf(dsMLD, outFileName) return dsMLD
def combine_observations(self): # {{{ ''' Combine SOSE oservations into a single file ''' # Authors # ------- # Xylar Asay-Davis config = self.config longitudes = sorted( config.getExpression('soseTransects', 'longitudes', usenumpyfunc=True)) observationsDirectory = build_obs_path(config, 'ocean', 'soseSubdirectory') outObsDirectory = build_config_full_path( config=config, section='output', relativePathOption='climatologySubdirectory', relativePathSection='oceanObservations') make_directories(outObsDirectory) combinedFileName = '{}/{}.nc'.format(outObsDirectory, self.transectCollectionName) obsFileNames = OrderedDict() for lon in longitudes: transectName = 'lon_{}'.format(lon) obsFileNames[transectName] = combinedFileName self.obsFileNames = obsFileNames if os.path.exists(combinedFileName): return print('Preprocessing SOSE transect data...') minLat = config.getfloat('soseTransects', 'minLat') maxLat = config.getfloat('soseTransects', 'maxLat') dsObs = None for field in self.fields: prefix = field['obsFilePrefix'] fieldName = field['obsFieldName'] if prefix is None: continue print(' {}'.format(field['prefix'])) fileName = '{}/SOSE_2005-2010_monthly_{}_SouthernOcean' \ '_0.167x0.167degree_20180710.nc'.format( observationsDirectory, prefix) dsLocal = xr.open_dataset(fileName) lat = dsLocal.lat.values mask = numpy.logical_and(lat >= minLat, lat <= maxLat) indices = numpy.argwhere(mask) dsLocal = dsLocal.isel(lat=slice(indices[0][0], indices[-1][0])) dsLocal.load() if fieldName == 'zonalVel': # need to average in longitude nLon = dsLocal.sizes['lon'] lonIndicesP1 = numpy.mod(numpy.arange(nLon) + 1, nLon) dsLocal = 0.5 * (dsLocal + dsLocal.isel(lon=lonIndicesP1)) if fieldName == 'meridVel': # need to average in latitude nLat = dsLocal.sizes['lat'] latIndicesP1 = numpy.mod(numpy.arange(nLat) + 1, nLat) dsLocal = 0.5 * (dsLocal + dsLocal.isel(lat=latIndicesP1)) dsLocal = dsLocal.sel(lon=longitudes, method=str('nearest')) if dsObs is None: dsObs = dsLocal else: dsLocal['lon'] = dsObs.lon dsLocal['lat'] = dsObs.lat dsObs[fieldName] = dsLocal[fieldName] dsLocal.close() if 'zonalVel' in dsObs and 'meridVel' in dsObs: # compute the velocity magnitude print(' velMag') description = 'Monthly velocity magnitude climatologies ' \ 'from 2005-2010 average of the Southern Ocean ' \ 'State Estimate (SOSE)' dsObs['velMag'] = numpy.sqrt(dsObs.zonalVel**2 + dsObs.meridVel**2) dsObs.velMag.attrs['units'] = 'm s$^{-1}$' dsObs.velMag.attrs['description'] = description write_netcdf(dsObs, combinedFileName) print(' Done.')
def text_to_netcdf(inDir, outDir): inFileName = '{}/Antarctic_shelf_data.txt'.format(inDir) outFileName = '{}/Schmidtko_et_al_2014_bottom_PT_S_PD_' \ 'SouthernOcean_0.25x0.125degree.nc'.format(outDir) if os.path.exists(outFileName): return # 1/4 x 1/8 degree grid cells cellsPerLon = 4 cellsPerLat = 8 obsFile = pandas.read_csv(inFileName, delim_whitespace=True) inLon = numpy.array(obsFile.iloc[:, 0]) inLat = numpy.array(obsFile.iloc[:, 1]) inZ = numpy.array(obsFile.iloc[:, 2]) inCT = numpy.array(obsFile.iloc[:, 3]) inCT_std = numpy.array(obsFile.iloc[:, 4]) inSA = numpy.array(obsFile.iloc[:, 5]) inSA_std = numpy.array(obsFile.iloc[:, 6]) pressure = gsw.p_from_z(inZ, inLat) inS = gsw.SP_from_SA(inSA, pressure, inLon, inLat) inPT = gsw.pt_from_CT(inSA, inCT) inPD = gsw.rho(inSA, inCT, 0.) minLat = int(numpy.amin(inLat) * cellsPerLat) / cellsPerLat maxLat = int(numpy.amax(inLat) * cellsPerLat) / cellsPerLat deltaLat = 1. / cellsPerLat outLat = numpy.arange(minLat - deltaLat, maxLat + 2 * deltaLat, deltaLat) deltaLon = 1. / cellsPerLon outLon = numpy.arange(0., 360., deltaLon) xIndices = numpy.array(cellsPerLon * inLon + 0.5, int) yIndices = numpy.array(cellsPerLat * (inLat - outLat[0]) + 0.5, int) Lon, Lat = numpy.meshgrid(outLon, outLat) ds = xarray.Dataset() ds['lon'] = (('lon', ), outLon) ds.lon.attrs['units'] = 'degrees' ds.lon.attrs['description'] = 'longitutude' ds['lat'] = (('lat', ), outLat) ds.lat.attrs['units'] = 'degrees' ds.lat.attrs['description'] = 'latitutude' z = numpy.ma.masked_all(Lon.shape) z[yIndices, xIndices] = inZ ds['z'] = (('lat', 'lon'), z) ds.z.attrs['units'] = 'meters' ds.z.attrs['description'] = 'depth of the seafloor (positive up)' PT = numpy.ma.masked_all(Lon.shape) PT[yIndices, xIndices] = inPT ds['botTheta'] = (('lat', 'lon'), PT) ds.botTheta.attrs['units'] = '$\degree$C' ds.botTheta.attrs['description'] = \ 'potential temperature at sea floor' PT_std = numpy.ma.masked_all(Lon.shape) # neglect difference between std of PT and CT PT_std[yIndices, xIndices] = inCT_std ds['botThetaStd'] = (('lat', 'lon'), PT_std) ds.botThetaStd.attrs['units'] = '$\degree$C' ds.botThetaStd.attrs['description'] = \ 'standard deviation in potential temperature at sea floor' S = numpy.ma.masked_all(Lon.shape) S[yIndices, xIndices] = inS ds['botSalinity'] = (('lat', 'lon'), S) ds.botSalinity.attrs['units'] = 'PSU' ds.botSalinity.attrs['description'] = \ 'salinity at sea floor' S_std = numpy.ma.masked_all(Lon.shape) # neglect difference between std of S and SA S_std[yIndices, xIndices] = inSA_std ds['botSalinityStd'] = (('lat', 'lon'), S_std) ds.botSalinityStd.attrs['units'] = 'PSU' ds.botSalinityStd.attrs['description'] = \ 'standard deviation in salinity at sea floor' PD = numpy.ma.masked_all(Lon.shape) PD[yIndices, xIndices] = inPD ds['botPotentialDensity'] = (('lat', 'lon'), PD) ds.botPotentialDensity.attrs['units'] = 'kg m$^{-3}$' ds.botPotentialDensity.attrs['description'] = \ 'potential desnity at sea floor' write_netcdf(ds, outFileName)
def _compute_climatologies_with_xarray(self, inDirectory, outDirectory): # {{{ ''' Uses xarray to compute seasonal and/or annual climatologies. Parameters ---------- inDirectory : str The run directory containing timeSeriesStatsMonthly output outDirectory : str The output directory where climatologies will be written ''' # Authors # ------- # Xylar Asay-Davis def _preprocess(ds): # drop unused variables during preprocessing because only the # variables we want are guaranteed to be in all the files return ds[variableList] season = self.season parentTask = self.parentTask variableList = parentTask.variableList[season] chunkSize = self.config.getint('input', 'maxChunkSize') if season in constants.abrevMonthNames: # this is an individual month, so create a climatology from # timeSeriesStatsMonthlyOutput fileNames = sorted(parentTask.inputFiles) years, months = get_files_year_month( fileNames, self.historyStreams, 'timeSeriesStatsMonthlyOutput') with xarray.open_mfdataset(parentTask.inputFiles, combine='nested', concat_dim='Time', chunks={'nCells': chunkSize}, decode_cf=False, decode_times=False, preprocess=_preprocess) as ds: ds.coords['year'] = ('Time', years) ds.coords['month'] = ('Time', months) month = constants.abrevMonthNames.index(season) + 1 climatologyFileName = parentTask.get_file_name(season) self.logger.info('computing climatology {}'.format( os.path.basename(climatologyFileName))) ds = ds.where(ds.month == month, drop=True) ds = ds.mean(dim='Time') ds.compute(num_workers=self.subprocessCount) write_netcdf(ds, climatologyFileName) else: outFileName = parentTask.get_file_name(season=season) self.logger.info('computing climatology {}'.format( os.path.basename(outFileName))) fileNames = [] weights = [] for month in constants.monthDictionary[season]: monthName = constants.abrevMonthNames[month - 1] fileNames.append(parentTask.get_file_name(season=monthName)) weights.append(constants.daysInMonth[month - 1]) with xarray.open_mfdataset(fileNames, concat_dim='weight', combine='nested', chunks={'nCells': chunkSize}, decode_cf=False, decode_times=False, preprocess=_preprocess) as ds: ds.coords['weight'] = ('weight', weights) ds = ((ds.weight * ds).sum(dim='weight') / ds.weight.sum(dim='weight')) ds.compute(num_workers=self.subprocessCount) write_netcdf(ds, outFileName)
def _compute_ice_shelf_fluxes(self): # {{{ """ Reads melt flux time series and computes regional total melt flux and mean melt rate. """ # Authors # ------- # Xylar Asay-Davis, Stephen Price mpasTimeSeriesTask = self.mpasTimeSeriesTask config = self.config baseDirectory = build_config_full_path(config, 'output', 'timeSeriesSubdirectory') outFileName = '{}/{}'.format(baseDirectory, self.outFileName) # Load data: inputFile = mpasTimeSeriesTask.outputFile dsIn = open_mpas_dataset(fileName=inputFile, calendar=self.calendar, variableList=self.variableList, startDate=self.startDate, endDate=self.endDate) try: if os.path.exists(outFileName): # The file already exists so load it dsOut = xarray.open_dataset(outFileName) if numpy.all(dsOut.Time.values == dsIn.Time.values): return dsOut.totalMeltFlux, dsOut.meltRates else: self.logger.warning('File {} is incomplete. Deleting ' 'it.'.format(outFileName)) os.remove(outFileName) except OSError: # something is potentailly wrong with the file, so let's delete # it and try again self.logger.warning('Problems reading file {}. Deleting ' 'it.'.format(outFileName)) os.remove(outFileName) # work on data from simulations freshwaterFlux = dsIn.timeMonthly_avg_landIceFreshwaterFlux restartFileName = \ mpasTimeSeriesTask.runStreams.readpath('restart')[0] dsRestart = xarray.open_dataset(restartFileName) areaCell = dsRestart.landIceFraction.isel(Time=0) * dsRestart.areaCell mpasMeshName = config.get('input', 'mpasMeshName') regionMaskDirectory = config.get('regions', 'regionMaskDirectory') regionMaskFileName = '{}/{}_iceShelfMasks.nc'.format( regionMaskDirectory, mpasMeshName) dsRegionMask = xarray.open_dataset(regionMaskFileName) # select only those regions we want to plot dsRegionMask = dsRegionMask.isel(nRegions=self.regionIndices) cellMasks = dsRegionMask.regionCellMasks # convert from kg/s to kg/yr totalMeltFlux = constants.sec_per_year * \ (cellMasks*areaCell*freshwaterFlux).sum(dim='nCells') totalArea = (cellMasks * areaCell).sum(dim='nCells') # from kg/m^2/yr to m/yr meltRates = (1. / constants.rho_fw) * (totalMeltFlux / totalArea) # convert from kg/yr to GT/yr totalMeltFlux /= constants.kg_per_GT baseDirectory = build_config_full_path(config, 'output', 'timeSeriesSubdirectory') outFileName = '{}/iceShelfAggregatedFluxes.nc'.format(baseDirectory) dsOut = xarray.Dataset() dsOut['totalMeltFlux'] = totalMeltFlux dsOut.totalMeltFlux.attrs['units'] = 'GT a$^{-1}$' dsOut.totalMeltFlux.attrs['description'] = \ 'Total melt flux summed over each ice shelf or region' dsOut['meltRates'] = meltRates dsOut.meltRates.attrs['units'] = 'm a$^{-1}$' dsOut.meltRates.attrs['description'] = \ 'Melt rate averaged over each ice shelf or region' write_netcdf(dsOut, outFileName) return totalMeltFlux, meltRates # }}}
def _write_mpas_t_s(self, config): # {{{ climatologyName = 'TS_{}_{}'.format(self.prefix, self.season) outFileName = get_masked_mpas_climatology_file_name(config, self.season, self.componentName, climatologyName, op='avg') if os.path.exists(outFileName): ds = xarray.open_dataset(outFileName) zmin, zmax = ds.zbounds.values return zmin, zmax with dask.config.set(schedular='threads', pool=ThreadPool(self.daskThreads)): self.logger.info(' Extracting T and S in the region...') sectionName = self.sectionName cellsChunk = 32768 chunk = {'nCells': cellsChunk} try: restartFileName = self.runStreams.readpath('restart')[0] except ValueError: raise IOError('No MPAS-O restart file found: need at least one' ' restart file to plot T-S diagrams') dsRestart = xarray.open_dataset(restartFileName) dsRestart = dsRestart.isel(Time=0).chunk(chunk) regionMaskFileName = self.mpasMasksSubtask.maskFileName dsRegionMask = xarray.open_dataset(regionMaskFileName) maskRegionNames = decode_strings(dsRegionMask.regionNames) regionIndex = maskRegionNames.index(self.regionName) dsMask = dsRegionMask.isel(nRegions=regionIndex).chunk(chunk) cellMask = dsMask.regionCellMasks == 1 if 'landIceMask' in dsRestart: # only the region outside of ice-shelf cavities cellMask = numpy.logical_and(cellMask, dsRestart.landIceMask == 0) if config.has_option(sectionName, 'zmin'): zmin = config.getfloat(sectionName, 'zmin') else: if 'zminRegions' in dsMask: zmin = dsMask.zminRegions.values else: # the old naming convention, used in some pre-generated # mask files zmin = dsMask.zmin.values if config.has_option(sectionName, 'zmax'): zmax = config.getfloat(sectionName, 'zmax') else: if 'zmaxRegions' in dsMask: zmax = dsMask.zmaxRegions.values else: # the old naming convention, used in some pre-generated # mask files zmax = dsMask.zmax.values inFileName = get_unmasked_mpas_climatology_file_name( config, self.season, self.componentName, op='avg') ds = xarray.open_dataset(inFileName) variableList = [ 'timeMonthly_avg_activeTracers_temperature', 'timeMonthly_avg_activeTracers_salinity', 'timeMonthly_avg_layerThickness' ] ds = ds[variableList] ds['zMid'] = compute_zmid(dsRestart.bottomDepth, dsRestart.maxLevelCell, dsRestart.layerThickness) ds['volume'] = (dsRestart.areaCell * ds['timeMonthly_avg_layerThickness']) ds = ds.where(cellMask, drop=True) self.logger.info("Don't worry about the following dask " "warnings.") depthMask = numpy.logical_and(ds.zMid >= zmin, ds.zMid <= zmax) depthMask.compute() self.logger.info("Dask warnings should be done.") ds['depthMask'] = depthMask for var in variableList: ds[var] = ds[var].where(depthMask) T = ds['timeMonthly_avg_activeTracers_temperature'].values.ravel() mask = numpy.isfinite(T) T = T[mask] S = ds['timeMonthly_avg_activeTracers_salinity'].values.ravel() S = S[mask] zMid = ds['zMid'].values.ravel()[mask] volume = ds['volume'].values.ravel()[mask] dsOut = xarray.Dataset() dsOut['T'] = ('nPoints', T) dsOut['S'] = ('nPoints', S) dsOut['z'] = ('nPoints', zMid) dsOut['volume'] = ('nPoints', volume) dsOut['zbounds'] = ('nBounds', [zmin, zmax]) write_netcdf(dsOut, outFileName) return zmin, zmax # }}}