@@ -534,6 +534,7 @@ def VerticalMixing(particle, fieldset, time):
534534 # Update particle position
535535 particle_ddepth += ddepth # noqa
536536
537+
537538def reflectAtSurface (particle , fieldset , time ):
538539 """A reflecting boundary condition kernel at the ocean surface.
539540
@@ -595,6 +596,103 @@ def unbeaching(particle, fieldset, time):
595596 particle_dlon += dlon # noqa
596597 particle_dlat += dlat # noqa
597598
599+ def unbeachingBySamplingAfterwards (particle , fieldset , time ):
600+ """Alternative unbeaching kernel.
601+
602+ Description
603+ ----------
604+ A kernel to 'unbeach' particles that have been advected onto non-ocean grid cells.
605+ This kernel samples the velocity field in the four cardinal directions around the particle,
606+ and moves the particle in the direction of the highest velocity magnitude, assuming that
607+ this direction is the ocean direction. This kernel only acts if the particle displacement
608+ in both zonal and meridional directions is (near) zero, indicating that the particle is beached.
609+
610+ Parameter Requirements
611+ ----------
612+ Fieldset:
613+ None
614+
615+ Kernel Requirements
616+ ----------
617+ Order of Operations:
618+ This kernel should be performed after all other movement kernels.
619+ """
620+ # In the case of being beached, these displacement will be zero
621+ new_lon = particle .lon + particle_dlon
622+ new_lat = particle .lat + particle_dlat
623+ new_depth = particle .depth + particle_ddepth
624+
625+ if math .fabs (particle_dlon ) + math .fabs (particle_dlat ) < 1e-14 :
626+ displacement = 1. / 8. # Degree displacement to sample the velocity field
627+
628+ # Convert 1m/s to degrees/s at the particle latitude in zonal and meridional directions
629+ unbeach_U = 1. / (1852. * 60. * math .cos (particle .lat * math .pi / 180. ))
630+ unbeach_V = 1. / (1852. * 60. )
631+
632+ # Sample the velocity field in the four cardinal directions
633+ (U_left , V_left ) = fieldset .UV [time , new_depth , new_lat , new_lon - displacement ]
634+ (U_right , V_right ) = fieldset .UV [time , new_depth , new_lat , new_lon + displacement ]
635+ (U_up , V_up ) = fieldset .UV [time , new_depth , new_lat + displacement , new_lon ]
636+ (U_down , V_down ) = fieldset .UV [time , new_depth , new_lat - displacement , new_lon ]
637+
638+ # Find the direction of the highest velocity
639+ left = math .sqrt (U_left ** 2 + V_left ** 2 )
640+ right = math .sqrt (U_right ** 2 + V_right ** 2 )
641+ up = math .sqrt (U_up ** 2 + V_up ** 2 )
642+ down = math .sqrt (U_down ** 2 + V_down ** 2 )
643+
644+ max_vel = 0.
645+ U_dir = 0.
646+ V_dir = 0.
647+
648+ if left + right + up + down > 1e-14 :
649+ max_vel = left
650+ U_dir = - 1.
651+ V_dir = 0.
652+ if max_vel < right :
653+ max_vel = right
654+ U_dir = 1.
655+ V_dir = 0.
656+ if max_vel < up :
657+ max_vel = up
658+ U_dir = 0.
659+ V_dir = 1.
660+ if max_vel < down :
661+ max_vel = down
662+ U_dir = 0.
663+ V_dir = - 1.
664+
665+ # If all four cardinal directions are zero, check diagonal directions
666+ else :
667+ (U_left_up , V_left_up ) = fieldset .UV [time , new_depth , new_lat + displacement , new_lon - displacement ]
668+ (U_left_down , V_left_down ) = fieldset .UV [time , new_depth , new_lat - displacement , new_lon - displacement ]
669+ (U_right_up , V_right_up ) = fieldset .UV [time , new_depth , new_lat + displacement , new_lon + displacement ]
670+ (U_right_down , V_right_down ) = fieldset .UV [time , new_depth , new_lat - displacement , new_lon + displacement ]
671+
672+ left_up = math .sqrt (U_left_up ** 2 + V_left_up ** 2 )
673+ left_down = math .sqrt (U_left_down ** 2 + V_left_down ** 2 )
674+ right_up = math .sqrt (U_right_up ** 2 + V_right_up ** 2 )
675+ right_down = math .sqrt (U_right_down ** 2 + V_right_down ** 2 )
676+
677+ max_vel = left_up
678+ U_dir = - 1.
679+ V_dir = 1.
680+ if max_vel < left_down :
681+ max_vel = left_down
682+ U_dir = 1.
683+ V_dir = - 1.
684+ if max_vel < right_up :
685+ max_vel = right_up
686+ U_dir = 1.
687+ V_dir = 1.
688+ if max_vel < right_down :
689+ max_vel = right_down
690+ U_dir = 1.
691+ V_dir = - 1.
692+
693+ particle_dlon += U_dir * unbeach_U * particle .dt
694+ particle_dlat += V_dir * unbeach_V * particle .dt
695+
598696
599697def checkThroughBathymetry (particle , fieldset , time ):
600698 """Bathymetry error kernel.
@@ -629,6 +727,7 @@ def checkThroughBathymetry(particle, fieldset, time):
629727 elif potential_depth > 3900. : # If particle >3.9km deep, stick it there
630728 particle_ddepth = 3900. - particle .depth # noqa
631729
730+
632731def reflectAtBathymetry (particle , fieldset , time ):
633732 """Reflect at bathymetry kernel.
634733
0 commit comments