def __reverse(self, **kwargs):
        """
            Reverse particle just off of the shore in the direction that it came in.
            Adds a slight random factor to the distance and angle it is reversed in.
        """

        #st = time.clock()

        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        reverse_azimuth = kwargs.pop('reverse_azimuth')
        reverse_distance = kwargs.get('reverse_distance', None)
        if reverse_distance is None:
            reverse_distance = 100

        # Randomize the reverse angle slightly (+/- 5 degrees)
        random_azimuth = reverse_azimuth + AsaRandom.random() * 5

        count = 0
        nudge_distance = 0.01
        nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance, azimuth=reverse_azimuth, start_point=hit_point)
        nudge_loc = Location4D(latitude=nudge_point['latitude'], longitude=nudge_point['longitude'], depth=start_point.depth)

        # Find point just offshore to do testing with.  Try 15 times (~350m).  This makes sure the start_point is in the water
        # for the next call to intersect (next while loop).
        while self.intersect(single_point=nudge_loc.point) and count < 16:
            nudge_distance *= 2
            nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance, azimuth=reverse_azimuth, start_point=hit_point)
            nudge_loc = Location4D(latitude=nudge_point['latitude'], longitude=nudge_point['longitude'], depth=start_point.depth)
            count += 1

        # We tried 16 times and couldn't find a point.  This should totally never happen.
        if count == 16:
            logger.warn("LOOK: Could not find location in water to do shoreline calculation with.  Assuming particle did not move from original location")
            return start_point

        # Keep trying to throw particle back, halfing the distance each time until it is in water.
        # Only half it 6 times before giving up and returning the point which the particle came from.
        count = 0
        # Distance amount to half each iteration
        changing_distance = reverse_distance
        new_point = AsaGreatCircle.great_circle(distance=reverse_distance, azimuth=random_azimuth, start_point=hit_point)
        new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)

        # We don't want to reverse further than the current spatial buffer, because we will reindex the
        # source file everytime we reverse, which will slow down the calculations considerably.
        while (not self._spatial_query_object.contains(new_loc.point) or self.intersect(start_point=nudge_loc.point, end_point=new_loc.point)) and count < 6:
            changing_distance /= 2
            new_point = AsaGreatCircle.great_circle(distance=changing_distance, azimuth=random_azimuth, start_point=hit_point)
            new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)
            count += 1

        # We tried 10 times and the particle was still on shore, return the point the particle started from.
        # No randomization.
        if count == 6:
            logger.warn("LOOK: Could not react particle with shoreline.  Assuming particle did not move from original location")
            return start_point

        #logger.info("Reaction time: %f" % (time.clock() - st))
        return new_loc
Example #2
0
    def test_great_circle_angles(self):

        # One decimal degree is 111000m
        starting = Location4D(latitude=40.00, longitude=-76.00, depth=0)

        azimuth = 90
        new_gc = AsaGreatCircle.great_circle(distance=111000, azimuth=azimuth, start_point=starting)
        new_pt = Location4D(latitude=new_gc['latitude'], longitude=new_gc['longitude'])
        # We should have gone to the right
        assert new_pt.longitude > starting.longitude + 0.9

        azimuth = 270
        new_gc = AsaGreatCircle.great_circle(distance=111000, azimuth=azimuth, start_point=starting)
        new_pt = Location4D(latitude=new_gc['latitude'], longitude=new_gc['longitude'])
        # We should have gone to the left
        assert new_pt.longitude < starting.longitude - 0.9

        azimuth = 180
        new_gc = AsaGreatCircle.great_circle(distance=111000, azimuth=azimuth, start_point=starting)
        new_pt = Location4D(latitude=new_gc['latitude'], longitude=new_gc['longitude'])
        # We should have gone down
        assert new_pt.latitude < starting.latitude - 0.9

        azimuth = 0
        new_gc = AsaGreatCircle.great_circle(distance=111000, azimuth=azimuth, start_point=starting)
        new_pt = Location4D(latitude=new_gc['latitude'], longitude=new_gc['longitude'])
        # We should have gone up
        assert new_pt.latitude > starting.latitude + 0.9

        azimuth = 315
        new_gc = AsaGreatCircle.great_circle(distance=111000, azimuth=azimuth, start_point=starting)
        new_pt = Location4D(latitude=new_gc['latitude'], longitude=new_gc['longitude'])
        # We should have gone up and to the left
        assert new_pt.latitude > starting.latitude + 0.45
        assert new_pt.longitude < starting.longitude - 0.45
