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
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
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
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
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_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
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
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
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
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)
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)
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
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
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
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
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