def test_brownian_example(mode, npart=3000): fieldset = brownian_fieldset() # Set diffusion constants. fieldset.Kh_meridional = 100. fieldset.Kh_zonal = 100. # Set random seed random.seed(123456) ptcls_start = 300000. # Start all particles at same location in middle of grid. pset = ParticleSet.from_line(fieldset=fieldset, size=npart, pclass=ptype[mode], start=(ptcls_start, ptcls_start), finish=(ptcls_start, ptcls_start)) endtime = delta(days=1) dt = delta(hours=1) interval = delta(hours=1) k_brownian = pset.Kernel(two_dim_brownian_flat) pset.execute(k_brownian, endtime=endtime, dt=dt, interval=interval, output_file=pset.ParticleFile(name="BrownianParticle"), show_movie=False) lats = np.array([particle.lat for particle in pset.particles]) lons = np.array([particle.lon for particle in pset.particles]) expected_std_lat = np.sqrt(2*fieldset.Kh_meridional*endtime.total_seconds()) expected_std_lon = np.sqrt(2*fieldset.Kh_zonal*endtime.total_seconds()) assert np.allclose(np.std(lats), expected_std_lat, rtol=.1) assert np.allclose(np.std(lons), expected_std_lon, rtol=.1) assert np.allclose(np.mean(lons), ptcls_start, rtol=.1) assert np.allclose(np.mean(lats), ptcls_start, rtol=.1)
def test_brownian_example(mode, mesh, npart=3000): fieldset = FieldSet.from_data({'U': 0, 'V': 0}, {'lon': 0, 'lat': 0}, mesh=mesh) # Set diffusion constants. kh_zonal = 100 # in m^2/s kh_meridional = 100 # in m^2/s # Create field of constant Kh_zonal and Kh_meridional fieldset.add_field(Field('Kh_zonal', kh_zonal, lon=0, lat=0, mesh=mesh)) fieldset.add_field(Field('Kh_meridional', kh_meridional, lon=0, lat=0, mesh=mesh)) # Set random seed random.seed(123456) runtime = delta(days=1) random.seed(1234) pset = ParticleSet(fieldset=fieldset, pclass=ptype[mode], lon=np.zeros(npart), lat=np.zeros(npart)) pset.execute(pset.Kernel(DiffusionUniformKh), runtime=runtime, dt=delta(hours=1)) expected_std_x = np.sqrt(2*kh_zonal*runtime.total_seconds()) expected_std_y = np.sqrt(2*kh_meridional*runtime.total_seconds()) ys = pset.lat * mesh_conversion(mesh) xs = pset.lon * mesh_conversion(mesh) # since near equator, we do not need to care about curvature effect tol = 200 # 200m tolerance assert np.allclose(np.std(xs), expected_std_x, atol=tol) assert np.allclose(np.std(ys), expected_std_y, atol=tol) assert np.allclose(np.mean(xs), 0, atol=tol) assert np.allclose(np.mean(ys), 0, atol=tol)
def test_recursive_errorhandling(mode, xdim=2, ydim=2): """Example script to show how recursaive error handling can work. In this example, a set of Particles is started at Longitude 0.5. These are run through a Kernel that throws an error if the Longitude is smaller than 0.7. The error Kernel then draws a new random number between 0 and 1 Importantly, the 'normal' Kernel and Error Kernel keep iterating until a particle does have a longitude larger than 0.7. This behaviour can be useful if particles need to be 'pushed out' from e.g. land. Note however that current under-the-hood implementation is not extremely efficient, so code could be slow.""" dimensions = { 'lon': np.linspace(0., 1., xdim, dtype=np.float32), 'lat': np.linspace(0., 1., ydim, dtype=np.float32) } data = { 'U': np.zeros((ydim, xdim), dtype=np.float32), 'V': np.zeros((ydim, xdim), dtype=np.float32) } fieldset = FieldSet.from_data(data, dimensions, mesh='flat') # Set minimum value for valid longitudes (i.e. all longitudes < minlon are 'land') fieldset.add_constant('minlon', 0.7) # create a ParticleSet with all particles starting at centre of Field pset = ParticleSet.from_line(fieldset=fieldset, pclass=ptype[mode], start=(0.5, 0.5), finish=(0.5, 0.5), size=10) def TestLon(particle, fieldset, time): """Kernel to check whether a longitude is larger than fieldset.minlon. If not, the Kernel throws an error""" if particle.lon <= fieldset.minlon: return ErrorCode.Error def Error_RandomiseLon(particle, fieldset, time): """Error handling kernel that draws a new longitude. Note that this new longitude can be smaller than fieldset.minlon""" particle.lon = random.uniform(0., 1.) random.seed(123456) # The .execute below is only run for one timestep. Yet the # recovery={ErrorCode.Error: Error_RandomiseLon} assures Parcels keeps # attempting to move all particles beyond 0.7 longitude pset.execute(pset.Kernel(TestLon), runtime=1, dt=1, recovery={ErrorCode.Error: Error_RandomiseLon}) assert (np.array([p.lon for p in pset]) > fieldset.minlon).all()
def two_dim_brownian_flat(particle, grid, time, dt): # Kernel for simple Brownian particle diffusion in zonal and meridional direction. # Seed is called on first call only, when time is zero if time == 0: random.seed(grid.seedval) particle.lat += random.normalvariate(0, 1) * math.sqrt( 2 * dt * grid.Kh_meridional) particle.lon += random.normalvariate(0, 1) * math.sqrt( 2 * dt * grid.Kh_zonal)
def run_brownian(fieldset, npart, outfilename): # Set diffusion constants. fieldset.Kh_meridional = 100. fieldset.Kh_zonal = 100. # Set random seed random.seed(123456) pset = ParticleSet.from_line(fieldset=fieldset, size=npart, pclass=JITParticle, start=(0., 0.), finish=(0., 0.)) pset.execute(two_dim_brownian_flat, runtime=delta(days=1), dt=delta(minutes=5)) pset.ParticleFile(name=outfilename).write(pset, pset[0].time)
def test_brownian_example(mode, npart=3000): fieldset = zeros_fieldset() # Set diffusion constants. kh_zonal = 100 kh_meridional = 100 # Create field of Kh_zonal and Kh_meridional, using same grid as U grid = fieldset.U.grid fieldset.add_field(Field('Kh_zonal', kh_zonal * np.ones((2, 2)), grid=grid)) fieldset.add_field( Field('Kh_meridional', kh_meridional * np.ones((2, 2)), grid=grid)) # Set random seed random.seed(123456) runtime = delta(days=1) random.seed(1234) pset = ParticleSet(fieldset=fieldset, pclass=ptype[mode], lon=np.zeros(npart), lat=np.zeros(npart)) pset.execute(pset.Kernel(BrownianMotion2D), runtime=runtime, dt=delta(hours=1)) expected_std_x = np.sqrt(2 * kh_zonal * runtime.total_seconds()) expected_std_y = np.sqrt(2 * kh_meridional * runtime.total_seconds()) conversion = (1852 * 60) # to convert from degrees to m ys = np.array([p.lat for p in pset]) * conversion xs = np.array( [p.lon for p in pset] ) * conversion # since near equator, we do not need to care about curvature effect tol = 200 # 200m tolerance assert np.allclose(np.std(xs), expected_std_x, atol=tol) assert np.allclose(np.std(ys), expected_std_y, atol=tol) assert np.allclose(np.mean(xs), 0, atol=tol) assert np.allclose(np.mean(ys), 0, atol=tol)
fieldset = FieldSet.from_nemo(filenames, variables, dimensions, indices) #, transpose=True) fieldset.add_constant('maxage', 40. * 86400) fieldset.temp.interp_method = 'nearest' # Create field of Kh_zonal and Kh_meridional, using same grid as U #[time, depth, particle.lon, particle.lat] # Think this order is correct for here size4D = (30, 30, fieldset.U.grid.ydim, fieldset.U.grid.xdim) fieldset.add_field( Field('Kh_zonal', Kh_zonal * np.ones(size4D), grid=fieldset.temp.grid)) fieldset.add_field( Field('Kh_meridional', Kh_meridional * np.ones(size4D), grid=fieldset.temp.grid)) random.seed(123456) # Set random seed class SampleParticle(JITParticle): # Define a new particle class age = Variable('age', dtype=np.float32, initial=0.) # initialise age temp = Variable('temp', dtype=np.float32, initial=fieldset.temp) # initialise temperature bathy = Variable('bathy', dtype=np.float32, initial=fieldset.bathy) # initialise bathy distance = Variable('distance', initial=0., dtype=np.float32) # the distance travelled prev_lon = Variable('prev_lon', dtype=np.float32, to_write=False, initial=attrgetter('lon')) # the previous longitude prev_lat = Variable('prev_lat',