Exemple #1
0
    def finalize(self, mskp_model):
        print('found %i islands' % self.nbisland)
        mskp = zeros((self.nyl, self.nxl), dtype=int8)
        work = zeros((self.nyl, self.nxl))
        mskr = zeros((self.nyl, self.nxl))
        for k in range(self.nbisland):
            idx = self.data[k]['idx']
            psi0 = self.data[k]['psi0']
            mskr[:, :] = 1.
            mskp[:, :] = 0
            mskr[idx] = 0.
            celltocorner(mskr, work)
            mskp[work == 1] = 1
            mskp = 1 - mskp

            vort = (roll(mskp, -1, axis=1) + roll(mskp, -1, axis=0) +
                    roll(mskp, +1, axis=1) + roll(mskp, +1, axis=0))

            z = (vort) * psi0 / (self.dx * self.dy)  # *(1-mskp)
            self.rhsp[vort > 0] = z[vort > 0]
            self.psi[mskp == 1] = psi0
#            print(self.psi[:,10])
        print('island are ok')
Exemple #2
0
    def invert_vorticity(self, x, flag='full', island=False):
        """ compute psi from vorticity (or 'whosetspsi' in general)

        this routine interpolates the vorticity from cell centers to
        cell corners (where psi is defined)

        it then solves div*grad psi = omega with psi=0 along the boundary
        (Dirichlet condition) using a multigrid

        the non-divergent velocity is computed from psi"""
        iu = self.varname_list.index('u')
        iv = self.varname_list.index('v')
        ip = self.varname_list.index('psi')
        iw = self.varname_list.index(self.whosetspsi)

        u = x[iu]
        v = x[iv]
        psi = x[ip]

        fo.celltocorner(x[iw], self.work)
        #fo.celltocornerbicubic(x[iw], self.work)
        if island:
            # correcting RHS for islands
            self.work[:, :] -= self.rhsp

        if flag == 'fast':
            ite, res = self.gmg.twoVcycle(psi, self.work, {
                'maxite': 1,
                'tol': 1e-6,
                'verbose': True
            })
            # ite, res = self.gmg.solve(psi, self.work,
            #                           {'maxite': 2,
            #                            'tol': 1e-8,
            #                            'verbose': False})

        else:
            # compute to machine accuracy
            if self.first_time:
                verbose = True
            else:
                verbose = False
            if (self.myrank == 0) and verbose:
                print('-' * 50)
                print(' Convergence of the vorticity inversion')
                print('    the residual should decrease by several orders')
                print('    of magnitude otherwise something is wrong')
                print('-' * 50)

            ite, res = self.gmg.solve(psi, self.work, {
                'maxite': 4,
                'tol': 1e-11,
                'verbose': verbose
            })
            if self.geometry == 'perio':
                # make sure psi has zero mean (to avoid the drift)
                psim = self.domain_integration(psi) / self.area
                psi -= psim

        # don't apply the fill_halo on it
        # [because fill_halo, as it is, is applying periodic BC]
        psi = psi * self.mskp
        if island:
            # we set psi on the boundary values by adding
            # self.psi (defined in island module)
            # before that line, psi=0 along all boundaries
            psi += self.psi
            # it should be added only if we invert for the total psi
            # it should not be added if we compute the increment of psi

        self.first_time = False

        # compute (u,v) @ U,V points from psi @ cell corner
        fo.computeorthogradient(self.msk, psi, self.dx, self.dy, self.nh, u, v)
        # self.fill_halo(u)
        # self.fill_halo(v)
        x[iu] = u
        x[iv] = v
        x[ip] = psi