Example #3
0
    def __reverse(self, **kwargs):
        """
            Reverse particle just off of the shore in the direction that it came in.
            Adds a slight random factor to the distance and angle it is reversed in.
        """
        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        distance = kwargs.pop('distance')
        azimuth = kwargs.pop('azimuth')
        reverse_azimuth = kwargs.pop('reverse_azimuth')
        reverse_distance = kwargs.get('reverse_distance', None)
        if reverse_distance is None:
            reverse_distance = 100

        # Randomize the reverse angle slightly (+/- 5 degrees)
        random_azimuth = reverse_azimuth + AsaRandom.random() * 5

        count = 0
        nudge_distance = 0.01
        nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance, azimuth=reverse_azimuth, start_point=hit_point)
        nudge_loc = Location4D(latitude=nudge_point['latitude'], longitude=nudge_point['longitude'], depth=start_point.depth)

        # Find point just offshore to do testing with.  Try 15 times (~350m).  This makes sure the start_point is in the water
        # for the next call to intersect (next while loop).
        while self.intersect(single_point=nudge_loc.point) and count < 16:
            nudge_distance *= 2
            nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance, azimuth=reverse_azimuth, start_point=hit_point)
            nudge_loc = Location4D(latitude=nudge_point['latitude'], longitude=nudge_point['longitude'], depth=start_point.depth)
            count += 1

        # We tried 16 times and couldn't find a point.  This should totally never happen.
        if count == 16:
            logger.debug("WOW. Could not find location in water to do shoreline calculation with.  Assuming particle did not move from original location")
            return start_point

        # Keep trying to throw particle back, halfing the distance each time until it is in water.
        # Only half it 12 times before giving up and returning the point which the particle came from.
        count = 0
        # Distance amount to half each iteration
        changing_distance = reverse_distance
        new_point = AsaGreatCircle.great_circle(distance=reverse_distance, azimuth=random_azimuth, start_point=hit_point)
        new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)
        while self.intersect(start_point=nudge_loc.point, end_point=new_loc.point) and count < 12:
            changing_distance /= 2
            new_point = AsaGreatCircle.great_circle(distance=changing_distance, azimuth=random_azimuth, start_point=hit_point)
            new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)
            count += 1

        # We tried 10 times and the particle was still on shore, return the point the particle started from.
        # No randomization.
        if count == 12:
            logger.debug("Could not react particle with shoreline.  Assuming particle did not move from original location")
            return start_point

        return new_loc
Example #4
0
    def near_xy(self, **kwargs):
        """
            TODO: Implement ncell near_xy
        """
        point = kwargs.get("point", None)
        if point == None:
            lat = kwargs.get("lat", None)
            lon = kwargs.get("lon", None)
            point = Location4D(latitude=lat, longitude=lon)
        num = kwargs.get("num", 1)
        ncell = kwargs.get("ncell", False)
        if ncell:
            if num > 1:
                pass
            else:
                distance = AsaGreatCircle.great_distance(
                    start_lats=self._yarray,
                    start_lons=self._xarray,
                    end_lats=point.latitude,
                    end_lons=point.longitude)["distance"]
                inds = np.where(distance == np.nanmin(distance))
                xinds, yinds = inds, inds
        else:
            if self._ndim == 2:
                distance = AsaGreatCircle.great_distance(
                    start_lats=self._yarray,
                    start_lons=self._xarray,
                    end_lats=point.latitude,
                    end_lons=point.longitude)["distance"]
                yinds, xinds = np.where(distance == np.nanmin(distance))
            else:
                #if self._xmesh == None and self._ymesh == None:
                #    self._xmesh, self._ymesh = np.meshgrid(self._xarray, self._yarray)
                if num > 1:
                    minlat = np.abs(self._yarray - point.latitude)
                    minlon = np.abs(self._xarray - point.longitude)
                    lat_cutoff = np.sort(minlat)[num - 1]
                    lon_cutoff = np.sort(minlon)[num - 1]
                elif num == 1:
                    lat_cutoff = np.nanmin(
                        np.abs(self._yarray - point.latitude))
                    lon_cutoff = np.nanmin(
                        np.abs(self._xarray - point.longitude))
                yinds = np.where(
                    np.abs(self._yarray - point.latitude) <= lat_cutoff)
                xinds = np.where(
                    np.abs(self._xarray - point.longitude) <= lon_cutoff)

        return yinds, xinds
