class Thermalwind(Param): """ Thermal wind model It provides the step(t,dt) function and 'var' containing the mode state """ def __init__(self, param, grid): self.list_param = [ 'forcing', 'noslip', 'timestepping', 'forcing_module', 'additional_tracer', 'myrank', 'gravity', 'diffusion', 'Kdiff', 'f0' ] param.copy(self, self.list_param) # for potential energy self.list_param = [ 'xr', 'yr', 'nh', 'Lx', 'msk', 'area', 'mpitools', 'dx' ] grid.copy(self, self.list_param) # for variables param.varname_list = [ 'vorticity', 'psi', 'u', 'v', 'buoyancy', 'V', 'qE' ] param.tracer_list = ['vorticity', 'buoyancy', 'V'] param.whosetspsi = ('vorticity') if hasattr(self, 'additional_tracer'): for k in range(len(self.additional_tracer)): trac = self.additional_tracer[k] param.varname_list.append(trac) param.tracer_list.append(trac) param.sizevar = [grid.nyl, grid.nxl] self.var = Var(param) # for operators self.ope = Operators(param, grid) # for timescheme self.tscheme = Timescheme(param, self.var.state) if self.forcing: try: f = import_module(self.forcing_module) except: print('module %s for forcing cannot be found' % self.forcing_module) print('make sure file **%s.py** exists' % self.forcing_module) exit(0) self.forc = f.Forcing(param, grid) self.diags = {} def step(self, t, dt): # 1/ integrate advection self.tscheme.set(self.dynamics, self.timestepping) self.tscheme.forward(self.var.state, t, dt) # 2/ integrate source if self.forcing or self.noslip: self.tscheme.set(self.sources, 'EF') self.tscheme.forward(self.var.state, t, dt) self.compute_pv() def compute_pv(self): qE = self.var.get('qE') v = self.var.get('V') b = self.var.get('buoyancy') # Ertel PV y = qE * 0. y[1:-1, 1:-1] = self.ope.jacobian(v + self.f0 * self.xr, b) y *= self.msk self.ope.fill_halo(y) qE[:, :] = y def dynamics(self, x, t, dxdt): self.ope.rhs_adv(x, t, dxdt) self.ope.rhs_thermalwind(x, t, dxdt) # add the r.h.s. terms if (self.tscheme.kstage == self.tscheme.kforcing): if self.forcing: self.forc.add_forcing(x, t, dxdt) if self.diffusion: self.ope.rhs_diffusion(x, t, dxdt) self.ope.invert_vorticity(dxdt, flag='fast') def sources(self, x, t, dxdt): if self.noslip: self.ope.rhs_noslip(x, t, dxdt) self.ope.invert_vorticity(x, flag='full') def set_psi_from_vorticity(self): self.ope.invert_vorticity(self.var.state) def diagnostics(self, var, t): """ should provide at least 'maxspeed' (for cfl determination) """ nh = self.nh u = var.get('u') v = var.get('v') vort = var.get('vorticity') buoy = var.get('buoyancy') V = var.get('V') qE = var.get('qE') qEneg = qE.copy() qEneg[qE > 0] = 0. ke, maxu = fd.computekemaxu(self.msk, u, v, self.nh) z, z2 = fd.computesumandnorm(self.msk, vort, self.nh) b, b2 = fd.computesumandnorm(self.msk, buoy, self.nh) vm, v2 = fd.computesumandnorm(self.msk, V, self.nh) q, q2 = fd.computesumandnorm(self.msk, qE, self.nh) qn, qn2 = fd.computesumandnorm(self.msk, qEneg, self.nh) # potential energy (minus sign because buoyancy is minus density) pe = fd.computesum(self.msk, buoy * self.yr, nh) pe = -self.gravity * pe cst = self.mpitools.local_to_global([(maxu, 'max'), (ke, 'sum'), (z, 'sum'), (z2, 'sum'), (pe, 'sum'), (b, 'sum'), (b2, 'sum'), (q, 'sum'), (q2, 'sum'), (qn, 'sum'), (qn2, 'sum'), (v2, 'sum')]) a = self.area self.diags['maxspeed'] = cst[0] self.diags['ke'] = (cst[1]) / a self.diags['keV'] = (0.5 * cst[11]) / a self.diags['pe'] = cst[4] / a self.diags[ 'energy'] = self.diags['ke'] + self.diags['pe'] + self.diags['keV'] self.diags['vorticity'] = cst[2] / a self.diags['enstrophy'] = 0.5 * cst[3] / a bm = cst[5] / a self.diags['buoyancy'] = bm self.diags['brms'] = sqrt(cst[6] / a - bm**2) pvm = cst[7] / a pvneg_mean = cst[9] / a self.diags['pv_mean'] = pvm self.diags['pv_std'] = sqrt(cst[8] / a - pvm**2) self.diags['pvneg_mean'] = pvneg_mean self.diags['pvneg_std'] = sqrt(cst[10] / a - pvneg_mean**2)
class Euler(object): """ Euler model It provides the step(t,dt) function and 'var' containing the mode state """ def __init__(self, param, grid): self.list_param = [ 'forcing', 'noslip', 'timestepping', 'diffusion', 'Kdiff', 'forcing_module', 'additional_tracer', 'enforce_momentum', 'var_to_save', 'customized', 'custom_module', 'spongelayer' ] param.copy(self, self.list_param) # for diagnostics self.list_param = [ 'yr', 'nh', 'msk', 'area', 'mpitools', 'dx', 'xr', 'yr', 'r2', 'x0', 'y0', 'x2', 'y2', 'isisland', 'Lx', 'ny' ] grid.copy(self, self.list_param) # for variables param.varname_list = ['vorticity', 'psi', 'u', 'v', 'source'] # ,'tauw','wshear'] param.tracer_list = ['vorticity'] param.whosetspsi = ('vorticity') if 'tauw' in self.var_to_save: param.varname_list.append('tauw') if 'wshear' in self.var_to_save: param.varname_list.append('wshear') if hasattr(self, 'additional_tracer'): for k in range(len(self.additional_tracer)): trac = self.additional_tracer[k] param.varname_list.append(trac) param.tracer_list.append(trac) param.sizevar = [grid.nyl, grid.nxl] self.var = Var(param) self.work = np.zeros(param.sizevar) # for timing the code self.timers = Timers(param) # for operators self.ope = Operators(param, grid) # for timescheme self.tscheme = Timescheme(param, self.var.state) self.tscheme.set(self.dynamics, self.timestepping) if self.forcing: if self.forcing_module == 'embedded': print( 'Warning: check that you have indeed added the forcing to the model' ) print('Right below the line : model = f2d.model') print( 'you should have the line: model.forc = Forcing(param, grid)' ) pass else: try: f = import_module(self.forcing_module) except ImportError: print('module %s for forcing cannot be found' % self.forcing_module) print('make sure file **%s.py** exists' % self.forcing_module) exit(0) self.forc = f.Forcing(param, grid) if self.spongelayer: # sponge layer zone [0 = full sponge, 1 = no sponge] self.spongemsk = (1 - (1 + np.tanh( (self.xr - self.Lx) / 0.1)) * 0.5) self.diags = {} if self.customized: try: f = import_module(self.custom_module) self.extrastep = f.Step(param, grid) except ImportError: print('module %s for forcing cannot be found' % self.custom_module) print('make sure file **%s.py** exists' % self.custom_module) exit(0) def step(self, t, dt): # 1/ integrate dynamics self.tscheme.forward(self.var.state, t, dt) # 2/ integrate source if self.noslip: self.add_noslip(self.var.state) source = self.var.get('source') source /= dt if 'tauw' in self.var_to_save: tauw = self.var.get('tauw') tauw[:, :] = source * self.dx * self.dx if 'wshear' in self.var_to_save: wshear = self.var.get('wshear') self.ope.wallshear(self.var.state, self.work) wshear[:, :] = self.work if self.customized: self.extrastep.do(self.var, t, dt) # # 3/ dye tracer if 'dye' in self.var.varname_list: i, jp, jm = 1, self.ny // 2 + 3, self.ny // 2 - 3 dye = self.var.get('dye') dye[jp + self.nh, i] = 1 dye[jm + self.nh, i] = -1 if 'age' in self.var.varname_list: age = self.var.get('age') age += dt * self.msk age[:, self.nh] = 0. if self.spongelayer: # 4/ sponge layer w = self.var.get('vorticity') w *= self.spongemsk if 'dye' in self.var.varname_list: dye *= self.spongemsk if 'age' in self.var.varname_list: age *= self.spongemsk #self.set_psi_from_vorticity() def dynamics(self, x, t, dxdt): """Compute the tendency terms + invert the streamfunction""" self.timers.tic('rhs_adv') self.ope.rhs_adv(x, t, dxdt) self.timers.toc('rhs_adv') if (self.tscheme.kstage == self.tscheme.kforcing): if self.forcing: self.forc.add_forcing(x, t, dxdt) if self.diffusion: self.ope.rhs_diffusion(x, t, dxdt) # else: self.timers.tic('invert') self.ope.invert_vorticity(dxdt, flag='fast') self.timers.toc('invert') def add_noslip(self, x): self.timers.tic('noslip') source = self.var.get('source') self.ope.rhs_noslip(x, source) self.timers.toc('noslip') # if not(self.enforce_momentum): self.timers.tic('invert') self.ope.invert_vorticity(x, flag='fast', island=self.isisland) self.timers.toc('invert') def set_psi_from_vorticity(self): self.ope.invert_vorticity(self.var.state, island=self.isisland) def diagnostics(self, var, t): """ should provide at least 'maxspeed' (for cfl determination) """ self.timers.tic('diag') u = var.get('u') v = var.get('v') trac = var.get('vorticity') psi = var.get('psi') source = self.var.get('source') xr = self.xr yr = self.yr ke, maxu = fd.computekemaxu(self.msk, u, v, self.nh) # ke = fd.computekewithpsi(self.msk, trac, psi, self.nh) z, z2 = fd.computesumandnorm(self.msk, trac, self.nh) px = fd.computedotprod(self.msk, trac, xr, self.nh) py = fd.computedotprod(self.msk, trac, yr, self.nh) angmom = fd.computesum(self.msk, psi, self.nh) sce = fd.computedotprod(self.msk, trac, source, self.nh) cst = self.mpitools.local_to_global([(maxu, 'max'), (ke, 'sum'), (z, 'sum'), (z2, 'sum'), (px, 'sum'), (py, 'sum'), (angmom, 'sum'), (sce, 'sum')]) self.diags['maxspeed'] = cst[0] self.diags['ke'] = cst[1] / self.area self.diags['vorticity'] = cst[2] / self.area self.diags['enstrophy'] = 0.5 * cst[3] / self.area self.diags['px'] = cst[4] / self.area self.diags['py'] = cst[5] / self.area self.diags['angmom'] = cst[6] / self.area self.diags['source'] = cst[7] / self.area self.timers.toc('diag')
class Boussinesq(object): """ Boussinesq model It provides the step(t,dt) function and 'var' containing the mode state """ def __init__(self, param, grid): self.list_param = [ 'forcing', 'noslip', 'timestepping', 'diffusion', 'Kdiff', 'myrank', 'forcing_module', 'gravity', 'isisland', 'customized', 'custom_module', 'additional_tracer' ] param.copy(self, self.list_param) # for potential energy self.list_param = ['xr', 'yr', 'nh', 'Lx', 'msk', 'area', 'mpitools'] grid.copy(self, self.list_param) # for variables param.varname_list = [ 'vorticity', 'psi', 'u', 'v', 'buoyancy', 'banom' ] param.tracer_list = ['vorticity', 'buoyancy'] param.whosetspsi = ('vorticity') if hasattr(self, 'additional_tracer'): for k in range(len(self.additional_tracer)): trac = self.additional_tracer[k] param.varname_list.append(trac) param.tracer_list.append(trac) param.sizevar = [grid.nyl, grid.nxl] self.var = Var(param) bref = self.var.get('buoyancy').copy() self.bref = bref self.source = np.zeros(param.sizevar) # for operators self.ope = Operators(param, grid) # for timescheme self.tscheme = Timescheme(param, self.var.state) self.tscheme.set(self.dynamics, self.timestepping) if self.forcing: if self.forcing_module == 'embedded': self.msg_forcing = ( 'To make Fluid2d aware of your embedded forcing\n' + 'you need to add in the user script \n' + 'model.forc = Forcing(param, grid)\n' + 'right below the line: model = f2d.model') pass else: try: f = import_module(self.forcing_module) except ImportError: print('module %s for forcing cannot be found' % self.forcing_module) print('make sure file **%s.py** exists' % self.forcing_module) exit(0) self.forc = f.Forcing(param, grid) self.diags = {} if self.customized: try: f = import_module(self.custom_module) print(f) self.extrastep = f.Step(param, grid) except ImportError: print('module %s for forcing cannot be found' % self.custom_module) print('make sure file **%s.py** exists' % self.custom_module) exit(0) def step(self, t, dt): # 1/ integrate advection self.tscheme.forward(self.var.state, t, dt) # 2/ integrate source if self.noslip: self.add_noslip(self.var.state) if self.customized: self.extrastep.do(self.var, t, dt) banom = self.var.get('banom') banom[:, :] = self.var.get('buoyancy') - self.bref def dynamics(self, x, t, dxdt): self.ope.rhs_adv(x, t, dxdt) # db/dx is a source term for the vorticity self.ope.rhs_torque(x, t, dxdt) if (self.tscheme.kstage == self.tscheme.kforcing): coef = self.tscheme.dtcoef if self.forcing: assert hasattr(self, 'forc'), self.msg_forcing self.forc.add_forcing(x, t, dxdt, coef=coef) if self.diffusion: self.ope.rhs_diffusion(x, t, dxdt, coef=coef) self.ope.invert_vorticity(dxdt, flag='fast') def add_noslip(self, x): self.ope.rhs_noslip(x, self.source) self.ope.invert_vorticity(x, flag='fast', island=self.isisland) def set_psi_from_vorticity(self): self.ope.invert_vorticity(self.var.state, island=self.isisland) def diagnostics(self, var, t): """ should provide at least 'maxspeed' (for cfl determination) """ nh = self.nh u = var.get('u') v = var.get('v') vort = var.get('vorticity') buoy = var.get('buoyancy') ke, maxu = fd.computekemaxu(self.msk, u, v, self.nh) z, z2 = fd.computesumandnorm(self.msk, vort, self.nh) b, b2 = fd.computesumandnorm(self.msk, buoy, self.nh) # potential energy (minus sign because buoyancy is minus density) pe = -self.gravity * fd.computesum(self.msk, buoy * self.yr, nh) cst = self.mpitools.local_to_global([(maxu, 'max'), (ke, 'sum'), (z, 'sum'), (z2, 'sum'), (pe, 'sum'), (b, 'sum'), (b2, 'sum')]) self.diags['maxspeed'] = cst[0] self.diags['ke'] = cst[1] / self.area self.diags['pe'] = cst[4] / self.area self.diags['energy'] = (cst[1] + cst[4]) / self.area self.diags['vorticity'] = cst[2] / self.area self.diags['enstrophy'] = 0.5 * cst[3] / self.area self.diags['buoyancy'] = cst[5] / self.area self.diags['brms'] = np.sqrt(cst[6] / self.area - (cst[5] / self.area)**2)
class Euler(Param): """ Euler model It provides the step(t,dt) function and 'var' containing the mode state """ def __init__(self, param, grid): self.list_param = [ 'forcing', 'noslip', 'timestepping', 'diffusion', 'Kdiff', 'forcing_module', 'additional_tracer', 'enforce_momentum', 'var_to_save', 'customized', 'custom_module' ] param.copy(self, self.list_param) # for diagnostics self.list_param = [ 'yr', 'nh', 'msk', 'area', 'mpitools', 'dx', 'xr', 'yr', 'r2', 'x0', 'y0', 'x2', 'y2', 'isisland', 'Lx' ] grid.copy(self, self.list_param) # for variables param.varname_list = ['vorticity', 'psi', 'u', 'v'] #,'tauw','wshear'] param.tracer_list = ['vorticity'] param.whosetspsi = ('vorticity') if 'tauw' in self.var_to_save: param.varname_list.append('tauw') if 'wshear' in self.var_to_save: param.varname_list.append('wshear') if hasattr(self, 'additional_tracer'): for k in range(len(self.additional_tracer)): trac = self.additional_tracer[k] param.varname_list.append(trac) param.tracer_list.append(trac) print('Tracers are :', param.tracer_list) param.sizevar = [grid.nyl, grid.nxl] self.var = Var(param) self.source = zeros(param.sizevar) # for operators self.ope = Operators(param, grid) # for timescheme self.tscheme = Timescheme(param, self.var.state) self.tscheme.set(self.advection, self.timestepping) if self.forcing: try: f = import_module(self.forcing_module) except: print('module %s for forcing cannot be found' % self.forcing_module) print('make sure file **%s.py** exists' % self.forcing_module) exit(0) self.forc = f.Forcing(param, grid) self.diags = {} if self.customized: try: f = import_module(self.custom_module) self.extrastep = f.step(param, grid) except: print('module %s for forcing cannot be found' % self.custom_module) print('make sure file **%s.py** exists' % self.custom_module) exit(0) def step(self, t, dt): # 1/ integrate advection self.tscheme.forward(self.var.state, t, dt) # 2/ integrate source if self.noslip: self.add_noslip(self.var.state) if 'tauw' in self.var_to_save: tauw = self.var.get('tauw') tauw[:, :] = self.source / dt * self.dx * self.dx if 'wshear' in self.var_to_save: wshear = self.var.get('wshear') self.ope.wallshear(self.var.state, self.source) wshear[:, :] = self.source if self.customized: self.extrastep.do(self.var, t, dt) # # 3/ dye tracer # i,jp,jm=1,67,61 # dye = self.var.get('dye') # dye[jp+self.nh,i]=1 # dye[jm+self.nh,i]=-1 # age = self.var.get('age') # age += dt*self.msk # age[:,self.nh]=0. # # 4/ sponge layer # damping = ( 1- (1+tanh( (self.xr - self.Lx)/0.1))*0.5) # w = self.var.get('vorticity') # w *= damping # dye *= damping # age *= damping def advection(self, x, t, dxdt): self.ope.rhs_adv(x, t, dxdt) if (self.tscheme.kstage == self.tscheme.kforcing): if self.forcing: self.forc.add_forcing(x, t, dxdt) if self.diffusion: self.ope.rhs_diffusion(x, t, dxdt) self.ope.invert_vorticity(dxdt, flag='fast') def add_noslip(self, x): self.ope.rhs_noslip(x, self.source) if not (self.enforce_momentum): self.ope.invert_vorticity(x, flag='fast', island=self.isisland) def set_psi_from_vorticity(self): self.ope.invert_vorticity(self.var.state, island=self.isisland) def diagnostics(self, var, t): """ should provide at least 'maxspeed' (for cfl determination) """ nh = self.nh u = var.get('u') v = var.get('v') trac = var.get('vorticity') xr = self.xr yr = self.yr r2 = self.r2 ke, maxu = computekemaxu(self.msk, u, v, self.nh) z, z2 = computesumandnorm(self.msk, trac, self.nh) px = computedotprod(self.msk, trac, xr, self.nh) py = computedotprod(self.msk, trac, yr, self.nh) angmom = computedotprod(self.msk, trac, r2, self.nh) cst = self.mpitools.local_to_global([(maxu, 'max'), (ke, 'sum'), (z, 'sum'), (z2, 'sum'), (px, 'sum'), (py, 'sum'), (angmom, 'sum')]) self.diags['maxspeed'] = cst[0] self.diags['ke'] = cst[1] / self.area self.diags['vorticity'] = cst[2] / self.area self.diags['enstrophy'] = cst[3] / self.area self.diags['px'] = cst[4] / self.area self.diags['py'] = cst[5] / self.area self.diags['angmom'] = cst[6] / self.area
class BoussinesqTS(object): """ Boussinesq model with temperature and salinity It provides the step(t,dt) function and 'var' containing the mode state """ def __init__(self, param, grid): self.list_param = [ 'forcing', 'noslip', 'timestepping', 'alphaT', 'betaS', 'diffusion', 'Kdiff', 'myrank', 'forcing_module', 'gravity', 'isisland', 'customized', 'custom_module', 'additional_tracer' ] param.copy(self, self.list_param) # for potential energy self.list_param = ['xr', 'yr', 'nh', 'Lx', 'msk', 'area', 'mpitools'] grid.copy(self, self.list_param) # for variables param.varname_list = [ 'vorticity', 'psi', 'u', 'v', 'density', 'danom', 'T', 'S' ] param.tracer_list = ['vorticity', 'T', 'S'] param.whosetspsi = ('vorticity') if hasattr(self, 'additional_tracer'): for k in range(len(self.additional_tracer)): trac = self.additional_tracer[k] param.varname_list.append(trac) param.tracer_list.append(trac) self.varname_list = param.varname_list param.sizevar = [grid.nyl, grid.nxl] self.var = Var(param) dref = self.var.get('density').copy() self.dref = dref self.source = np.zeros(param.sizevar) # for operators self.ope = Operators(param, grid) # for timescheme self.tscheme = Timescheme(param, self.var.state) self.tscheme.set(self.dynamics, self.timestepping) if self.forcing: if self.forcing_module == 'embedded': print( 'Warning: check that you have indeed added the forcing to the model' ) print('Right below the line : model = f2d.model') print( 'you should have the line: model.forc = Forcing(param, grid)' ) pass else: try: f = import_module(self.forcing_module) except ImportError: print('module %s for forcing cannot be found' % self.forcing_module) print('make sure file **%s.py** exists' % self.forcing_module) sys.exit(0) self.forc = f.Forcing(param, grid) self.diags = {} if self.customized: try: f = import_module(self.custom_module) print(f) self.extrastep = f.Step(param, grid) except ImportError: print('module %s for forcing cannot be found' % self.custom_module) print('make sure file **%s.py** exists' % self.custom_module) exit(0) def step(self, t, dt): # 1/ integrate advection self.tscheme.forward(self.var.state, t, dt) self.set_density() # 2/ integrate source if self.noslip: self.add_noslip(self.var.state) if self.customized: self.extrastep.do(self.var, t, dt) danom = self.var.get('danom') danom[:, :] = self.var.get('density') - self.dref def dynamics(self, x, t, dxdt): self.ope.rhs_adv(x, t, dxdt) self.eos(dxdt) # db/dx is a source term for the vorticity self.ope.rhs_torque_density(x, t, dxdt) if (self.tscheme.kstage == self.tscheme.kforcing): coef = self.tscheme.dtcoef if self.forcing: self.forc.add_forcing(x, t, dxdt, coef=coef) if self.diffusion: self.ope.rhs_diffusion(x, t, dxdt, coef=coef) self.eos(dxdt) self.ope.invert_vorticity(dxdt, flag='fast') def add_noslip(self, x): self.ope.rhs_noslip(x, self.source) self.ope.invert_vorticity(x, flag='fast', island=self.isisland) def eos(self, x): """ compute density from T and S """ idens = self.varname_list.index('density') itemp = self.varname_list.index('T') isalt = self.varname_list.index('S') x[idens] = -self.alphaT * x[itemp] + self.betaS * x[isalt] def set_density(self): self.eos(self.var.state) def set_psi_from_vorticity(self): self.ope.invert_vorticity(self.var.state, island=self.isisland) def diagnostics(self, var, t): """ should provide at least 'maxspeed' (for cfl determination) """ nh = self.nh u = var.get('u') v = var.get('v') vort = var.get('vorticity') dens = var.get('density') ke, maxu = fd.computekemaxu(self.msk, u, v, self.nh) z, z2 = fd.computesumandnorm(self.msk, vort, self.nh) b, b2 = fd.computesumandnorm(self.msk, dens, self.nh) # potential energy pe = +self.gravity * fd.computesum(self.msk, dens * self.yr, nh) cst = self.mpitools.local_to_global([(maxu, 'max'), (ke, 'sum'), (z, 'sum'), (z2, 'sum'), (pe, 'sum'), (b, 'sum'), (b2, 'sum')]) self.diags['maxspeed'] = cst[0] self.diags['ke'] = cst[1] / self.area self.diags['pe'] = cst[4] / self.area self.diags['energy'] = (cst[1] + cst[4]) / self.area self.diags['vorticity'] = cst[2] / self.area self.diags['enstrophy'] = 0.5 * cst[3] / self.area self.diags['density'] = cst[5] / self.area self.diags['drms'] = np.sqrt(cst[6] / self.area - (cst[5] / self.area)**2)