Exemple #3
0
    def __init__(self, param, grid):
        self.list_param = [
            'varname_list', 'tracer_list', 'whosetspsi', 'mpi', 'npx', 'npy',
            'nh', 'gravity', 'f0', 'beta', 'Rd', 'qgoperator', 'order',
            'Kdiff', 'diffusion', 'enforce_momentum', 'isisland', 'aparab',
            'flux_splitting_method', 'hydroepsilon', 'myrank', 'geometry',
            'sqgoperator'
        ]

        param.copy(self, self.list_param)

        self.list_grid = [
            'msk', 'nxl', 'nyl', 'dx', 'dy', 'bcarea', 'mpitools', 'msknoslip',
            'mskbc', 'domain_integration', 'nh', 'xr0', 'yr0', 'i0', 'j0',
            'area'
        ]

        grid.copy(self, self.list_grid)
        self.first_time = True

        # internal work array for the inversion
        self.work = zeros((self.nyl, self.nxl))
        self.work2 = zeros((self.nyl, self.nxl))

        pp = {
            'np': param.npx,
            'mp': param.npy,
            'nh': param.nh,
            'n': param.nx // param.npx,
            'm': param.ny // param.npy,
            'omega': 8. / 9.,
            'npmpmax': 1,
            'verbose': False,
            'dx': grid.dx,
            'dy': grid.dy,
            'n1': 32,
            'n0': 4,
            'method': 'deep',
            'nagglo': 2,
            'hydroepsilon': param.hydroepsilon,
            'relaxation': param.relaxation
        }

        # load the multigrid solver
        #
        # WARNING: the multigrid needs the mask at cell corners!!!
        #         not at cell centers
        mskr = self.msk * 1.

        # this piece is a bit awkward: to initialize gmg, we need
        # a mask with a halo properly filled but the fill_halo method
        # belongs to gmg. We have a circular definition.
        # the trick: define a dummy gmg first a msk=1 everywhere
        # then grab the fill_halo method and redefine once again the
        # multigrid, this time with the proper mask
        # self.gmg = Gmg(pp,mskr)
        # borrow the fill_halo from the multigrid
        # self.fill_halo = self.gmg.grid[0].halo.fill

        fo.celltocorner(mskr, self.work)
        # self.fill_halo(self.work)

        # del self.gmg
        # del self.fill_halo

        self.work[self.work < 1.] = 0.
        self.mskp = self.msk * 0
        self.mskp[self.work == 1.] = 1
        pp['verbose'] = True
        if self.myrank == 0:
            print('-' * 50)
            print(' Multigrid hierarchy')
            print('-' * 50)

        if hasattr(self, 'qgoperator'):
            pp['qgoperator'] = True
            pp['Rd'] = self.Rd
            self.gmg = Gmg(pp, self.work)
        else:
            self.gmg = Gmg(pp, self.work)
        if hasattr(self, 'sqgoperator'):
            self.fourier = Fourier(param, grid)

        # borrow the fill_halo from the multigrid
        self.fill_halo = self.gmg.grid[0].halo.fill
        grid.fill_halo = self.gmg.grid[0].halo.fill

        self.blwidth = param.Lx * 0.05

        # tentative for a regularized no-slip source term
        coef = 0. * zeros_like(self.mskp)
        coef[1:, 1:] = (self.mskp[:-1, 1:] + self.mskp[:-1, :-1] +
                        self.mskp[1:, 1:] + self.mskp[1:, :-1])
        # nbpsibc is the number of land psi-points surrounding a fluid cell
        self.nbpsibc = (4. - coef) * self.msk
        self.nbpsibc[self.nbpsibc > 0] = 1.

        self.set_boundary_msk()

        self.cst = zeros(5, )
        # select the proper flux discretization
        if self.order % 2 == 0:
            self.fortran_adv = fa.adv_centered
            self.cst[0] = grid.dx
            self.cst[1] = grid.dy
            self.cst[2] = 0.05
            self.cst[3] = 0  # umax
            self.cst[4] = 0  # unused
            # should be updated at each timestep
            # self.cst[3]=param.umax

        else:
            self.fortran_adv = fa.adv_upwind
            self.cst[0] = grid.dx
            self.cst[1] = grid.dy
            self.cst[2] = 0.05
            self.cst[3] = 0  # umax
            self.cst[4] = self.aparab
            # should be updated at each timestep
            # self.cst[3]=param.umax

        # controls the flux splitting method
        # 0 = min/max
        # 1 = parabolic
        list_fs_method = ['minmax', 'parabolic']
        if self.flux_splitting_method in list_fs_method:
            self.fs_method = list_fs_method.index(self.flux_splitting_method)
        else:
            print('Warning: %s does not exist' % self.flux_splitting_method)
            print('replaced with the default: parabolic')
            self.fs_method = list_fs_method.index('parabolic')

        # these coefficients below are used for the thermalwind model
        coef = 0. * zeros_like(self.msk)
        coef[1:-1, 1:-1] = self.msk[1:-1, 2:] + self.msk[1:-1, 0:-2]
        coef[coef < 2] = 0.
        coef[coef == 2] = 0.5
        self.fill_halo(coef)
        self.coefb = coef * 1.

        coef = 0. * zeros_like(self.msk)
        coef[1:-1, 1:-1] = self.msk[2:, 1:-1] + self.msk[0:-2, 1:-1]
        coef[coef < 2] = 0.
        coef[coef == 2] = 0.5
        self.fill_halo(coef)
        self.coefV = coef * 1.

        if type(self.Kdiff) != dict:
            K = self.Kdiff
            self.Kdiff = {}
            for trac in self.tracer_list:
                self.Kdiff[trac] = K
        if self.diffusion:
            print('diffusion coefficients')
            print('  => ', self.Kdiff)