def base_model(): """ Channel """ g=unstructured_grid.UnstructuredGrid(max_sides=4) g.add_rectilinear([0,0],[1000,100],21,3) g.add_cell_field('depth',-6*np.ones(g.Ncells())) model=sun_driver.SuntansModel() model.load_template('point_source_test.dat') model.set_grid(g) model.run_start=np.datetime64("2018-01-01 00:00") model.run_stop =np.datetime64("2018-01-05 00:00") dt=np.timedelta64(600,'s') times=np.arange(model.run_start-dt,model.run_stop+2*dt,dt) secs=(times-times[0])/np.timedelta64(1,'s') eta0=-1 eta_bc=sun_driver.StageBC(name="eta_bc", geom=np.array([ [0,0], [0,100]]), z=eta0) model.add_bcs(eta_bc) model.add_bcs( [sun_driver.ScalarBC(parent=eta_bc,scalar="S",value=34), sun_driver.ScalarBC(parent=eta_bc,scalar="T",value=15)] ) model.set_run_dir('rundata_met_3d', mode='pristine') model.projection='EPSG:26910' model.num_procs=1 # test single first model.config['dt']=120 model.config['ntout']=5 model.config['Cmax']=30 model.config['Nkmax']=10 model.config['stairstep']=0 model.config['mergeArrays']=0 return model
def base_model_setup(L=100, dx=10): g = unstructured_grid.UnstructuredGrid(max_sides=4) g.add_rectilinear([0, 0], [L, 10], 1 + int(L / dx), 2) g.add_cell_field('depth', -6 * np.ones(g.Ncells())) model = sun_driver.SuntansModel() model.num_procs = 1 model.load_template('point_source_test.dat') model.set_grid(g) model.run_start = np.datetime64("2018-01-01 00:00") model.run_stop = np.datetime64("2018-01-02 00:00") # 50m2, 5.0 m3/s, 0.1m/s source = sun_driver.FlowBC(name='inflow', geom=np.array([[0, 0], [0, 10]]), Q=10.0) outlet = sun_driver.StageBC(name='outflow', geom=np.array([[100, 0], [100, 10]]), z=-1) model.add_bcs([source, outlet]) model.set_run_dir('rundata_2d_average', mode='pristine') model.projection = 'EPSG:26910' model.config['dt'] = 2.5 model.config['ntout'] = 100 model.config['ntaverage'] = 100 model.config['calcaverage'] = 1 model.config['averageNetcdfFile'] = "average.nc" model.config['thetaramptime'] = 100 model.config['Cmax'] = 2 model.config['Nkmax'] = 1 model.config['stairstep'] = 0 model.config['mergeArrays'] = 0 return model
nx=int(L/dx_lon),ny=int(W/dy_lat)) g.add_cell_field('depth',bathy(g.cells_center())) model.set_grid(g) model.config['maxFaces']=4 model.z_offset=0 from shapely import geometry feats=np.zeros( 2, [ ('name','O'), ('geom','O') ] ) feats[0]['name']='left' # HALF STEP: feats[0]['geom']=geometry.LineString( [ [0,W/2], [0,W] ] ) feats[1]['name']='right' feats[1]['geom']=geometry.LineString( [ [L,0], [L,W] ] ) model.add_gazetteer(feats) Q_left=drv.FlowBC(name='left',Q=200.0) h_right=drv.StageBC(name='right',z=0.0) model.add_bcs([Q_left,h_right]) model.write() model.partition() #model.run_simulation()
n1 = g.select_nodes_nearest([300, 0]) n2 = g.select_nodes_nearest([300, 500]) model = sun_driver.SuntansModel() model.load_template('sun-template.dat') model.set_grid(g) model.run_start = np.datetime64("2018-01-01 00:00") model.run_stop = np.datetime64("2018-01-01 10:00") dt = np.timedelta64(600, 's') times = np.arange(model.run_start - dt, model.run_stop + 2 * dt, dt) secs = (times - times[0]) / np.timedelta64(1, 's') eta_values = -6 + 0.75 * np.cos(secs * np.pi / 7200) eta_da = xr.DataArray(eta_values, coords=[('time', times)]) eta_bc = sun_driver.StageBC(name="eta_bc", geom=np.array([[0, 0], [0, 500]]), z=eta_da) model.add_bcs(eta_bc) model.add_bcs([ sun_driver.ScalarBC(parent=eta_bc, scalar="S", value=1), sun_driver.ScalarBC(parent=eta_bc, scalar="T", value=1) ]) # point source that is typically dry hill_source = sun_driver.SourceSinkBC(name='inflow', geom=np.array([150, 150]), z=-10, Q=1.0) # on a saddle
model.add_gazetteer("gis/forcing-v00.shp") Q_upstream = drv.FlowBC(name='SJ_upstream', Q=250.0) Qdown = -100 # target outflow # ramp up to the full outflow over 1h h = np.timedelta64(1, 'h') Qdown = xr.DataArray( data=[0, 0, Qdown, Qdown, Qdown], name='Q', dims=['time'], coords=dict(time=[ model.run_start - 24 * h, model.run_start, model.run_start + ramp_hours * h, model.run_stop, model.run_stop + 24 * h ])) Q_downstream = drv.FlowBC(name='SJ_downstream', Q=Qdown) h_old_river = drv.StageBC(name='Old_River', z=2.2 - 0.65) model.add_bcs([Q_upstream, Q_downstream, h_old_river]) model.write() #-- if 0: # Add in variable roughness ec = model.grid.edges_center() z0_map = field.GdalGrid("../../bathy/composite-roughness.tif") z0 = z0_map(ec) z0[np.isnan(z0)] = float(model.config['z0B']) model.ic_ds['z0B'] = ('time', 'Ne'), z0[None, :] model.write_ic_ds()
def test_point_source_3d(): """ A square 3D grid with wetting and drying. the bathymetry is a wavy cos(x)*cos(y) function. two point sources and an oscillating freesurface. one point source at a saddle point, and the other on top of a bump which goes dry. This currently does pretty well, but it could be better -- see the test thresholds near the end which have been relaxed somewhat. """ g=unstructured_grid.UnstructuredGrid(max_sides=4) g.add_rectilinear([0,0],[500,500],50,50) # wavy bed half_wave=150 cc=g.cells_center() cell_depth=-6 + np.cos(cc[:,0]*np.pi/half_wave) * np.cos(cc[:,1]*np.pi/half_wave) g.add_cell_field('depth',cell_depth) model=sun_driver.SuntansModel() model.load_template('point_source_test.dat') model.set_grid(g) model.run_start=np.datetime64("2018-01-01 00:00") model.run_stop =np.datetime64("2018-01-01 10:00") dt=np.timedelta64(600,'s') times=np.arange(model.run_start-dt,model.run_stop+2*dt,dt) secs=(times-times[0])/np.timedelta64(1,'s') eta_values=-6 + 0.75*np.cos(secs*np.pi/7200) eta_da=xr.DataArray(eta_values,coords=[ ('time',times) ]) eta_bc=sun_driver.StageBC(name="eta_bc",geom=np.array([ [0,0], [0,500]]), z=eta_da) model.add_bcs(eta_bc) model.add_bcs( [sun_driver.ScalarBC(parent=eta_bc,scalar="S",value=1), sun_driver.ScalarBC(parent=eta_bc,scalar="T",value=1)] ) # point source that is typically dry hill_source=sun_driver.SourceSinkBC(name='inflow',geom=np.array([150,150]), z=-10,Q=1.0) # on a saddle saddle_source=sun_driver.SourceSinkBC(name='inflow',geom=np.array([220,225]), z=-10,Q=1.0) model.add_bcs(hill_source) model.add_bcs(saddle_source) model.add_bcs( [sun_driver.ScalarBC(parent=hill_source,scalar="S",value=1), sun_driver.ScalarBC(parent=hill_source,scalar="T",value=1)] ) model.add_bcs( [sun_driver.ScalarBC(parent=saddle_source,scalar="S",value=1), sun_driver.ScalarBC(parent=saddle_source,scalar="T",value=1)] ) model.set_run_dir('rundata_point_3d', mode='pristine') model.projection='EPSG:26910' model.num_procs=4 model.config['dt']=2.5 model.config['ntout']=5 model.config['Cmax']=30 model.config['Nkmax']=10 model.config['stairstep']=0 model.config['mergeArrays']=0 model.write() model.ic_ds.eta.values[:]=eta_da.values[1] model.ic_ds.salt.values[:]=1.0 model.ic_ds.temp.values[:]=1.0 model.write_ic_ds() model.partition() model.sun_verbose_flag='-v' model.run_simulation() for map_fn in model.map_outputs(): ds=xr.open_dataset(map_fn) dzz=ds.dzz.values # This is not as strict as it should be. # should be 0.001 or less. dzz_thresh=0.05 salt=ds.salt.values valid=np.isfinite(dzz) & (dzz>=dzz_thresh) salt_errors=salt[valid] - 1.0 # This is not as strict as it should be. # we should be able to get this down to 1e-4 or # better. assert np.max( np.abs(salt_errors) )<0.01 ds.close()
model.add_gazetteer("grid-lsb/linear_features.shp") ## ocean_salt_bc = drv.ScalarBC(name='ocean', scalar='salinity', value=25) ocean_temp_bc = drv.ScalarBC(name='ocean', scalar='temperature', value=10) msl_navd88 = 0.94 # m ocean_bc = drv.NOAAStageBC( name='ocean', station=9414575, # Coyote - will come in as MSL # station=9414750, # Alameda. cache_dir=cache_dir, filters=[dfm.Lowpass(cutoff_hours=1.5)]) ocean_offset_bc = drv.StageBC(name='ocean', mode='add', z=z_offset_manual + msl_navd88) model.add_bcs([ocean_bc, ocean_salt_bc, ocean_temp_bc, ocean_offset_bc]) import sfb_common # sfb_common.add_usgs_stream_bcs(model,cache_dir) # disable if no internet # sfb_common.add_potw_bcs(model,cache_dir) if __name__ == '__main__': if args.write_grid: model.grid.write_ugrid(args.write_grid, overwrite=True) else: model.write() try: shutil.copy(__file__, model.run_dir)
def base_model(run_dir,run_start,run_stop, restart_from=None, grid_option=None, steady=False): if restart_from is None: model=SuntansModel() model.load_template(os.path.join(here,"sun-template.dat")) model.num_procs=num_procs else: old_model=SuntansModel.load(restart_from) model=old_model.create_restart() model.manual_z_offset=-4 model.z_offset=0.0 # moving away from the semi-automated datum shift to manual shift model.projection="EPSG:26910" model.set_run_dir(run_dir,mode='pristine') if model.restart: model.run_start=model.restart_model.restartable_time() else: model.run_start=run_start model.run_stop=run_stop model.config['grid_option']=grid_option or 'snubby' if restart_from is None: ramp_hours=1 # how quickly to increase the outflow else: ramp_hours=0 if not model.restart: # dt=0.25 # for lower friction run on refined shore grid # with new grid that's deformed around the barrier can probably # get away with 0.5 # dt=0.5 # for lower friction run on refined shore grid dt=0.25 # bit of safety for high res grid. # dt=0.1 # for shaved cell grid. still not stable. model.config['dt']=dt model.config['metmodel']=0 # 0: no wind, 4: wind only model.config['nonlinear']=1 if 0: model.config['Nkmax']=1 model.config['stairstep']=0 if 1: model.config['Nkmax']=50 model.config['stairstep']=1 # 3D, stairstep model.config['thetaM']=-1 # with 1, seems to be unstable model.config['z0B']=5e-4 # maybe with ADCP bathy need more friction # slow, doesn't make a huge difference, but does make w nicer. model.config['nonhydrostatic']=0 model.config['nu_H']=0.0 model.config['nu']=1e-5 model.config['turbmodel']=10 # 1: my25, 10: parabolic model.config['CdW']=0.0 # model.config['wetdry']=1 model.config['maxFaces']=4 model.config['mergeArrays']=1 # hopefully easier to use than split up. if model.config['grid_option']=='snubby': # 2019-07-11: refine near-shore swaths of grid, snubby-01 => snubby-04 # 2019-07-12: further refinements 04 => 06 #grid_src="../grid/snubby_junction/snubby-06.nc" #grid_src="../grid/snubby_junction/snubby-07-edit45.nc" #grid_src="../grid/snubby_junction/snubby-08-edit06.nc" #grid_src="../grid/snubby_junction/snubby-08-edit24.nc" #grid_src="../grid/snubby_junction/snubby-08-edit50.nc" # good grid_src="../grid/snubby_junction/snubby-08-edit60.nc" # higher res in hole #grid_src="../grid/snubby_junction/snubby-08-refine-edit03.nc" # double res of edit60 elif model.config['grid_option']=='large': grid_src="../grid/merge_v16/merge_v16_edit09.nc" else: raise Exception("Unknown grid option %s"%grid_option) # bathy_suffix='' # post_suffix='med0' # on-grid bathy postprocessesing: #bathy_suffix='smooth' # pre-smoothed just in sand wave areas bathy_suffix='smoothadcp' # pre-smoothed just in sand wave areas, and revisit ADCP data. #bathy_suffix='smoothadcp2' # same, but extend ADCP data upstream. post_suffix='' # bathy_suffix='adcp' # post_suffix='' grid_bathy=os.path.basename(grid_src).replace('.nc',f"-with_bathy{bathy_suffix}{post_suffix}.nc") if utils.is_stale(grid_bathy,[grid_src]): g_src=unstructured_grid.UnstructuredGrid.from_ugrid(grid_src) g_src.cells_center(refresh=True) bare_edges=g_src.orient_edges(on_bare_edge='return') if len(bare_edges): ec=g_src.edges_center() for j in bare_edges[:50]: print("Bare edge: j=%d xy=%g %g"%(j, ec[j,0], ec[j,1])) raise Exception('Bare edges in grid') add_bathy.add_bathy(g_src,suffix=bathy_suffix) add_bathy.postprocess(g_src,suffix=post_suffix) g_src.write_ugrid(grid_bathy,overwrite=True) g=unstructured_grid.UnstructuredGrid.from_ugrid(grid_bathy) g.cells['z_bed'] += model.manual_z_offset g.delete_edge_field('edge_z_bed') #g.edges['edge_z_bed'] += model.manual_z_offset model.set_grid(g) model.grid.modify_max_sides(4) dt=float(model.config['dt']) # with 0.01, was getting many CmaxW problems. model.config['dzmin_surface']=0.05 # may have to bump this up.. model.config['ntout']=int(1800./dt) model.config['ntaverage']=int(1800./dt) model.config['ntoutStore']=int(86400./dt) # isn't this just duplicating the setting from above? model.z_offset=0.0 # moving away from the semi-automated datum shift to manual shift if model.config['grid_option']=='snubby': model.add_gazetteer(os.path.join(here,"../grid/snubby_junction/forcing-snubby-01.shp")) elif model.config['grid_option']=='large': model.add_gazetteer(os.path.join(here,"../grid/merge_v16/forcing-merge_16-01.shp")) def fill(da): return utils.fill_tidal_data(da,fill_time=False) if steady: # Would like to ramp these up at the very beginning. # Mossdale, tested at 220.0 m3/s Q_upstream=drv.FlowBC(name='SJ_upstream',flow=220.0,dredge_depth=None) Q_downstream=drv.FlowBC(name='SJ_downstream',flow=-100,dredge_depth=None) # had been 1.75. but that's showing about 0.75m too much water. # could be too much friction, or too high BC. h_old_river=drv.StageBC(name='Old_River',water_level=1.75 + model.manual_z_offset) else: # 15 minute data. The flows in particular have enough overtide energy # that the lowpass interval shouldn't be too large. Spot checks of plots # show 1.0h is pretty good lp_hours=1.0 data_upstream=common.msd_flow(model.run_start,model.run_stop) Q_upstream=drv.FlowBC(name="SJ_upstream",flow=data_upstream.flow_m3s,dredge_depth=None, filters=[hm.Lowpass(cutoff_hours=1.0)]) data_downstream=common.sjd_flow(model.run_start,model.run_stop) # flip sign to get outflow. Q_downstream=drv.FlowBC(name="SJ_downstream",flow=-data_downstream.flow_m3s,dredge_depth=None, filters=[hm.Lowpass(cutoff_hours=1.0)]) or_stage=common.oh1_stage(model.run_start,model.run_stop) h_old_river=drv.StageBC(name='Old_River',water_level=or_stage.stage_m, filters=[hm.Transform(fn=lambda x: x+model.manual_z_offset), hm.Lowpass(cutoff_hours=1.0)]) model.add_bcs([Q_upstream,Q_downstream,h_old_river]) model.write() assert np.all(np.isfinite(model.bc_ds.boundary_Q.values)) if not model.restart: # bathy rms ranges from 0.015 to 1.5 # 0.5 appears a little better than 1.0 or 0.1 # cfg007 used 0.1, and the shape was notably not as good # as steady008. # cfg008 will return to 0.5... # BUT - now that I have more metrics in place, it looks like cfg007 # was actually better, in terms of MAE over top 2m, and smaller bias. # with that in mind, steady012 will try an even smaller factor, and infact # something more in line with Nikuradse. # best roughness using constant z0B was 5e-4. # so map 0.1 to that... if 1: print("Adding roughness") grid_roughness.add_roughness(model.grid) cell_z0B=(1./30)*model.grid.cells['bathy_rms'] e2c=model.grid.edge_to_cells() nc1=e2c[:,0] nc2=e2c[:,1] nc2[nc2<0]=nc1[nc2<0] edge_z0B=0.5*( cell_z0B[nc1] + cell_z0B[nc2] ) model.ic_ds['z0B']=('time','Ne'), edge_z0B[None,:] model.write_ic_ds() if int(model.config['metmodel'])>=4: # and how about some wind? times=np.array( [model.run_start - np.timedelta64(10,'D'), model.run_start, model.run_stop, model.run_stop + np.timedelta64(10,'D')] ) nt=len(times) met_ds=model.zero_met(times=times) pnts=model.grid.cells_center()[:1] for comp in ['Uwind','Vwind']: met_ds['x_'+comp]=("N"+comp,),pnts[:,0] met_ds['y_'+comp]=("N"+comp,),pnts[:,1] met_ds['z_'+comp]=("N"+comp,),10*np.ones_like(pnts[:,1]) met_ds['Uwind']=('nt',"NUwind"), 0.0 * np.ones((nt,len(pnts))) met_ds['Vwind']=('nt',"NVwind"),-5.0 * np.ones((nt,len(pnts))) model.met_ds=met_ds model.write_met_ds() model.partition() model.sun_verbose_flag='-v' return model
def base_model(): """ A channel, uniform bathy. """ g=unstructured_grid.UnstructuredGrid(max_sides=4) g.add_rectilinear([0,0],[1000,100],21,3) g.add_cell_field('depth',-6*np.ones(g.Ncells())) model=sun_driver.SuntansModel() model.load_template('point_source_test.dat') model.set_grid(g) model.run_start=np.datetime64("2018-01-01 00:00") model.run_stop =np.datetime64("2018-01-01 10:00") dt=np.timedelta64(600,'s') times=np.arange(model.run_start-dt,model.run_stop+2*dt,dt) secs=(times-times[0])/np.timedelta64(1,'s') eta0=-2 eta_bc=sun_driver.StageBC(name="eta_bc", geom=np.array([ [0,0], [0,100]]), z=eta0) model.add_bcs(eta_bc) model.add_bcs( [sun_driver.ScalarBC(parent=eta_bc,scalar="S",value=1), sun_driver.ScalarBC(parent=eta_bc,scalar="T",value=1)] ) model.set_run_dir('rundata_sedi_3d', mode='pristine') model.projection='EPSG:26910' model.num_procs=1 # test single first model.config['dt']=30 model.config['ntout']=5 model.config['Cmax']=30 model.config['Nkmax']=10 model.config['stairstep']=0 model.config['mergeArrays']=0 # Sediment: model.config['computeSediments']=1 # whether include sediment model model.config['Nlayer']=0 # Number of bed layers (MAX = 5) model.config['Nsize']=3 # Number of sediment fractions (Max = 3) model.config['TBMAX']=1 # whether to output tb for each cell model.config['SETsediment']=0 # When Nlayer>5 or Nsize>3, SETsediment=1 to use SetSediment model.config['WSconstant']=1 # if 1, ws for sediment = ws0 model.config['readSediment']=0 # if 1, read sediment concentration data as IC. only work with Nsize==1 model.config['bedInterval']=150 # the interval steps to update bed change model.config['bedComplex']=0 # whether to consider the possibility to flush away a whole layer model.config['ParabolKappa']=0 # whether to use parabolic tubulent diffusivity model.config['Ds90']=0.000008 # ds90 for calculation of erosion taub model.config['Ds1']=0.00000057 # sediment diameter for fraction No.1 (m) model.config['Ds2']=0.0002 # sediment diameter for fraction No.2 model.config['Ds3']=0.0002 # sediment diameter for fraction No.3 model.config['Ws01']= 0.0001 # constant settling velocity for fraction No.1 (m/s) model.config['Ws02']= 0.01 # constant settling velocity for fraction No.2 model.config['Ws03']=-0.01 # constant settling velocity for fraction No.3 model.config['Gsedi1']=2.65 # relative density for fraction No.1 model.config['Gsedi2']=2.65 # relative density for fraction No.2 model.config['Gsedi3']=2.65 # relative density for fraction No.3 model.config['Prt1']=1 # Prandtl Number for fraction No.1 model.config['Prt2']=1 # Prandtl Number for fraction No.2 model.config['Prt3']=1 # Prandtl Number for fraction No.3 model.config['Consolid1']=0.00 # Consolidation rate (g/m^2/s) for layer No.1 model.config['E01']=0.1 # Basic Erosion Rate Constant (g/m^2/s) for layer No.1 model.config['Taue1']=0.0 # Erosion Critical Shear Stress (N/m^2) for layer No.1 # Taud1 isn't actually used in current code. Deposition always occurs at the rate # of w_s. model.config['Taud1']=0.0 # Deposition Critical Shear Stress (N/m^2) for layer No.1 model.config['Drydensity1']=530000 # Dry density (g/m^3) for layer No.1 model.config['Thickness1']=0.0 # Thickness (m) for layer No.1 model.config['softhard1']=1 # 0 soft or hard for layer No.1 to decide how to calculate erosion model.config['Bedmudratio1']=0.8 # Bed mud ratio for layer No.1 model.config['Chind']=1000000 # Concentration (in volumetric fraction) criterion for hindered settling velocity model.config['Cfloc']=500000 # Concentration (in volumetric fraction) criterion for flocculated settling velcoity model.config['k']=0.0002 # Constant coefficient for settling velocity as a function of conc. model.config['Sediment1File']='sedi1.dat' model.config['Sediment2File']='sedi2.dat' model.config['Sediment3File']='sedi3.dat' model.config['LayerFile']='sedilayer.dat' model.config['tbFile']='Seditb.dat' model.config['tbmaxFile']='Seditbmax.dat' return model
xy for xy in xys if model.grid.select_cells_nearest(xy, inside=True) is not None ] np.savetxt(os.path.join(model.run_dir, model.config['DataLocations']), np.array(valid_xys)) ## # spatially varying hycom_ll_box = [-124.9, -121.7, 35.9, 39.0] ocean_bcs = [] if ocean_method == 'eta-otps': ocean_bc = drv.MultiBC(drv.OTPSStageBC, name='Ocean', otps_model='wc') ocean_offset_bc = drv.StageBC(name='Ocean', mode='add', water_level=z_offset_manual) ocean_bcs += [ocean_bc, ocean_offset_bc] elif ocean_method == 'flux-otps': ocean_bc = drv.MultiBC(drv.OTPSFlowBC, name='Ocean', otps_model='wc') ocean_bcs.append(ocean_bc) elif ocean_method == 'velocity-otps': ocean_bc = drv.MultiBC(drv.OTPSVelocityBC, name='Ocean', otps_model='wc') ocean_bcs.append(ocean_bc) elif ocean_method.startswith('velocity-hycom'): # explicity give bounds to make sure we always download the same # subset. # z_offset here is the elevation of MSL in the model vertical datum. # NAVD88 is offset by z_offset_manual, but MSL is a bit higher than # that. ocean_bc = drv.HycomMultiVelocityBC(ll_box=hycom_ll_box,