Beispiel #1
0
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)
Beispiel #2
0
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()
Beispiel #4
0
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
Beispiel #10
0
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