def test_conversions(verbose=False): r"""Test unit conversions.""" for (measurement_type, measurement_units) in units.items(): value = numpy.pi units_list = list(units[measurement_type].keys()) for i in range(len(units_list)): if verbose: print("%s (%s) -> (%s)" % (value, units_list[i - 1], units_list[i])) value = convert(value, units_list[i - 1], units_list[i]) numpy.testing.assert_allclose([value], [numpy.pi], err_msg="Measurement tyep %s failed." % measurement_type)
def setgeo(rundata): """ Set GeoClaw specific runtime parameters. For documentation see .... """ geo_data = rundata.geo_data # == Physics == geo_data.gravity = 9.81 geo_data.coordinate_system = 1 geo_data.earth_radius = 6367.5e3 geo_data.rho = 1025.0 geo_data.rho_air = 1.15 geo_data.ambient_pressure = 101.3e3 # == Forcing Options geo_data.coriolis_forcing = True geo_data.theta_0 = 25.0 # Beta-plane approximation center geo_data.friction_forcing = True geo_data.friction_depth = 1e10 # == Algorithm and Initial Conditions == # Due to seasonal swelling of gulf we set sea level higher geo_data.sea_level = 0.0 geo_data.dry_tolerance = 1.e-2 # Refinement Criteria refine_data = rundata.refinement_data refine_data.wave_tolerance = 1.0 refine_data.speed_tolerance = [1.0, 2.0, 3.0, 4.0] refine_data.variable_dt_refinement_ratios = True # == settopo.data values == topo_data = rundata.topo_data topo_data.topofiles = [] # for topography, append lines of the form # [topotype, fname] topo_data.topofiles.append([2, 'topo.tt2']) # == setfixedgrids.data values == rundata.fixed_grid_data.fixedgrids = [] # for fixed grids append lines of the form # [t1,t2,noutput,x1,x2,y1,y2,xpoints,ypoints,\ # ioutarrivaltimes,ioutsurfacemax] # ================ # Set Surge Data # ================ data = rundata.surge_data # Source term controls data.wind_forcing = True data.drag_law = 1 data.pressure_forcing = True data.wind_index = 2 data.pressure_index = 4 data.display_landfall_time = True # AMR parameters, m/s and m respectively data.wind_refine = [20.0, 40.0, 60.0] data.R_refine = [60.0e3, 40e3, 20e3] # Storm parameters - Parameterized storm (Holland 1980) data.storm_specification_type = 'holland80' # (type 1) data.storm_file = os.path.expandvars(os.path.join(os.getcwd(), 'fake.storm')) # Contruct storm forward_velocity = units.convert(20, 'km/h', 'm/s') theta = 0.0 * numpy.pi / 180.0 # degrees from horizontal to radians my_storm = Storm() # Take seconds and time period of 30 minutes and turn them into datatimes t_ref = datetime.datetime.now() t_sec = numpy.arange(-RAMP_UP_TIME, rundata.clawdata.tfinal, 30.0 * 60.0) my_storm.t = [t_ref + datetime.timedelta(seconds=t) for t in t_sec] ramp_func = lambda t: (t + (2 * RAMP_UP_TIME)) * (t < 0) / (2 * RAMP_UP_TIME) \ + numpy.ones(t_sec.shape) * (t >= 0) my_storm.time_offset = t_ref my_storm.eye_location = numpy.empty((t_sec.shape[0], 2)) my_storm.eye_location[:, 0] = forward_velocity * t_sec * numpy.cos(theta) my_storm.eye_location[:, 1] = forward_velocity * t_sec * numpy.sin(theta) my_storm.max_wind_speed = units.convert(56, 'knots', 'm/s') * ramp_func(t_sec) my_storm.central_pressure = units.convert(1024, "mbar", "Pa") \ - (units.convert(1024, "mbar", "Pa") \ - units.convert(950, 'mbar', 'Pa')) \ * ramp_func(t_sec) my_storm.max_wind_radius = [units.convert(8, 'km', 'm')] * t_sec.shape[0] my_storm.storm_radius = [units.convert(100, 'km', 'm')] * t_sec.shape[0] my_storm.write(data.storm_file, file_format="geoclaw") # ======================= # Set Variable Friction # ======================= data = rundata.friction_data # Variable friction data.variable_friction = False data.friction_index = 1 return rundata
'weight': 'normal', 'verticalalignment': 'bottom' } # Bottom vertical alignment for more space axis_font = {'fontname': 'Arial', 'size': '12'} axes = fig.add_subplot(2, 2, 1) axes.plot(test_storm.max_wind_speed, test_storm.max_wind_radius / 1000, 'ro', label="Knaff Max Wind Radius") axes.set_xlabel('Max Wind Speed (m/s)', **axis_font) axes.set_ylabel('Max Wind Radius (km)', **axis_font) axes.legend() axes = fig.add_subplot(2, 2, 2) axes.plot(units.convert(test_storm.max_wind_speed, 'm/s', 'knots'), units.convert(test_storm.max_wind_radius, 'km', 'nmi'), 'ro-', label="Knaff MWR") axes.set_xlabel('Max Wind Speed (knots)', **axis_font) axes.set_ylabel('Max Wind Radius (nmi)', **axis_font) axes.legend() axes = fig.add_subplot(2, 2, 3) axes.plot(range(0, test_storm.max_wind_speed.shape[0]), test_storm.max_wind_speed, 'bo-', label="Max Wind Speed") axes.set_xlabel('Obs Count', **axis_font) axes.set_ylabel('Max Wind Speed (m/s)', **axis_font) axes.legend()
def setgeo(rundata): #------------------- """ Set GeoClaw specific runtime parameters. For documentation see .... """ try: geo_data = rundata.geo_data except: print("*** Error, this rundata has no geo_data attribute") raise AttributeError("Missing geo_data attribute") # == Physics == geo_data.gravity = 9.81 geo_data.coordinate_system = 1 geo_data.earth_radius = 6367.5e3 geo_data.rho = [1025.0 * 0.9, 1025.0] geo_data.rho_air = 1.15 geo_data.ambient_pressure = 101.3e3 # == Forcing Options geo_data.coriolis_forcing = True geo_data.theta_0 = 25.0 # Beta-plane approximation center geo_data.friction_forcing = True geo_data.friction_depth = 1e10 # == Algorithm and Initial Conditions == geo_data.sea_level = 0.0 geo_data.dry_tolerance = 1.e-2 # Refinement settings refine_data = rundata.refinement_data refine_data.wave_tolerance = 1.0 refine_data.speed_tolerance = [1.0, 2.0, 3.0, 4.0] refine_data.deep_depth = 300.0 refine_data.max_level_deep = 4 refine_data.variable_dt_refinement_ratios = True # == settopo.data values == topo_data = rundata.topo_data # for topography, append lines of the form # [topotype, minlevel, maxlevel, t1, t2, fname] topo_data.topofiles.append([2, 1, 5, -RAMP_UP_TIME, 1e10, 'topo.tt2']) # == setdtopo.data values == dtopo_data = rundata.dtopo_data # for moving topography, append lines of the form : (<= 1 allowed for now!) # [topotype, minlevel,maxlevel,fname] # ================ # Set Surge Data # ================ data = rundata.surge_data # Source term controls data.wind_forcing = True data.drag_law = 1 data.pressure_forcing = True data.wind_index = 2 data.pressure_index = 4 data.display_landfall_time = True # AMR parameters, m/s and m respectively data.wind_refine = [20.0, 40.0, 60.0] data.R_refine = [60.0e3, 40e3, 20e3] # Storm parameters - Parameterized storm (Holland 1980) data.storm_specification_type = 'holland80' # (type 1) data.storm_file = os.path.expandvars( os.path.join(os.getcwd(), 'fake.storm')) # Contruct storm forward_velocity = units.convert(20, 'km/h', 'm/s') theta = 0.0 * numpy.pi / 180.0 # degrees from horizontal to radians my_storm = Storm() # Take seconds and time period of 30 minutes and turn them into datatimes t_ref = datetime.datetime.now() t_sec = numpy.arange(-RAMP_UP_TIME, rundata.clawdata.tfinal, 30.0 * 60.0) my_storm.t = [t_ref + datetime.timedelta(seconds=t) for t in t_sec] ramp_func = lambda t: (t + (2 * RAMP_UP_TIME)) * (t < 0) / (2 * RAMP_UP_TIME) \ + numpy.ones(t_sec.shape) * (t >= 0) my_storm.time_offset = t_ref my_storm.eye_location = numpy.empty((t_sec.shape[0], 2)) my_storm.eye_location[:, 0] = forward_velocity * t_sec * numpy.cos(theta) my_storm.eye_location[:, 1] = forward_velocity * t_sec * numpy.sin(theta) my_storm.max_wind_speed = units.convert(56, 'knots', 'm/s') * ramp_func(t_sec) my_storm.central_pressure = units.convert(1024, "mbar", "Pa") \ - (units.convert(1024, "mbar", "Pa") \ - units.convert(950, 'mbar', 'Pa')) \ * ramp_func(t_sec) my_storm.max_wind_radius = [units.convert(8, 'km', 'm')] * t_sec.shape[0] my_storm.storm_radius = [units.convert(100, 'km', 'm')] * t_sec.shape[0] my_storm.write(data.storm_file, file_format="geoclaw") # ====================== # Multi-layer settings # ====================== data = rundata.multilayer_data # Physics parameters data.num_layers = 2 data.eta = [0.0, -300.0] # Algorithm parameters data.eigen_method = 2 data.inundation_method = 2 data.richardson_tolerance = 1e10 data.wave_tolerance = [0.1, 0.5] data.layer_index = 1 # ======================= # Set Variable Friction # ======================= data = rundata.friction_data # Variable friction data.variable_friction = False data.friction_index = 1 return rundata
def load_obs1(path, mask_distance=None, mask_coordinate=(0.0, 0.0), mask_category=None, categorization="NHC"): r"""Load storms from a Matlab file containing storms This format is based on the format Prof. Emmanuel uses to generate storms. :Input: - *path* (string) Path to the file to be read in - *mask_distance* (float) Distance from *mask_coordinate* at which a storm needs to in order to be returned in the list of storms. If *mask_distance* is *None* then no masking is used. Default is to use no *mask_distance*. - *mask_coordinate* (tuple) Longitude and latitude coordinates to measure the distance from. Default is *(0.0, 0.0)*. - *mask_category* (int) Category or highter a storm needs to be to be included in the returned list of storms. If *mask_category* is *None* then no masking occurs. The categorization used is controlled by *categorization*. Default is to use no *mask_category*. - *categorization* (string) Categorization to be used for the *mask_category* filter. Default is "NHC". :Output: - (list) List of Storm objects that have been read in and were not filtered out. """ data = netCDF4.Dataset(path) # Days from 1-1-1950 start_date = datetime.datetime(1950, 1, 1) storms = [] time_length = data['Mwspd'].shape[0] num_tracks = data['Mwspd'].shape[1] for i in range(num_tracks): # Use intensity to find non-nans and extract correct arrays max_wind_speed = numpy.array(data.variables['Mwspd'][:, i]) index_set = (numpy.isnan(max_wind_speed) - 1).nonzero()[0] index = len(index_set) t = numpy.array(data.variables['time'][0:index, i]) x = numpy.array(data.variables['longitude'][0:index, i]) y = numpy.array(data.variables['latitude'][0:index, i]) # Filter out nan values index_x = (numpy.isnan(x) - 1).nonzero()[0] index_y = (numpy.isnan(y) - 1).nonzero()[0] # Determine which is the smallest of the indicies indicies = [index_x, index_y, index_set] index_set = min(indicies, key=len) x = x[index_set] y = y[index_set] t = t[index_set] max_wind_speed = max_wind_speed[index_set] # Remove zero-length intensities if len(index_set) > 0: # Create storm object storm = clawpack.geoclaw.surge.storm.Storm() storm.ID = i # Initialize the date set storm.t = [datetime.datetime(2000, 1, 1, 0) + \ datetime.timedelta(hours=6) * i for i in range(len(index_set))] storm.time_offset = storm.t[0] storm.eye_location = numpy.empty((len(index_set), 2)) x = x - 360.0 * numpy.ones(len(index_set)) storm.eye_location[:, 0] = x storm.eye_location[:, 1] = y # TODO: Convert from knots print(max_wind_speed.shape) print(max_wind_speed) #storm.max_wind_speed = max_wind_speed[index_set] storm.max_wind_speed = numpy.array(max_wind_speed) # Calculate Radius of Max Wind C0 = 218.3784 * numpy.ones(len(index_set)) storm.max_wind_radius = C0 - 1.2014 * storm.max_wind_speed + \ (storm.max_wind_speed / 10.9884)**2 - \ (storm.max_wind_speed / 35.3052)**3 - \ 145.5090 * \ numpy.cos(storm.eye_location[:, 1] * 0.0174533) # From Kossin, J. P. WAF 2015 a = -0.0025 b = -0.36 c = 1021.36 storm.central_pressure = (a * storm.max_wind_speed**2 + b * storm.max_wind_speed + c) # Determine extent of storm storm.storm_radius = 300 * numpy.ones(len(index_set)) storm.storm_radius = units.convert(storm.storm_radius, 'km', 'm') storm.max_wind_radius = units.convert(storm.max_wind_radius, 'nmi', 'm') storm.max_wind_speed = units.convert(storm.max_wind_speed, 'knots', 'm/s') include_storm = True include_storm_md = True include_storm_mc = True if mask_distance is not None: distance = numpy.sqrt( (storm.eye_location[:, 0] - mask_coordinate[0])**2 + (storm.eye_location[:, 1] - mask_coordinate[1])**2) include_storm_md = numpy.any(distance <= mask_distance) if mask_category is not None: category = storm.category(categorization=categorization) include_storm_mc = numpy.any(category > mask_category) if include_storm_md and include_storm_mc: storms.append(storm) return storms
def load_other_chaz_storms(path, mask_distance=None, mask_coordinate=(0.0, 0.0), mask_category=None, categorization="NHC"): r"""Load storms from a Matlab file containing storms This format is based on the format Prof. Emmanuel uses to generate storms. :Input: - *path* (string) Path to the file to be read in - *mask_distance* (float) Distance from *mask_coordinate* at which a storm needs to in order to be returned in the list of storms. If *mask_distance* is *None* then no masking is used. Default is to use no *mask_distance*. - *mask_coordinate* (tuple) Longitude and latitude coordinates to measure the distance from. Default is *(0.0, 0.0)*. - *mask_category* (int) Category or highter a storm needs to be to be included in the returned list of storms. If *mask_category* is *None* then no masking occurs. The categorization used is controlled by *categorization*. Default is to use no *mask_category*. - *categorization* (string) Categorization to be used for the *mask_category* filter. Default is "NHC". :Output: - (list) List of Storm objects that have been read in and were not filtered out. """ # Load the netcdf file and extract pertinent data #data = xarray.open_dataset(path) #['stormID', 'lifetimelength']) #odict_keys(['longitude', 'latitude', 'intensity', 'RMW'] data = netCDF4.Dataset(path) # print(data.dimensions.keys()) # print(data.variables.keys()) # print("") # print("") # Days from 1-1-1950 # start_date = datetime.datetime(1950, 1, 1) #stormIDs = data.variables['time']['stormID'][:] #stormIDs = data['time']['stormID'] storms = [] # print() # print(data.dimensions['lifetimelength']) # print(data.variables['intensity'].shape) num_tracks = data.dimensions['stormID'].size num_intensities = data['intensity'].shape #print(num_intensities) for i in range(num_tracks): max_wind_speed = numpy.array(data.variables['intensity'][:, i]) index_set = (numpy.isnan(max_wind_speed) - 1).nonzero()[0] #print(index_set) index = len(index_set) if len(index_set) > 0: storm = clawpack.geoclaw.surge.storm.Storm() storm.ID = i # Initialize the date set storm.t = [datetime.datetime(2000, 1, 1, 0) + \ datetime.timedelta(hours=6) * i for i in range(index)] storm.time_offset = storm.t[0] x = numpy.array(data.variables['longitude'][0:index, i]) y = numpy.array(data.variables['latitude'][0:index, i]) max_wind_radius = numpy.array(data.variables['RMW'][0:index, i]) storm.eye_location = numpy.empty((len(index_set), 2)) #x = x - 360.0 * numpy.ones(len(index_set)) storm.eye_location[:, 0] = x storm.eye_location[:, 1] = y storm.max_wind_speed = max_wind_speed[index_set] # Define maximum radius for all sotrms storm.storm_radius = 500000 * numpy.ones(len(index_set)) # From Kossin, J. P. WAF 2015 a = -0.0025 b = -0.36 c = 1021.36 storm.central_pressure = (a * storm.max_wind_speed**2 + b * storm.max_wind_speed + c) # Convert max wind from knots to m/s storm.max_wind_speed = units.convert(storm.max_wind_speed, 'knots', 'm/s') storm.max_wind_radius = max_wind_radius storm.max_wind_radius = units.convert(storm.max_wind_radius, 'km', 'm') include_storm = True if mask_distance is not None: distance = numpy.sqrt( (storm.eye_location[:, 0] - mask_coordinate[0])**2 + (storm.eye_location[:, 1] - mask_coordinate[1])**2) inlcude_storm = numpy.any(distance < mask_distance) if mask_category is not None: category = storm.category(categorization=categorization) include_storm = numpy.any(category > mask_category) #raise NotImplementedError("Category masking not implemented.") if include_storm: storms.append(storm) #print(len(storms)) return storms
def load_emanuel_storms(path, mask_distance=None, mask_coordinate=(0.0, 0.0), mask_category=None, categorization="NHC"): r"""Load storms from a Matlab file containing storms This format is based on the format Prof. Emmanuel uses to generate storms. :Input: - *path* (string) Path to the file to be read in - *mask_distance* (float) Distance from *mask_coordinate* at which a storm needs to in order to be returned in the list of storms. If *mask_distance* is *None* then no masking is used. Default is to use no *mask_distance*. - *mask_coordinate* (tuple) Longitude and latitude coordinates to measure the distance from. Default is *(0.0, 0.0)*. - *mask_category* (int) Category or highter a storm needs to be to be included in the returned list of storms. If *mask_category* is *None* then no masking occurs. The categorization used is controlled by *categorization*. Default is to use no *mask_category*. - *categorization* (string) Categorization to be used for the *mask_category* filter. Default is "NHC". :Output: - (list) List of Storm objects that have been read in and were not filtered out. """ # Load the mat file and extract pertinent data import scipy.io mat = scipy.io.loadmat(path) lon = mat['longstore'] lat = mat['latstore'] hour = mat['hourstore'] day = mat['daystore'] month = mat['monthstore'] year = mat['yearstore'] max_wind_radius = mat['rmstore'] max_wind_speed = mat['vstore'] central_pressure = mat['pstore'] # Convert into storms and truncate zeros storms = [] for n in range(lon.shape[0]): m = len(lon[n].nonzero()[0]) storm = Storm() storm.ID = n storm.t = [ datetime.datetime(year[0, n], month[n, i], day[n, i], hour[n, i]) for i in range(m) ] storm.time_offset = storm.t[0] storm.eye_location = numpy.empty((m, 2)) storm.max_wind_speed = numpy.empty(m) storm.max_wind_radius = numpy.empty(m) storm.central_pressure = numpy.empty(m) storm.eye_location[:, 0] = lon[n, :m] storm.eye_location[:, 1] = lat[n, :m] storm.max_wind_speed = max_wind_speed[n, :m] storm.max_wind_speed = units.convert(max_wind_speed[n, :m], 'knots', 'm/s') storm.max_wind_radius = units.convert(max_wind_radius[n, :m], 'km', 'm') storm.central_pressure = units.convert(central_pressure[n, :m], 'hPa', 'Pa') storm.storm_radius = numpy.ones(m) * 300e3 include_storm = True if mask_distance is not None: distance = numpy.sqrt((storm.eye_location[:, 0] - \ mask_coordinate[0])**2 + (storm.eye_location[:, 1] - \ mask_coordinate[1])**2) inlcude_storm = numpy.any(distance < mask_distance) if mask_category is not None: category = storm.category(categorization=categorization) include_storm = numpy.any(category > mask_category) if include_storm: storms.append(storm) #print("Length of storms:", len(storms)) return storms
def load_chaz_storms(path, mask_distance=None, mask_coordinate=(0.0, 0.0), mask_category=None, categorization="NHC"): r"""Load storms from a Matlab file containing storms This format is based on the format Prof. Emmanuel uses to generate storms. :Input: - *path* (string) Path to the file to be read in - *mask_distance* (float) Distance from *mask_coordinate* at which a storm needs to in order to be returned in the list of storms. If *mask_distance* is *None* then no masking is used. Default is to use no *mask_distance*. - *mask_coordinate* (tuple) Longitude and latitude coordinates to measure the distance from. Default is *(0.0, 0.0)*. - *mask_category* (int) Category or highter a storm needs to be to be included in the returned list of storms. If *mask_category* is *None* then no masking occurs. The categorization used is controlled by *categorization*. Default is to use no *mask_category*. - *categorization* (string) Categorization to be used for the *mask_category* filter. Default is "NHC". :Output: - (list) List of Storm objects that have been read in and were not filtered out. """ # Load the mat file and extract pertinent data data = netCDF4.Dataset(path) storms = [] time_length = data['Mwspd'].shape[0] num_tracks = data['Mwspd'].shape[1] num_intensities = data['Mwspd'].shape[2] count = 0 for i in range(num_tracks): # Extract initial data ranges for n in range(num_intensities): # Use intensity to find non-nans and extract correct arrays max_wind_speed = numpy.array(data.variables['Mwspd'][:, i, n]) index_set = (numpy.isnan(max_wind_speed) - 1).nonzero()[0] index = len(index_set) t = numpy.array(data.variables['time'][0:index, i]) x = numpy.array(data.variables['longitude'][0:index, i]) y = numpy.array(data.variables['latitude'][0:index, i]) # Filter out nan values index_x = (numpy.isnan(x) - 1).nonzero()[0] index_y = (numpy.isnan(y) - 1).nonzero()[0] indicies = [index_x, index_y, index_set] index_set = min(indicies, key=len) x = x[index_set] y = y[index_set] t = t[index_set] max_wind_speed = max_wind_speed[index_set] # Remove zero-length intensities if len(index_set) > 0: # Create storm object storm = clawpack.geoclaw.surge.storm.Storm() storm.ID = i * num_intensities + n # Initialize the date set storm.t = [datetime.datetime(2000, 1, 1, 0) + \ datetime.timedelta(hours=6) * i for i in range(len(index_set))] storm.eye_location = numpy.empty((len(index_set), 2)) x = x - 360.0 * numpy.ones(len(index_set)) storm.eye_location[:, 0] = x storm.eye_location[:, 1] = y # Get the storm within the domain for the first time step # The domain of the run in a list # x = [lower bound, upper bound] # x is long # y is lat # Radius of the earth in km R = 6373.0 # Domain of storm x_domain = numpy.abs([-60, -78]) y_domain = numpy.abs([20, 40]) # Default time offset storm.time_offset = (storm.t[0], 0) # Start the storm in a domain contained # within the given boundaries. # This domain is 5 degrees from either boundary # of the latitude #and of the longitude. For example if the boundaries specified that #the domain of the entire storm was [-50, -95] for the latitude #and [10, 45] for the longitude then the actual domain in which we #START the storm running would be [-55, -90] for lat and [15, 40] for long # than the boundaries. We find the region for this. # Note here 5 degrees is roughly 550 km. Thus the center of the # storm is 550 km away from either boundary. for b in range(0, len(x)): if numpy.abs(x[b]) >= (x_domain[0]) and numpy.abs( x[b]) <= (x_domain[1]): if numpy.abs(y[b]) >= (y_domain[0]) and numpy.abs( y[b]) <= (y_domain[1]): #storm.time_offset = (storm.t[b],b) storm.time_offset = storm.t[b] break # TODO: Convert from knots storm.max_wind_speed = numpy.array(max_wind_speed) # Calculate Radius of Max Wind C0 = 218.3784 * numpy.ones(len(index_set)) storm.max_wind_radius = C0 - 1.2014 * storm.max_wind_speed + \ (storm.max_wind_speed / 10.9884)**2 - \ (storm.max_wind_speed / 35.3052)**3 - \ 145.5090 * \ numpy.cos(storm.eye_location[:, 1] * 0.0174533) # From Kossin, J. P. WAF 2015 a = -0.0025 b = -0.36 c = 1021.36 storm.central_pressure = (a * storm.max_wind_speed**2 + b * storm.max_wind_speed + c) # Extent of storm set to 300 km storm.storm_radius = 500 * numpy.ones(len(index_set)) storm.storm_radius = units.convert(storm.storm_radius, 'km', 'm') storm.max_wind_radius = units.convert(storm.max_wind_radius, 'nmi', 'm') storm.max_wind_speed = units.convert(storm.max_wind_speed, 'knots', 'm/s') storm.central_pressure = units.convert(storm.central_pressure, 'hPa', 'Pa') print(storm.central_pressure) include_storm = True include_storm_md = True include_storm_mc = True if mask_distance is not None: distance = numpy.sqrt( (storm.eye_location[:, 0] - mask_coordinate[0])**2 + (storm.eye_location[:, 1] - mask_coordinate[1])**2) include_storm_md = numpy.any(distance <= mask_distance) if mask_category is not None: category = storm.category(categorization=categorization) include_storm_mc = numpy.any(category > mask_category) if include_storm_md and include_storm_mc: storms.append(storm) return storms
def calculate_intensity(intensity_data_descriptors=None, mask_distance=None, mask_coordinate=None, mask_category=None): r''' Parameters ---------- intensity_data_descriptors : list A list containing the path, label, and type of file Returns ------- ''' fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, sharey=False, sharex=False) fig.set_size_inches(20.0, 30.0) bar_width = 1.0 opacity = 1.0 if intensity_data_descriptors is not None: for (index, data) in enumerate(intensity_data_descriptors): if data[2] == "other_chaz": data_path = os.path.join("data", data[0]) storms = storm.load_other_chaz_storms( path=data_path, mask_distance=mask_distance, mask_coordinate=mask_coordinate, mask_category=mask_category, categorization="NHC") elif data[2] == "mat": data_path = os.path.join("data", data[0]) storms = storm.load_emanuel_storms( path=data_path, mask_distance=mask_distance, mask_coordinate=mask_coordinate, mask_category=mask_category, categorization="NHC") else: break events_intensity = numpy.ones((1, len(storms)), dtype=float) for (i, storm_track) in enumerate(storms): storm_track.max_wind_speed = units.convert( storm_track.max_wind_speed, 'm/s', 'knots') events_intensity[0, i] = numpy.max(storm_track.max_wind_speed) #bins_intensity = numpy.array([1.0, 30.0, 64.0, 83.0, 96.0, 113.0, 135.0, 160.0, 180.0]) bins_intensity = numpy.linspace(1.0, 200, 100) period = data[-1] hist, bin_edges = numpy.histogram(events_intensity, bins_intensity) index_edges = numpy.ones(bin_edges.shape) * (index + bar_width) n = hist.sum() # Complement of empirical distribution function ECDF_c = numpy.cumsum(hist[::-1])[::-1] * 1 / n ECDF = numpy.ones(ECDF_c.shape, dtype=float) - ECDF_c return_period = period * 1 / n * (1 / ECDF_c) T_r = numpy.zeros(events_intensity.shape, dtype=float) events_intensity = numpy.sort(events_intensity) counter = 0 for i in range(events_intensity.shape[1]): if events_intensity[0, i] < bin_edges[counter]: T_r[0, i] = return_period[counter] else: counter += 1 T_r[0, i] = return_period[counter] ax1.bar(index_edges[:-1] + bin_edges[:-1], ECDF_c, bar_width, label=data[1], color=data[-2], alpha=opacity) ax2.semilogx(T_r[0, :], events_intensity[0, :], label=data[1], color=data[-2]) title_font = { 'fontname': 'Arial', 'size': '10', 'color': 'black', 'weight': 'normal', 'verticalalignment': 'bottom' } # Bottom vertical alignment for more space axis_font = {'fontname': 'Arial', 'size': '8'} ax1.set_xlabel('Knots', **axis_font) ax1.set_ylabel('CDF', **axis_font) ax1.set_title('Mumbai 150 km', **title_font) ax1.legend() ax2.set_xlabel('Return Period (Years)', **axis_font) ax2.set_ylabel('Intensity (knots)', **axis_font) ax2.set_title('Mumbai 150 km', **title_font) ax2.set_xlim(0, 5000) ax2.set_ylim(20, 150) ax2.legend() plt.yticks(fontsize=10) plt.xticks(fontsize=10) plt.tight_layout() plt.savefig('output/Mumbai_Stats_ncdata.pdf') plt.show() return fig
def max_wind_radius_calculation(storm): r""" Use the approach: Complete Radial Structure in the paper [1] to calculate radius of maximum wind. To calculate radius of maximum wind, seek to merge the solutions for the inner ascending and outer descending regions given by Eqs. (6) and (2), respectively [1]. Combined with Eq. (10), this equation set is solved by Newton method. :Input: - *storm* (object) Storm 1. Chavas, D. R., N. Lin, and K. Emanuel, A model for the complete radial structure of the tropical cyclone wind field. Part I: Comparison with observed structure. J. Atmos. Sci., 72, 3647–3662 (2015). """ rm, ra, va = symbols('rm ra va') A = np.mat(zeros(3,3)) B = np.matrix(np.arange(9).reshape((3,3)), dtype = 'float') # Number of data lines in storm object num = len(storm.t) # w - the average angular velocity of Earth’s rotation w = 7.292e-5 v30 = units.convert(30.0, 'knots', 'm/s') # Calculate radius of maximum wind by Newton Method for i in range(num): if (i != 0) & (storm.t[i] == storm.t[i-1]): storm.max_wind_radius[i] = storm.max_wind_radius[i-1] continue # Radius of 30kts wind r30 = -1 for j in range(max(i-2, 0), min(i+3, num)): if (storm.wind_speeds[i, 1] != -1) & (np.abs(storm.wind_speeds[i, 0] - v30) < 1e-5) & (storm.t[j] == storm.t[i]): r30 = units.convert(storm.wind_speeds[i, 1], 'm', 'nmi') break else: r30 = -1 # Find radius of maximum defined wind speed (such as 30kt, 50kt in atcf # file) in every record. max_record_wind_radius = -1 a = storm.wind_speeds[i, 0] b = i for k in range(max(i-2, 0), min(i+3, num)): if (storm.t[k] == storm.t[i]) & (storm.wind_speeds[k, 0] > a) & (storm.wind_speeds[k, 1] != -1): b = k a = storm.wind_speeds[k, 0] max_record_wind_radius = units.convert(storm.wind_speeds[b, 1], 'm', 'nmi') # Latitude phi = storm.eye_location[i, 1] * np.pi / 180.0 # Coriolis parameter f = 2 * np.sin(phi) * w # Speed of maximum wind vm = units.convert(storm.max_wind_speed[i], 'm/s', 'knots') chi_30 = 1.0 if (np.abs(r30) < 1e-5) | (np.abs(r30 + 1) < 1e-5): storm.max_wind_radius[i] = -1 continue # Parameter of the equationn set r0 = Find_r0(r30, v30, chi_30, f) chi = 1.0 CkCd = 1.0 # Two equations of the equation set: Eqs. (8) and (9) f1 = ((ra * va + 0.5 * f * ra**2 * 1000) / (rm * vm + 0.5 * f * rm**2 * 1000))**(CkCd) - 2 * (ra / rm)**2 / (2 - CkCd + CkCd * (ra / rm)**2) f2 = 2 * (ra * va + 0.5 * f * ra**2 * 1000) / (ra * ((ra / rm)**2 + 1)) - chi * (ra * va)**2 / (r0**2 - ra**2) # The derivative of Eq. (10) with the respect of ra f32 = lambda ra, v, va: chi * (ra * v)**2 / (r0**2 - ra**2) - va - f * ra * 1000 # Initial Guess for Newton Method x0 = [1.0, 1.0, 1.0] xk = [0, 0, 0] step = 0 if (max_record_wind_radius == -1) | (np.abs(max_record_wind_radius) < 1e-5): storm.max_wind_radius[i] = -1 continue x0[0] = max_record_wind_radius / 2.0 x0[1] = max_record_wind_radius num_1 = int((x0[1] - 0.1) * 10) M1 = solve_outer_region(r0, chi, f, v0=0, num=num_1) x0[2] = M1[2] Fx0 = [-1, -1, -1] max_wind_radius = 0 # Newton Method while((abs(Fx0[0]) > 1.e-3) | (abs(Fx0[1]) > 1.e-3) | (abs(Fx0[2]) > 1.e-3)): F = [f1, f2] x = [rm, ra, va] for m in range(2): for n in range(3): A[m, n] = diff(F[m], x[n]) xk = x0 for m in range(2): for n in range(3): B[m, n] = A[m, n].evalf(subs={rm:xk[0], ra:xk[1], va:xk[2]}) # Check whether va is negative or whether ra is larger than outer radius r0 num_2 = int((xk[1] - 0.1) * 10) if (num_2 < 0) | (xk[1] > r0): max_wind_radius = -1 break M2 = solve_outer_region(r0, chi, f, v0=0, num=num_2) B[2, 0] = 0 B[2, 1] = f32(xk[1], M2[2], xk[2]) B[2, 2] = -xk[1] Fx1 = f1.evalf(subs={rm:xk[0], ra:xk[1], va:xk[2]}) Fx2 = f2.evalf(subs={rm:xk[0], ra:xk[1], va:xk[2]}) Fx3 = M2[1] - (xk[1] * xk[2] + 0.5 * f * xk[1]**2 * 1000) Fx0 = [Fx1, Fx2, Fx3] Fx = np.array(Fx0).reshape(-1,1) # Check whether inv(B) exists if np.linalg.matrix_rank(B) != 3: break B1 = np.linalg.inv(B) B2 = B1 * Fx for l in range(3): x0[l] = xk[l] - B2.sum(axis=1)[l, 0] step = step + 1 if step > 1.e3: max_wind_radius = -1 break if (max_wind_radius != -1) & (x0[0] > 0) & (x0[0] < r0): max_wind_radius = x0[0] storm.max_wind_radius[i] = units.convert(float(max_wind_radius), 'km', 'm') else: storm.max_wind_radius[i] = -1 return None