Example #5
0
    def test_reverse_half_distance_until_in_water(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending   = Location4D(latitude=38.96, longitude=-75.315, depth=0)
        
        difference = AsaGreatCircle.great_distance(start_point=starting, end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point, end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(  start_point = starting,
                                hit_point = int4d,
                                end_point = ending,
                                feature = intersection['feature'],
                                distance = distance,
                                angle = angle,
                                azimuth = difference['azimuth'],
                                reverse_azimuth = difference['reverse_azimuth'],
                                reverse_distance = 40000)

        # Should be in water
        assert s.intersect(start_point=final_point.point, end_point=final_point.point) is None
Example #6
0
    def test_reverse_left(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.1, longitude=-74.91, depth=0)
        ending   = Location4D(latitude=39.1, longitude=-74.85, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting, end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point, end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(  start_point = starting,
                                hit_point = int4d,
                                end_point = ending,
                                feature = intersection['feature'],
                                distance = distance,
                                angle = angle,
                                azimuth = difference['azimuth'],
                                reverse_azimuth = difference['reverse_azimuth'])

        # Since we are on a stright horizonal line, the latitude will change only slightly
        assert abs(final_point.latitude - starting.latitude) < 0.005

        # Resulting longitude should be between the startpoint and the intersection point
        assert final_point.longitude < int4d.longitude
        assert final_point.longitude > starting.longitude
Example #7
0
    def test_reverse_up_left(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending   = Location4D(latitude=38.96, longitude=-75.315, depth=0)
        
        difference = AsaGreatCircle.great_distance(start_point=starting, end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point, end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(  start_point = starting,
                                hit_point = int4d,
                                end_point = ending,
                                feature = intersection['feature'],
                                distance = distance,
                                angle = angle,
                                azimuth = difference['azimuth'],
                                reverse_azimuth = difference['reverse_azimuth'])

        # Resulting latitude should be between the startpoint and the intersection point
        assert final_point.latitude > int4d.latitude
        assert final_point.latitude < starting.latitude
        
        # Resulting longitude should be between the startpoint and the intersection point
        assert final_point.longitude < int4d.longitude
        assert final_point.longitude > starting.longitude
    def test_reverse_distance_traveled(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending = Location4D(latitude=38.96, longitude=-75.315, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting,
                                                   end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point,
                                   end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(start_point=starting,
                              hit_point=int4d,
                              end_point=ending,
                              feature=intersection['feature'],
                              distance=distance,
                              angle=angle,
                              azimuth=difference['azimuth'],
                              reverse_azimuth=difference['reverse_azimuth'],
                              reverse_distance=0.000001)

        # Resulting point should be VERY close to the hit point.
        assert abs(int4d.latitude - final_point.latitude) < 0.005
        assert abs(int4d.longitude - final_point.longitude) < 0.005
    def test_reverse_left(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.1, longitude=-74.91, depth=0)
        ending = Location4D(latitude=39.1, longitude=-74.85, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting,
                                                   end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point,
                                   end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(start_point=starting,
                              hit_point=int4d,
                              end_point=ending,
                              feature=intersection['feature'],
                              distance=distance,
                              angle=angle,
                              azimuth=difference['azimuth'],
                              reverse_azimuth=difference['reverse_azimuth'])

        # Since we are on a stright horizonal line, the latitude will change only slightly
        assert abs(final_point.latitude - starting.latitude) < 0.005

        # Resulting longitude should be between the startpoint and the intersection point
        assert final_point.longitude < int4d.longitude
        assert final_point.longitude > starting.longitude
Example #10
0
    def test_reverse_distance_traveled(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending   = Location4D(latitude=38.96, longitude=-75.315, depth=0)
        
        difference = AsaGreatCircle.great_distance(start_point=starting, end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point, end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(  start_point = starting,
                                hit_point = int4d,
                                end_point = ending,
                                feature = intersection['feature'],
                                distance = distance,
                                angle = angle,
                                azimuth = difference['azimuth'],
                                reverse_azimuth = difference['reverse_azimuth'],
                                reverse_distance = 0.000001)

        # Resulting point should be VERY close to the hit point.
        assert abs(int4d.latitude - final_point.latitude) < 0.005
        assert abs(int4d.longitude - final_point.longitude) < 0.005
    def test_reverse_12_times_then_start_point(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending = Location4D(latitude=38.96, longitude=-75.315, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting,
                                                   end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point,
                                   end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(start_point=starting,
                              hit_point=int4d,
                              end_point=ending,
                              feature=intersection['feature'],
                              distance=distance,
                              angle=angle,
                              azimuth=difference['azimuth'],
                              reverse_azimuth=difference['reverse_azimuth'],
                              reverse_distance=9999999999999999999999999999)

        # Should be start location
        assert final_point.longitude == starting.longitude
        assert final_point.latitude == starting.latitude
        assert final_point.depth == starting.depth
    def test_reverse_half_distance_until_in_water(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending = Location4D(latitude=38.96, longitude=-75.315, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting,
                                                   end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point,
                                   end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(start_point=starting,
                              hit_point=int4d,
                              end_point=ending,
                              feature=intersection['feature'],
                              distance=distance,
                              angle=angle,
                              azimuth=difference['azimuth'],
                              reverse_azimuth=difference['reverse_azimuth'],
                              reverse_distance=40000)

        # Should be in water
        assert s.intersect(start_point=final_point.point,
                           end_point=final_point.point) is None
    def test_reverse_up_left(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending = Location4D(latitude=38.96, longitude=-75.315, depth=0)

        difference = AsaGreatCircle.great_distance(start_point=starting,
                                                   end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point,
                                   end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(start_point=starting,
                              hit_point=int4d,
                              end_point=ending,
                              feature=intersection['feature'],
                              distance=distance,
                              angle=angle,
                              azimuth=difference['azimuth'],
                              reverse_azimuth=difference['reverse_azimuth'])

        # Resulting latitude should be between the startpoint and the intersection point
        assert final_point.latitude > int4d.latitude
        assert final_point.latitude < starting.latitude

        # Resulting longitude should be between the startpoint and the intersection point
        assert final_point.longitude < int4d.longitude
        assert final_point.longitude > starting.longitude
Example #14
0
    def test_reverse_10_times_then_start_point(self):

        s = Shoreline(type='reverse')

        starting = Location4D(latitude=39.05, longitude=-75.34, depth=0)
        ending   = Location4D(latitude=38.96, longitude=-75.315, depth=0)
        
        difference = AsaGreatCircle.great_distance(start_point=starting, end_point=ending)
        angle = AsaMath.azimuth_to_math_angle(azimuth=difference['azimuth'])
        distance = difference['distance']

        intersection = s.intersect(start_point=starting.point, end_point=ending.point)
        int4d = Location4D(point=intersection['point'])

        final_point = s.react(  start_point = starting,
                                hit_point = int4d,
                                end_point = ending,
                                feature = intersection['feature'],
                                distance = distance,
                                angle = angle,
                                azimuth = difference['azimuth'],
                                reverse_azimuth = difference['reverse_azimuth'],
                                reverse_distance = 9999999999999999999999999999)

        # Should be start location
        assert final_point.longitude == starting.longitude
        assert final_point.latitude == starting.latitude
        assert final_point.depth == starting.depth
Example #15
0
    def __bounce(self, **kwargs):
        """
            Bounce off of the shoreline.

            NOTE: This does not work, but left here for future implementation

            feature = Linestring of two points, being the line segment the particle hit.
            angle = decimal degrees from 0 (x-axis), couter-clockwise (math style)
        """
        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        end_point = kwargs.pop('end_point')
        feature = kwargs.pop('feature')
        distance = kwargs.pop('distance')
        angle = kwargs.pop('angle')

        # Figure out the angle of the shoreline here (beta)
        points_in_shore = map(lambda x: Point(x), list(feature.coords))
        points_in_shore = sorted(points_in_shore, key=lambda x: x.x)

        # The point on the left (least longitude is always the first Point)
        first_shore = points_in_shore[0]
        last_shore = points_in_shore[-1]

        shoreline_x = abs(abs(first_shore.x) - abs(last_shore.x))
        shoreline_y = abs(abs(first_shore.y) - abs(last_shore.y))
        beta = math.degrees(math.atan(shoreline_x / shoreline_y))

        theta = 90 - angle - beta
        bounce_azimuth = AsaMath.math_angle_to_azimuth(angle=2 * theta + angle)

        print "Beta:           " + str(beta)
        print "Incoming Angle: " + str(angle)
        print "ShorelineAngle: " + str(theta + angle)
        print "Bounce Azimuth: " + str(bounce_azimuth)
        print "Bounce Angle:   " + str(
            AsaMath.azimuth_to_math_angle(azimuth=bounce_azimuth))

        after_distance = distance - AsaGreatCircle.great_distance(
            start_point=start_point, end_point=hit_point)['distance']

        new_point = AsaGreatCircle.great_circle(distance=after_distance,
                                                azimuth=bounce_azimuth,
                                                start_point=hit_point)
        return Location4D(latitude=new_point['latitude'],
                          longitude=new_point['longitude'],
                          depth=start_point.depth)
Example #16
0
    def __bounce(self, **kwargs):
        """
            Bounce off of the shoreline.

            NOTE: This does not work, but left here for future implementation

            feature = Linestring of two points, being the line segment the particle hit.
            angle = decimal degrees from 0 (x-axis), couter-clockwise (math style)
        """
        start_point = kwargs.pop("start_point")
        hit_point = kwargs.pop("hit_point")
        end_point = kwargs.pop("end_point")
        feature = kwargs.pop("feature")
        distance = kwargs.pop("distance")
        angle = kwargs.pop("angle")

        # Figure out the angle of the shoreline here (beta)
        points_in_shore = map(lambda x: Point(x), list(feature.coords))
        points_in_shore = sorted(points_in_shore, key=lambda x: x.x)

        # The point on the left (least longitude is always the first Point)
        first_shore = points_in_shore[0]
        last_shore = points_in_shore[-1]

        shoreline_x = abs(abs(first_shore.x) - abs(last_shore.x))
        shoreline_y = abs(abs(first_shore.y) - abs(last_shore.y))
        beta = math.degrees(math.atan(shoreline_x / shoreline_y))

        theta = 90 - angle - beta
        bounce_azimuth = AsaMath.math_angle_to_azimuth(angle=2 * theta + angle)

        print "Beta:           " + str(beta)
        print "Incoming Angle: " + str(angle)
        print "ShorelineAngle: " + str(theta + angle)
        print "Bounce Azimuth: " + str(bounce_azimuth)
        print "Bounce Angle:   " + str(AsaMath.azimuth_to_math_angle(azimuth=bounce_azimuth))

        after_distance = (
            distance - AsaGreatCircle.great_distance(start_point=start_point, end_point=hit_point)["distance"]
        )

        new_point = AsaGreatCircle.great_circle(distance=after_distance, azimuth=bounce_azimuth, start_point=hit_point)
        return Location4D(latitude=new_point["latitude"], longitude=new_point["longitude"], depth=start_point.depth)
Example #17
0
    def __reverse(self, **kwargs):
        """
            Reverse particle just off of the shore in the direction that it came in.
            Adds a slight random factor to the distance and angle it is reversed in.
        """
        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        distance = kwargs.pop('distance')
        azimuth = kwargs.pop('azimuth')
        reverse_azimuth = kwargs.pop('reverse_azimuth')
        reverse_distance = kwargs.get('reverse_distance', None)
        if reverse_distance is None:
            reverse_distance = 100

        # Randomize the reverse angle slightly (+/- 5 degrees)
        random_azimuth = reverse_azimuth + AsaRandom.random() * 5

        # Nudge the hitpoint off of the shore by a tiny bit to test shoreline intersection in while loop.
        nudged_hit_point = AsaGreatCircle.great_circle(distance=0.01, azimuth=random_azimuth, start_point=hit_point)
        nudged_hit_location = Location4D(latitude=nudged_hit_point['latitude'], longitude=nudged_hit_point['longitude'], depth=start_point.depth)

        new_point = AsaGreatCircle.great_circle(distance=reverse_distance, azimuth=random_azimuth, start_point=hit_point)
        new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)

        # Keep trying to throw particle back, halfing the distance each time until it is in water.
        # Only half it 10 times before giving up and returning the point which the particle came from.
        count = 0
        # Distance amount to half each iteration
        changing_distance = reverse_distance
        while self.intersect(start_point=nudged_hit_location.point, end_point=new_loc.point) and count < 10:
            changing_distance /= 2
            new_point = AsaGreatCircle.great_circle(distance=changing_distance, azimuth=random_azimuth, start_point=hit_point)
            new_loc = Location4D(latitude=new_point['latitude'], longitude=new_point['longitude'], depth=start_point.depth)
            count += 1

        # We tried 10 times and the particle was still on shore, return the point the particle started from.
        # No randomization.
        if count == 10:
            logger.warn("Could not react particle with shoreline.  Assuming particle did not move from original location")
            new_loc = start_point

        return new_loc
Example #18
0
    def near_xy(self, **kwargs):
        """
            TODO: Implement ncell near_xy
        """
        point = kwargs.get("point", None)
        if point == None:
            lat = kwargs.get("lat", None)
            lon = kwargs.get("lon", None)
            point = Location4D(latitude=lat, longitude=lon)
        num = kwargs.get("num", 1)
        ncell = kwargs.get("ncell", False)
        if ncell:
            if num > 1:
                pass
            else:
                distance = AsaGreatCircle.great_distance(
                    start_lats=self._yarray, start_lons=self._xarray, end_lats=point.latitude, end_lons=point.longitude
                )["distance"]
                inds = np.where(distance == np.nanmin(distance))
                xinds, yinds = inds, inds
        else:
            if self._ndim == 2:
                distance = AsaGreatCircle.great_distance(
                    start_lats=self._yarray, start_lons=self._xarray, end_lats=point.latitude, end_lons=point.longitude
                )["distance"]
                yinds, xinds = np.where(distance == np.nanmin(distance))
            else:
                # if self._xmesh == None and self._ymesh == None:
                #    self._xmesh, self._ymesh = np.meshgrid(self._xarray, self._yarray)
                if num > 1:
                    minlat = np.abs(self._yarray - point.latitude)
                    minlon = np.abs(self._xarray - point.longitude)
                    lat_cutoff = np.sort(minlat)[num - 1]
                    lon_cutoff = np.sort(minlon)[num - 1]
                elif num == 1:
                    lat_cutoff = np.nanmin(np.abs(self._yarray - point.latitude))
                    lon_cutoff = np.nanmin(np.abs(self._xarray - point.longitude))
                yinds = np.where(np.abs(self._yarray - point.latitude) <= lat_cutoff)
                xinds = np.where(np.abs(self._xarray - point.longitude) <= lon_cutoff)

        return yinds, xinds
Example #19
0
    def distance_from_location_using_u_v_w(cls, u=None, v=None, w=None, timestep=None, location=None):
        """
            Calculate the greate distance from a location using u, v, and w.

            u, v, and w must be in the same units as the timestep.  Stick with seconds.

        """
        # Move horizontally
        distance_horiz = 0
        azimuth = 0
        angle = 0
        depth = location.depth

        if u is not 0 and v is not 0:
            s_and_d = AsaMath.speed_direction_from_u_v(u=u,v=v) # calculates velocity in m/s from transformed u and v
            distance_horiz = s_and_d['speed'] * timestep # calculate the horizontal distance in meters using the velocity and model timestep
            angle = s_and_d['direction']
            # Great circle calculation 
            # Calculation takes in azimuth (heading from North, so convert our mathematical angle to azimuth)
            azimuth = AsaMath.math_angle_to_azimuth(angle=angle)
            
        distance_vert = 0.
        if w is not None:
            # Move vertically
            # Depth is positive up, negative down.  w wil be negative if moving down, and positive if moving up
            distance_vert = w * timestep
            depth += distance_vert # calculate the vertical distance in meters using w (m/s) and model timestep (s)
            

        if distance_horiz != 0:
            vertical_angle = math.degrees(math.atan(distance_vert / distance_horiz))
            gc_result = AsaGreatCircle.great_circle(distance=distance_horiz, azimuth=azimuth, start_point=location) 
        else:
            # Did we go up or down?
            vertical_angle = 0.
            if distance_vert < 0:
                # Down
                vertical_angle = 270.
            elif distance_vert > 0:
                # Up
                vertical_angle = 90.
            gc_result = { 'latitude': location.latitude, 'longitude': location.longitude, 'reverse_azimuth': 0 }
            
        #logger.info("Particle moving from %fm to %fm from a vertical speed of %f m/s over %s seconds" % (location.depth, depth, w, str(timestep)))            
        gc_result['azimuth'] = azimuth
        gc_result['depth'] = depth
        gc_result['distance'] = distance_horiz
        gc_result['angle'] = angle
        gc_result['vertical_distance'] = distance_vert
        gc_result['vertical_angle'] = vertical_angle
        return gc_result
Example #20
0
    def __reverse(self, **kwargs):
        """
            Reverse particle just off of the shore in the direction that it came in.
            Adds a slight random factor to the distance and angle it is reversed in.
        """
        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        distance = kwargs.pop('distance')
        azimuth = kwargs.pop('azimuth')
        reverse_azimuth = kwargs.pop('reverse_azimuth')
        reverse_distance = kwargs.get('reverse_distance', None)
        if reverse_distance is None:
            reverse_distance = 100

        # Randomize the reverse angle slightly (+/- 5 degrees)
        random_azimuth = reverse_azimuth + AsaRandom.random() * 5

        count = 0
        nudge_distance = 0.01
        nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance,
                                                  azimuth=reverse_azimuth,
                                                  start_point=hit_point)
        nudge_loc = Location4D(latitude=nudge_point['latitude'],
                               longitude=nudge_point['longitude'],
                               depth=start_point.depth)

        # Find point just offshore to do testing with.  Try 15 times (~350m).  This makes sure the start_point is in the water
        # for the next call to intersect (next while loop).
        while self.intersect(single_point=nudge_loc.point) and count < 16:
            nudge_distance *= 2
            nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance,
                                                      azimuth=reverse_azimuth,
                                                      start_point=hit_point)
            nudge_loc = Location4D(latitude=nudge_point['latitude'],
                                   longitude=nudge_point['longitude'],
                                   depth=start_point.depth)
            count += 1

        # We tried 16 times and couldn't find a point.  This should totally never happen.
        if count == 16:
            logger.debug(
                "WOW. Could not find location in water to do shoreline calculation with.  Assuming particle did not move from original location"
            )
            return start_point

        # Keep trying to throw particle back, halfing the distance each time until it is in water.
        # Only half it 12 times before giving up and returning the point which the particle came from.
        count = 0
        # Distance amount to half each iteration
        changing_distance = reverse_distance
        new_point = AsaGreatCircle.great_circle(distance=reverse_distance,
                                                azimuth=random_azimuth,
                                                start_point=hit_point)
        new_loc = Location4D(latitude=new_point['latitude'],
                             longitude=new_point['longitude'],
                             depth=start_point.depth)
        while self.intersect(start_point=nudge_loc.point,
                             end_point=new_loc.point) and count < 12:
            changing_distance /= 2
            new_point = AsaGreatCircle.great_circle(distance=changing_distance,
                                                    azimuth=random_azimuth,
                                                    start_point=hit_point)
            new_loc = Location4D(latitude=new_point['latitude'],
                                 longitude=new_point['longitude'],
                                 depth=start_point.depth)
            count += 1

        # We tried 10 times and the particle was still on shore, return the point the particle started from.
        # No randomization.
        if count == 12:
            logger.debug(
                "Could not react particle with shoreline.  Assuming particle did not move from original location"
            )
            return start_point

        return new_loc
Example #21
0
    def __reverse(self, **kwargs):
        """
            Reverse particle just off of the shore in the direction that it came in.
            Adds a slight random factor to the distance and angle it is reversed in.
        """

        #st = time.clock()

        start_point = kwargs.pop('start_point')
        hit_point = kwargs.pop('hit_point')
        reverse_azimuth = kwargs.pop('reverse_azimuth')
        reverse_distance = kwargs.get('reverse_distance', None)
        if reverse_distance is None:
            reverse_distance = 100

        # Randomize the reverse angle slightly (+/- 5 degrees)
        random_azimuth = reverse_azimuth + AsaRandom.random() * 5

        count = 0
        nudge_distance = 0.01
        nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance,
                                                  azimuth=reverse_azimuth,
                                                  start_point=hit_point)
        nudge_loc = Location4D(latitude=nudge_point['latitude'],
                               longitude=nudge_point['longitude'],
                               depth=start_point.depth)

        # Find point just offshore to do testing with.  Try 15 times (~350m).  This makes sure the start_point is in the water
        # for the next call to intersect (next while loop).
        while self.intersect(single_point=nudge_loc.point) and count < 16:
            nudge_distance *= 2
            nudge_point = AsaGreatCircle.great_circle(distance=nudge_distance,
                                                      azimuth=reverse_azimuth,
                                                      start_point=hit_point)
            nudge_loc = Location4D(latitude=nudge_point['latitude'],
                                   longitude=nudge_point['longitude'],
                                   depth=start_point.depth)
            count += 1

        # We tried 16 times and couldn't find a point.  This should totally never happen.
        if count == 16:
            logger.warn(
                "LOOK: Could not find location in water to do shoreline calculation with.  Assuming particle did not move from original location"
            )
            return start_point

        # Keep trying to throw particle back, halfing the distance each time until it is in water.
        # Only half it 6 times before giving up and returning the point which the particle came from.
        count = 0
        # Distance amount to half each iteration
        changing_distance = reverse_distance
        new_point = AsaGreatCircle.great_circle(distance=reverse_distance,
                                                azimuth=random_azimuth,
                                                start_point=hit_point)
        new_loc = Location4D(latitude=new_point['latitude'],
                             longitude=new_point['longitude'],
                             depth=start_point.depth)

        # We don't want to reverse further than the current spatial buffer, because we will reindex the
        # source file everytime we reverse, which will slow down the calculations considerably.
        while (not self._spatial_query_object.contains(new_loc.point)
               or self.intersect(start_point=nudge_loc.point,
                                 end_point=new_loc.point)) and count < 6:
            changing_distance /= 2
            new_point = AsaGreatCircle.great_circle(distance=changing_distance,
                                                    azimuth=random_azimuth,
                                                    start_point=hit_point)
            new_loc = Location4D(latitude=new_point['latitude'],
                                 longitude=new_point['longitude'],
                                 depth=start_point.depth)
            count += 1

        # We tried 10 times and the particle was still on shore, return the point the particle started from.
        # No randomization.
        if count == 6:
            logger.warn(
                "LOOK: Could not react particle with shoreline.  Assuming particle did not move from original location"
            )
            return start_point

        #logger.info("Reaction time: %f" % (time.clock() - st))
        return new_loc