def gridcell_areas(lat, lon, mask=None, radius=6372000., lat_edges_in=False, lon_edges_in=False): ### assume uniform longitude spacing lat_edges, lon_edges = get_gridcell_edges(lat, lon) if lon_edges_in: IM = lon.shape[0] - 1 lon_edges = lon[:] res_lon = lon_edges[1] - lon_edges[0] else: IM = lon.shape[0] res_lon = lon[1] - lon[0] # if lat_edges_in: JM = lat.shape[0] - 1 lat_edges = lat[:] else: JM = lat.shape[0] southern_edge = np.fmax(lat_edges[0:JM], np.ones(JM) * -89.99) northern_edge = np.fmin(lat_edges[1:], np.ones(JM) * 89.99) # area = Ngl.gc_qarea(southern_edge,np.zeros(JM)-res_lon/2.,\ northern_edge,np.zeros(JM)-res_lon/2.,\ northern_edge,np.zeros(JM)+res_lon/2.,\ southern_edge,np.zeros(JM)+res_lon/2.,\ radius=radius) ### 1-D array in meters sq. area_array = np.array(np.reshape(np.repeat(area, IM), [JM, IM])) if not mask == None: area_array = np.ma.array(area_array, mask=mask) return area_array
def gridcell_areas(lat, lon, mask=None, radius=6372000., lat_edges_in=False, lon_edges_in=False): ### assume uniform longitude spacing lat_edges, lon_edges = get_gridcell_edges(lat, lon) if lon_edges_in: IM = lon.shape[0] - 1 lon_edges = lon[:] res_lon = lon_edges[1] - lon_edges[0] else: IM = lon.shape[0] res_lon = lon[1]-lon[0] # if lat_edges_in: JM = lat.shape[0] - 1 lat_edges = lat[:] else: JM = lat.shape[0] southern_edge = np.fmax(lat_edges[0:JM], np.ones(JM)*-89.99) northern_edge = np.fmin(lat_edges[1:], np.ones(JM)*89.99) # area = Ngl.gc_qarea(southern_edge,np.zeros(JM)-res_lon/2.,\ northern_edge,np.zeros(JM)-res_lon/2.,\ northern_edge,np.zeros(JM)+res_lon/2.,\ southern_edge,np.zeros(JM)+res_lon/2.,\ radius=radius) ### 1-D array in meters sq. area_array = np.array(np.reshape(np.repeat(area,IM), [JM,IM])) if not mask==None: area_array = np.ma.array(area_array, mask=mask) return area_array
def conservative_regrid(data_in, lats_in, lons_in, lats_out, lons_out, centers_out=True, weights_in=None, spherical=True, radius=6372000., dilute_w_masked_data=True, return_frac_input_masked=False): # """ do a conservative remapping from one 2-d grid to another. assumes that input coordinate arrays are monotonic increasing (but handles lon jump across meridian) and that lat and lon are second-to last and last dimensions possible to mask the input data either by using a masked array or by setting weights array to zero for masked gridcells option dilute_w_masked_data means that where the input data is masked, a value of zero is averaged into the output grid, so that global integrals equal. setting this false will mean that global integrals do not equal, hoe=wever this could be back-calculated out using the fraction masked if return_frac_input_masked is set to true using the weights_in argument will also lead to non-equal global integrals """ # shape = data_in.shape ndims = len(shape) JM_i = shape[ndims-2] IM_i = shape[ndims-1] maxlat = 89.9 if weights_in == None: weights_in = np.ones([JM_i,IM_i]) weights_mask = np.zeros([JM_i,IM_i], dtype=np.bool) else: weights_mask = weights_in[:] == 0. if type(data_in) == np.ma.core.MaskedArray: if ndims == 2: mask_in = np.logical_or(data_in[:].mask, weights_mask) elif ndims == 3: mask_in = np.logical_or(data_in[0,:].mask, weights_mask) elif ndims == 4: mask_in = np.logical_or(data_in[0,0,:].mask, weights_mask) else: mask_in = np.logical_or(np.zeros([JM_i,IM_i], dtype=np.bool), weights_mask) ## check to see if coordinates input are for gridcell centers or edges. assume that if edges, length of vector will be one longer than length of data # # # # ####### lats_in if len(lats_in) == JM_i: if spherical: lat_edges_in = np.zeros(JM_i+1) lat_edges_in[0] = max(-maxlat, lats_in[0] - 0.5*(lats_in[1] - lats_in[0])) lat_edges_in[JM_i] = min(maxlat, lats_in[JM_i-1] + 0.5*(lats_in[JM_i-1] - lats_in[JM_i-2])) lat_edges_in[1:JM_i] = (lats_in[0:JM_i-1] + lats_in[1:JM_i])/2. else: lat_edges_in = np.zeros(JM_i+1) lat_edges_in[0] = lats_in[0] - 0.5*(lats_in[1] - lats_in[0]) lat_edges_in[JM_i] = lats_in[JM_i-1] + 0.5*(lats_in[JM_i-1] - lats_in[JM_i-2]) lat_edges_in[1:JM_i] = (lats_in[0:JM_i-1] + lats_in[1:JM_i])/2. elif len(lats_in) == JM_i+1: lat_edges_in = lats_in else: raise RuntimeError # ####### lats_out if centers_out: JM_o = len(lats_out) if spherical: lat_edges_out = np.zeros(JM_o+1) lat_edges_out[0] = max(-maxlat, lats_out[0] - 0.5*(lats_out[1] - lats_out[0])) lat_edges_out[JM_o] = min(maxlat, lats_out[JM_o-1] + 0.5*(lats_out[JM_o-1] - lats_out[JM_o-2])) lat_edges_out[1:JM_o] = (lats_out[0:JM_o-1] + lats_out[1:JM_o])/2. else: lat_edges_out = np.zeros(JM_o+1) lat_edges_out[0] = lats_out[0] - 0.5*(lats_out[1] - lats_out[0]) lat_edges_out[JM_o] = lats_out[JM_o-1] + 0.5*(lats_out[JM_o-1] - lats_out[JM_o-2]) lat_edges_out[1:JM_o] = (lats_out[0:JM_o-1] + lats_out[1:JM_o])/2. else: JM_o = len(lats_out) -1 lat_edges_out = lats_out # ####### lons_in if len(lons_in) == IM_i: lon_edges_in = np.zeros(IM_i+1) lon_edges_in[0] = lons_in[0] - 0.5*(lons_in[1] - lons_in[0]) lon_edges_in[IM_i] = lons_in[IM_i-1] + 0.5*(lons_in[IM_i-1] - lons_in[IM_i-2]) lon_edges_in[1:IM_i] = (lons_in[0:IM_i-1] + lons_in[1:IM_i])/2. elif len(lons_in) == IM_i+1: lon_edges_in = lons_in else: raise RuntimeError # ####### lons_out if centers_out: IM_o = len(lons_out) lon_edges_out = np.zeros(IM_o+1) lon_edges_out[0] = lons_out[0] - 0.5*(lons_out[1] - lons_out[0]) lon_edges_out[IM_o] = lons_out[IM_o-1] + 0.5*(lons_out[IM_o-1] - lons_out[IM_o-2]) lon_edges_out[1:IM_o] = (lons_out[0:IM_o-1] + lons_out[1:IM_o])/2. else: IM_o = len(lons_out) -1 lon_edges_out = lons_out # # # ### first define ranges to loop over that map overlapping lat and lons lon_looplist = [[]] for i in range(IM_o): if i > 0: lon_looplist.append([]) ### figure out which lon quadrant to normalize the data to. if -90<lon<90 then normalize to option 1, otherwise to zero if (Ngl.normalize_angle(lon_edges_out[i], 1) < 90.) and (Ngl.normalize_angle(lon_edges_out[i], 1) > -90.): lon_sector = 1 else: lon_sector = 0 min_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i], lon_sector) max_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i+1], lon_sector) for ii in range(IM_i): min_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii], lon_sector) max_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii+1], lon_sector) overlap_interval_lon = min(max_cell_lon_i, max_cell_lon_o) - max(min_cell_lon_i,min_cell_lon_o) if overlap_interval_lon > 0.: lon_looplist[i].append(ii) # # # lat_looplist = [[]] for j in range(JM_o): if j > 0: lat_looplist.append([]) min_cell_lat_o = lat_edges_out[j] max_cell_lat_o = lat_edges_out[j+1] for jj in range(JM_i): min_cell_lat_i = lat_edges_in[jj] max_cell_lat_i = lat_edges_in[jj+1] overlap_interval_lat = min(max_cell_lat_i, max_cell_lat_o) - max(min_cell_lat_i,min_cell_lat_o) if overlap_interval_lat > 0.: lat_looplist[j].append(jj) # # # ### now begin looping over output grid total_weights = np.zeros([JM_o,IM_o]) total_weights_inputmasked = np.zeros([JM_o,IM_o]) if ndims == 2: total_value = np.zeros([JM_o,IM_o]) elif ndims == 3: total_value = np.zeros([shape[0],JM_o,IM_o]) elif ndims == 4: total_value = np.zeros([shape[0],shape[1],JM_o,IM_o]) else: raise RuntimeError for i in range(IM_o): ### figure out which lon quadrant to normalize the data to. if -90<lon<90 then normalize to option 1, otherwise to zero if (Ngl.normalize_angle(lon_edges_out[i], 1) < 90.) and (Ngl.normalize_angle(lon_edges_out[i], 1) > -90.): lon_sector = 1 else: lon_sector = 0 min_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i], lon_sector) max_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i+1], lon_sector) for j in range(JM_o): min_cell_lat_o = lat_edges_out[j] max_cell_lat_o = lat_edges_out[j+1] for ii in lon_looplist[i]: for jj in lat_looplist[j]: if not(mask_in[jj,ii]) or dilute_w_masked_data: min_cell_lat_i = lat_edges_in[jj] max_cell_lat_i = lat_edges_in[jj+1] min_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii], lon_sector) max_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii+1], lon_sector) overlap_interval_lat = min(max_cell_lat_i, max_cell_lat_o) - max(min_cell_lat_i,min_cell_lat_o) overlap_interval_lon = min(max_cell_lon_i, max_cell_lon_o) - max(min_cell_lon_i,min_cell_lon_o) if overlap_interval_lat > 0. and overlap_interval_lon > 0.: fractional_overlap_lat = overlap_interval_lat / (max_cell_lat_i - min_cell_lat_i) fractional_overlap_lon = overlap_interval_lon / (max_cell_lon_i - min_cell_lon_i) fractional_overlap_total = fractional_overlap_lat * fractional_overlap_lon if spherical: weight = fractional_overlap_total * weights_in[jj,ii] * Ngl.gc_qarea(min_cell_lat_i,min_cell_lon_i,max_cell_lat_i,min_cell_lon_i,max_cell_lat_i,max_cell_lon_i,min_cell_lat_i,max_cell_lon_i,radius=radius) else: weight = fractional_overlap_total * weights_in[jj,ii] total_weights[j,i] = total_weights[j,i] + weight if not(mask_in[jj,ii]): total_weights_inputmasked[j,i] = total_weights_inputmasked[j,i] + weight if ndims == 2: total_value[j,i] = total_value[j,i] + weight * data_in[jj,ii] elif ndims == 3: total_value[:,j,i] = total_value[:,j,i] + weight * data_in[:,jj,ii] elif ndims == 4: total_value[:,:,j,i] = total_value[:,:,j,i] + weight * data_in[:,:,jj,ii] # if ndims > 2: total_weights_bc, total_value_bc = np.broadcast_arrays(total_weights, total_value) total_weights_inputmasked_bc, total_value_bc = np.broadcast_arrays(total_weights_inputmasked, total_value) else: total_weights_bc = total_weights total_weights_inputmasked_bc = total_weights_inputmasked # if total_weights_inputmasked.min() > 0.: mean_value = total_value[:] / total_weights_bc[:] fraction_maskedinput = total_weights_inputmasked[:] / total_weights[:] else: mean_value = np.ma.masked_array(total_value[:] / total_weights_bc[:], mask=total_weights_inputmasked_bc[:] == 0.) fraction_maskedinput = np.ma.masked_array(total_weights_inputmasked[:] / total_weights[:], mask=total_weights_inputmasked[:] == 0.) # # if not return_frac_input_masked: return mean_value else: return mean_value, fraction_maskedinput
def conservative_regrid(data_in, lats_in, lons_in, lats_out, lons_out, centers_out=True, weights_in=None, spherical=True, radius=6372000., dilute_w_masked_data=True, return_frac_input_masked=False): # """ do a conservative remapping from one 2-d grid to another. assumes that input coordinate arrays are monotonic increasing (but handles lon jump across meridian) and that lat and lon are second-to last and last dimensions possible to mask the input data either by using a masked array or by setting weights array to zero for masked gridcells option dilute_w_masked_data means that where the input data is masked, a value of zero is averaged into the output grid, so that global integrals equal. setting this false will mean that global integrals do not equal, hoe=wever this could be back-calculated out using the fraction masked if return_frac_input_masked is set to true using the weights_in argument will also lead to non-equal global integrals """ # shape = data_in.shape ndims = len(shape) JM_i = shape[ndims - 2] IM_i = shape[ndims - 1] maxlat = 89.9 if weights_in == None: weights_in = np.ones([JM_i, IM_i]) weights_mask = np.zeros([JM_i, IM_i], dtype=np.bool) else: weights_mask = weights_in[:] == 0. if type(data_in) == np.ma.core.MaskedArray: if ndims == 2: mask_in = np.logical_or(data_in[:].mask, weights_mask) elif ndims == 3: mask_in = np.logical_or(data_in[0, :].mask, weights_mask) elif ndims == 4: mask_in = np.logical_or(data_in[0, 0, :].mask, weights_mask) else: mask_in = np.logical_or(np.zeros([JM_i, IM_i], dtype=np.bool), weights_mask) ## check to see if coordinates input are for gridcell centers or edges. assume that if edges, length of vector will be one longer than length of data # # # # ####### lats_in if len(lats_in) == JM_i: if spherical: lat_edges_in = np.zeros(JM_i + 1) lat_edges_in[0] = max(-maxlat, lats_in[0] - 0.5 * (lats_in[1] - lats_in[0])) lat_edges_in[JM_i] = min( maxlat, lats_in[JM_i - 1] + 0.5 * (lats_in[JM_i - 1] - lats_in[JM_i - 2])) lat_edges_in[1:JM_i] = (lats_in[0:JM_i - 1] + lats_in[1:JM_i]) / 2. else: lat_edges_in = np.zeros(JM_i + 1) lat_edges_in[0] = lats_in[0] - 0.5 * (lats_in[1] - lats_in[0]) lat_edges_in[JM_i] = lats_in[JM_i - 1] + 0.5 * (lats_in[JM_i - 1] - lats_in[JM_i - 2]) lat_edges_in[1:JM_i] = (lats_in[0:JM_i - 1] + lats_in[1:JM_i]) / 2. elif len(lats_in) == JM_i + 1: lat_edges_in = lats_in else: raise RuntimeError # ####### lats_out if centers_out: JM_o = len(lats_out) if spherical: lat_edges_out = np.zeros(JM_o + 1) lat_edges_out[0] = max( -maxlat, lats_out[0] - 0.5 * (lats_out[1] - lats_out[0])) lat_edges_out[JM_o] = min( maxlat, lats_out[JM_o - 1] + 0.5 * (lats_out[JM_o - 1] - lats_out[JM_o - 2])) lat_edges_out[1:JM_o] = (lats_out[0:JM_o - 1] + lats_out[1:JM_o]) / 2. else: lat_edges_out = np.zeros(JM_o + 1) lat_edges_out[0] = lats_out[0] - 0.5 * (lats_out[1] - lats_out[0]) lat_edges_out[JM_o] = lats_out[ JM_o - 1] + 0.5 * (lats_out[JM_o - 1] - lats_out[JM_o - 2]) lat_edges_out[1:JM_o] = (lats_out[0:JM_o - 1] + lats_out[1:JM_o]) / 2. else: JM_o = len(lats_out) - 1 lat_edges_out = lats_out # ####### lons_in if len(lons_in) == IM_i: lon_edges_in = np.zeros(IM_i + 1) lon_edges_in[0] = lons_in[0] - 0.5 * (lons_in[1] - lons_in[0]) lon_edges_in[IM_i] = lons_in[IM_i - 1] + 0.5 * (lons_in[IM_i - 1] - lons_in[IM_i - 2]) lon_edges_in[1:IM_i] = (lons_in[0:IM_i - 1] + lons_in[1:IM_i]) / 2. elif len(lons_in) == IM_i + 1: lon_edges_in = lons_in else: raise RuntimeError # ####### lons_out if centers_out: IM_o = len(lons_out) lon_edges_out = np.zeros(IM_o + 1) lon_edges_out[0] = lons_out[0] - 0.5 * (lons_out[1] - lons_out[0]) lon_edges_out[IM_o] = lons_out[IM_o - 1] + 0.5 * (lons_out[IM_o - 1] - lons_out[IM_o - 2]) lon_edges_out[1:IM_o] = (lons_out[0:IM_o - 1] + lons_out[1:IM_o]) / 2. else: IM_o = len(lons_out) - 1 lon_edges_out = lons_out # # # ### first define ranges to loop over that map overlapping lat and lons lon_looplist = [[]] for i in range(IM_o): if i > 0: lon_looplist.append([]) ### figure out which lon quadrant to normalize the data to. if -90<lon<90 then normalize to option 1, otherwise to zero if (Ngl.normalize_angle(lon_edges_out[i], 1) < 90.) and (Ngl.normalize_angle(lon_edges_out[i], 1) > -90.): lon_sector = 1 else: lon_sector = 0 min_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i], lon_sector) max_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i + 1], lon_sector) for ii in range(IM_i): min_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii], lon_sector) max_cell_lon_i = Ngl.normalize_angle(lon_edges_in[ii + 1], lon_sector) overlap_interval_lon = min(max_cell_lon_i, max_cell_lon_o) - max( min_cell_lon_i, min_cell_lon_o) if overlap_interval_lon > 0.: lon_looplist[i].append(ii) # # # lat_looplist = [[]] for j in range(JM_o): if j > 0: lat_looplist.append([]) min_cell_lat_o = lat_edges_out[j] max_cell_lat_o = lat_edges_out[j + 1] for jj in range(JM_i): min_cell_lat_i = lat_edges_in[jj] max_cell_lat_i = lat_edges_in[jj + 1] overlap_interval_lat = min(max_cell_lat_i, max_cell_lat_o) - max( min_cell_lat_i, min_cell_lat_o) if overlap_interval_lat > 0.: lat_looplist[j].append(jj) # # # ### now begin looping over output grid total_weights = np.zeros([JM_o, IM_o]) total_weights_inputmasked = np.zeros([JM_o, IM_o]) if ndims == 2: total_value = np.zeros([JM_o, IM_o]) elif ndims == 3: total_value = np.zeros([shape[0], JM_o, IM_o]) elif ndims == 4: total_value = np.zeros([shape[0], shape[1], JM_o, IM_o]) else: raise RuntimeError for i in range(IM_o): ### figure out which lon quadrant to normalize the data to. if -90<lon<90 then normalize to option 1, otherwise to zero if (Ngl.normalize_angle(lon_edges_out[i], 1) < 90.) and (Ngl.normalize_angle(lon_edges_out[i], 1) > -90.): lon_sector = 1 else: lon_sector = 0 min_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i], lon_sector) max_cell_lon_o = Ngl.normalize_angle(lon_edges_out[i + 1], lon_sector) for j in range(JM_o): min_cell_lat_o = lat_edges_out[j] max_cell_lat_o = lat_edges_out[j + 1] for ii in lon_looplist[i]: for jj in lat_looplist[j]: if not (mask_in[jj, ii]) or dilute_w_masked_data: min_cell_lat_i = lat_edges_in[jj] max_cell_lat_i = lat_edges_in[jj + 1] min_cell_lon_i = Ngl.normalize_angle( lon_edges_in[ii], lon_sector) max_cell_lon_i = Ngl.normalize_angle( lon_edges_in[ii + 1], lon_sector) overlap_interval_lat = min( max_cell_lat_i, max_cell_lat_o) - max( min_cell_lat_i, min_cell_lat_o) overlap_interval_lon = min( max_cell_lon_i, max_cell_lon_o) - max( min_cell_lon_i, min_cell_lon_o) if overlap_interval_lat > 0. and overlap_interval_lon > 0.: fractional_overlap_lat = overlap_interval_lat / ( max_cell_lat_i - min_cell_lat_i) fractional_overlap_lon = overlap_interval_lon / ( max_cell_lon_i - min_cell_lon_i) fractional_overlap_total = fractional_overlap_lat * fractional_overlap_lon if spherical: weight = fractional_overlap_total * weights_in[ jj, ii] * Ngl.gc_qarea(min_cell_lat_i, min_cell_lon_i, max_cell_lat_i, min_cell_lon_i, max_cell_lat_i, max_cell_lon_i, min_cell_lat_i, max_cell_lon_i, radius=radius) else: weight = fractional_overlap_total * weights_in[ jj, ii] total_weights[j, i] = total_weights[j, i] + weight if not (mask_in[jj, ii]): total_weights_inputmasked[ j, i] = total_weights_inputmasked[j, i] + weight if ndims == 2: total_value[j, i] = total_value[ j, i] + weight * data_in[jj, ii] elif ndims == 3: total_value[:, j, i] = total_value[:, j, i] + weight * data_in[:, jj, ii] elif ndims == 4: total_value[:, :, j, i] = total_value[:, :, j, i] + weight * data_in[:, :, jj, ii] # if ndims > 2: total_weights_bc, total_value_bc = np.broadcast_arrays( total_weights, total_value) total_weights_inputmasked_bc, total_value_bc = np.broadcast_arrays( total_weights_inputmasked, total_value) else: total_weights_bc = total_weights total_weights_inputmasked_bc = total_weights_inputmasked # if total_weights_inputmasked.min() > 0.: mean_value = total_value[:] / total_weights_bc[:] fraction_maskedinput = total_weights_inputmasked[:] / total_weights[:] else: mean_value = np.ma.masked_array( total_value[:] / total_weights_bc[:], mask=total_weights_inputmasked_bc[:] == 0.) fraction_maskedinput = np.ma.masked_array( total_weights_inputmasked[:] / total_weights[:], mask=total_weights_inputmasked[:] == 0.) # # if not return_frac_input_masked: return mean_value else: return mean_value, fraction_maskedinput