Esempio n. 1
0
def test_sin_nlbvp(benchmark, x_basis_class, Nx, dtype):
    # Parameters
    ncc_cutoff = 1e-10
    tolerance = 1e-10
    # Build domain
    x_basis = x_basis_class('x', Nx, interval=(0, 1), dealias=2)
    domain = de.Domain([x_basis], np.float64)
    # Setup problem
    problem = de.NLBVP(domain, variables=['u'], ncc_cutoff=ncc_cutoff)
    problem.add_equation("dx(u) = sqrt(1 - u**2)")
    problem.add_bc("left(u) = 0")
    # Setup initial guess
    solver = problem.build_solver()
    x = domain.grid(0)
    u = solver.state['u']
    u['g'] = x
    # Iterations
    pert = solver.perturbations.data
    pert.fill(1 + tolerance)
    while np.sum(np.abs(pert)) > tolerance:
        solver.newton_iteration()
        logger.info('Perturbation norm: {}'.format(np.sum(np.abs(pert))))
    # Check solution
    u_true = np.sin(x)
    u.set_scales(1)
    assert np.allclose(u['g'], u_true)
    def build_problem(self, ncc_cutoff=1e-10):
        """Constructs and initial value problem of the current object's equation set

        Arguments:
        ----------
        ncc_cutoff  : float
            The largest coefficient magnitude to keep track of when building NCCs
        """
        if self.variables is None:
            logger.error("BVP variables must be set before problem is built")
        self.problem = de.NLBVP(self.de_domain.domain,
                                variables=self.variables,
                                ncc_cutoff=ncc_cutoff)
 def __init__(self,
              *args,
              ncc_cutoff=1e-10,
              dealias=3 / 2,
              flux_factor=1,
              **kwargs):
     self.flux_factor = flux_factor
     super(FC_equilibrium_solver, self).__init__(*args,
                                                 dealias=dealias,
                                                 **kwargs)
     self.problem = de.NLBVP(
         self.domain,
         variables=['ln_T1', 'ln_rho1', 'ln_T1_z', 'M1'],
         ncc_cutoff=ncc_cutoff)
Esempio n. 4
0
def find_rho(domain,
             rho0,
             T0,
             T0z,
             mass,
             m,
             tol=1e-10,
             n_rho0=3,
             epsilon=1e-4,
             gamma=5. / 3):
    problem = de.NLBVP(domain, variables=['rho', 'ln_rho', 'M'])
    problem.parameters['T'] = T0
    problem.parameters['Tz'] = T0z
    problem.parameters['tot_M'] = mass
    problem.parameters['g'] = 1 + m

    problem.add_equation('dz(M) - rho = 0')
    problem.add_equation('ln_rho = log(rho)')
    problem.add_equation('dz(ln_rho) = -(Tz + g)/T')

    problem.add_bc(' left(M) = 0')
    problem.add_bc('right(M) = tot_M')

    solver = problem.build_solver()
    rho = solver.state['rho']
    ln_rho = solver.state['ln_rho']
    M = solver.state['M']
    rho0.antidifferentiate('z', ('left', 0), out=M)
    ln_rho['g'] = np.copy(np.log(rho0['g']))
    rho['g'] = np.copy(rho0['g'])

    pert = solver.perturbations.data
    pert.fill(1 + tol)
    while np.sum(np.abs(pert)) > tol:
        solver.newton_iteration()

    ln_rho_bot = np.mean(ln_rho.interpolate(z=0)['g'])
    ln_rho_top = np.mean(ln_rho.interpolate(z=Lz)['g'])
    n_rho = ln_rho_bot - ln_rho_top

    d_nrho = n_rho - n_rho0
    dS_0 = -epsilon * n_rho0 * (gamma - 1) / m / gamma
    delta_dS = (gamma - 1) * d_nrho / gamma
    dS = dS_0 + delta_dS
    print(
        'epsilon {} / BL {} / Delta n_rho: {} / dS_0 {}, delta_dS {}, dS/dS_0 {}'
        .format(epsilon, bl_thickness, d_nrho, dS_0, delta_dS, dS / dS_0))

    return rho['g'], ln_rho['g'], d_nrho, dS / dS_0
Esempio n. 5
0
def lane_emden(Nr, m=1.5, n_rho=3, radius=1,
               ncc_cutoff = 1e-10, tolerance = 1e-10, dtype=np.complex128, comm=None):
    # TO-DO: clean this up and make work for ncc ingestion in main script in np.float64 rather than np.complex128
    c = de.SphericalCoordinates('phi', 'theta', 'r')
    d = de.Distributor((c,), comm=comm, dtype=dtype)
    b = de.BallBasis(c, (1, 1, Nr), radius=radius, dtype=dtype)
    br = b.radial_basis
    phi, theta, r = b.local_grids()
    # Fields
    f = d.Field(name='f', bases=b)
    R = d.Field(name='R')
    τ = d.Field(name='τ', bases=b.S2_basis(radius=radius))
    # Parameters and operators
    lap = lambda A: de.Laplacian(A, c)
    lift_basis = b.clone_with(k=2) # match laplacian
    lift = lambda A: de.LiftTau(A, lift_basis, -1)
    problem = de.NLBVP([f, R, τ])
    problem.add_equation((lap(f) + lift(τ), - R**2 * f**m))
    problem.add_equation((f(r=0), 1))
    problem.add_equation((f(r=radius), np.exp(-n_rho/m, dtype=dtype))) # explicit typing to match domain

    # Solver
    solver = problem.build_solver(ncc_cutoff=ncc_cutoff)
    # Initial guess
    f['g'] = np.cos(np.pi/2 * r)**2
    R['g'] = 5

    # Iterations
    logger.debug('beginning Lane-Emden NLBVP iterations')
    pert_norm = np.inf
    while pert_norm > tolerance:
        solver.newton_iteration()
        pert_norm = sum(pert.allreduce_data_norm('c', 2) for pert in solver.perturbations)
        logger.debug(f'Perturbation norm: {pert_norm:.3e}')
    T = d.Field(name='T', bases=br)
    ρ = d.Field(name='ρ', bases=br)
    lnρ = d.Field(name='lnρ', bases=br)
    T['g'] = f['g']
    ρ['g'] = f['g']**m
    lnρ['g'] = np.log(ρ['g'])

    structure = {'T':T,'lnρ':lnρ}
    for key in structure:
        structure[key].require_scales(1)
    structure['r'] = r
    structure['problem'] = {'c':c, 'b':b, 'problem':problem}
    return structure
Esempio n. 6
0
def solve_dedalus(X0, P, domain, tolerance=1e-10, **bvp_kw):
    """Solve for structure using Dedalus NLBVP."""
    # Unpack state vector and parameters
    p0, pz0 = X0
    N2, g, γ = P
    # Setup buoyancy frequency field
    z = domain.grid(0)
    N2f = domain.new_field()
    N2f['g'] = np.array([N2(zi) for zi in z])
    # Setup NLBVP for background
    problem = de.NLBVP(domain, variables=['p', 'pz'], **bvp_kw)
    problem.parameters['γ'] = γ
    problem.parameters['g'] = g
    problem.parameters['p0'] = p0
    problem.parameters['pz0'] = pz0
    problem.parameters['N2'] = N2f
    problem.add_equation("dz(pz) + (N2/g)*pz = pz*pz/p/γ")
    problem.add_equation("dz(p) - pz = 0")
    problem.add_bc("left(p) = p0")
    problem.add_bc("left(pz) = pz0")
    # Start from scipy solution
    z0 = domain.bases[0].interval[0]
    zs = np.concatenate([[z0], z])
    p, pz = solve_scipy(X0, P, zs)
    solver = problem.build_solver()
    solver.state['p']['g'] = p[1:]
    solver.state['pz']['g'] = pz[1:]
    # Solve
    pert = solver.perturbations.data
    pert.fill(1 + tolerance)
    while np.sum(np.abs(pert)) > tolerance:
        solver.newton_iteration()
        logger.info('Perturbation norm: {}'.format(np.sum(np.abs(pert))))
    p = solver.state['p']
    pz = solver.state['pz']
    return p, pz
Esempio n. 7
0
    def loop_tasks(self, tolerance=1e-10):
        """ 
        Perform AE tasks every loop iteration.

        Arguments:
        ---------
        tolerance : float
            convergence tolerance for AE NLBVP
        """
        # Don't do anything AE related if Pe < 1
        if self.flow.grid_average('Pe') < 1 and not self.pe_switch:
            return
        elif not self.pe_switch:
            self.curr_ae_wait_time += self.solver_ivp.sim_time
            self.pe_switch = True

        #If first averaging iteration, reset stuff properly
        first = False
        if not self.doing_ae and not self.finished_ae and self.solver_ivp.sim_time >= self.curr_ae_wait_time:
            self._reset_profiles()  #set time data properly
            self.doing_ae = True
            first = True

        if self.doing_ae:
            self._update_avg_profiles()
            if first: return

            do_AE = self._check_convergence()
            if do_AE:
                #Get averages from global domain
                avg_fields = OrderedDict()
                for k, prof in self.avg_profiles.items():
                    avg_fields[k] = self._communicate_profile(
                        prof / self.elapsed_avg_time)

                #Solve BVP
                if self.dist_ivp.comm_cart.rank == 0:
                    problem = de.NLBVP(
                        self.AE_domain,
                        variables=['T1', 'T1_z', 'p', 'delta_T1', 'Xi'])
                    for k, p in (['P', self.P], ['R', self.R]):
                        problem.parameters[k] = p
                    for k, p in avg_fields.items():
                        f = self.AE_domain.new_field()
                        f['g'] = p
                        problem.parameters[k] = f
                    self._set_AE_equations(problem)
                    solver = problem.build_solver()
                    pert = solver.perturbations.data
                    pert.fill(1 + tolerance)
                    while np.sum(np.abs(pert)) > tolerance:
                        solver.newton_iteration()
                        logger.info('Perturbation norm: {}'.format(
                            np.sum(np.abs(pert))))
                else:
                    solver = None

                # Update fields appropriately
                ae_structure = self._broadcast_ae_solution(solver)
                diff = self._update_simulation_state(ae_structure, avg_fields)

                #communicate diff
                if diff < self.ivp_convergence_thresh: self.finished_ae = True
                logger.info('Diff: {:.4e}, finished_ae? {}'.format(
                    diff, self.finished_ae))
                self.doing_ae = False
                self.curr_ae_wait_time = self.solver_ivp.sim_time + self.ae_wait_time
                self.curr_ae_avg_time = self.ae_avg_time
                self.curr_ae_avg_thresh = self.ae_avg_thresh
Esempio n. 8
0
def heated_polytrope(nz, γ, ε, n_h,
                     tolerance = 1e-8,
                     ncc_cutoff = 1e-10,
                     dealias = 2,
                     verbose=False):

    import dedalus.public as de

    cP = γ/(γ-1)
    m_ad = 1/(γ-1)

    s_c_over_c_P = scrS = 1 # s_c/c_P = 1

    logger.info("γ = {:.3g}, ε={:.3g}".format(γ, ε))

    # this assumes h_bot=1, grad_φ = (γ-1)/γ (or L=Hρ)
    h_bot = 1
    # generally, h_slope = -1/(1+m)
    # start in an adibatic state, heat from there
    h_slope = -1/(1+m_ad)
    grad_φ = (γ-1)/γ

    Lz = -1/h_slope*(1-np.exp(-n_h))

    print(n_h, Lz, h_slope)

    c = de.CartesianCoordinates('z')
    d = de.Distributor(c, dtype=np.float64)
    zb = de.ChebyshevT(c.coords[-1], size=nz, bounds=(0, Lz), dealias=dealias)
    b = zb
    z = zb.local_grid(1)
    zd = zb.local_grid(dealias)

    # Fields
    θ = d.Field(name='θ', bases=b)
    Υ = d.Field(name='Υ', bases=b)
    s = d.Field(name='s', bases=b)
    u = d.VectorField(c, name='u', bases=b)

    # Taus
    lift_basis = zb.clone_with(a=zb.a+2, b=zb.b+2)
    lift = lambda A, n: de.Lift(A, lift_basis, n)
    lift_basis1 = zb.clone_with(a=zb.a+1, b=zb.b+1)
    lift1 = lambda A, n: de.Lift(A, lift_basis1, n)
    τ_h1 = d.VectorField(c,name='τ_h1')
    τ_s1 = d.Field(name='τ_s1')
    τ_s2 = d.Field(name='τ_s2')

    # Parameters and operators
    lap = lambda A: de.Laplacian(A, c)
    grad = lambda A: de.Gradient(A, c)

    ez, = c.unit_vector_fields(d)

    # NLBVP goes here
    # intial guess
    h0 = d.Field(name='h0', bases=zb)
    θ0 = d.Field(name='θ0', bases=zb)
    Υ0 = d.Field(name='Υ0', bases=zb)
    s0 = d.Field(name='s0', bases=zb)
    structure = {'h':h0,'s':s0,'θ':θ0,'Υ':Υ0}
    for key in structure:
        structure[key].change_scales(dealias)
    h0['g'] = h_bot + zd*h_slope #(Lz+1)-z
    θ0['g'] = np.log(h0).evaluate()['g']
    Υ0['g'] = (m_ad*θ0).evaluate()['g']
    s0['g'] = 0

    problem = de.NLBVP([h0, s0, Υ0, τ_s1, τ_s2, τ_h1])
    problem.add_equation((grad(h0) + lift1(τ_h1,-1),
                         -grad_φ*ez + h0*grad(s0)))
    problem.add_equation((-lap(h0)
    + lift(τ_s1,-1) + lift(τ_s2,-2), ε))
    problem.add_equation(((γ-1)*Υ0 + s_c_over_c_P*γ*s0, np.log(h0)))
    problem.add_equation((Υ0(z=0), 0))
    problem.add_equation((h0(z=0), 1))
    problem.add_equation((h0(z=Lz), np.exp(-n_h)))

    # Solver
    solver = problem.build_solver(ncc_cutoff=ncc_cutoff)
    pert_norm = np.inf
    while pert_norm > tolerance:
        solver.newton_iteration()
        pert_norm = sum(pert.allreduce_data_norm('c', 2) for pert in solver.perturbations)
        logger.info('current perturbation norm = {:.3g}'.format(pert_norm))

    if verbose:
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots()
        ax2 = ax.twinx()

        ax.plot(zd, h0['g'], linestyle='dashed', color='xkcd:dark grey', label='h')
        ax2.plot(zd, np.log(h0).evaluate()['g'], label=r'$\ln h$')
        ax2.plot(zd, Υ0['g'], label=r'$\ln \rho$')
        ax2.plot(zd, s0['g'], color='xkcd:brick red', label=r'$s$')
        ax.legend()
        ax2.legend()
        fig.savefig('heated_polytrope_nh{}_eps{}_gamma{:.3g}.pdf'.format(n_h,ε,γ))

    for key in structure:
        structure[key].change_scales(1)

    return structure
    def solve_BVP(self,
                  atmosphere_kwargs,
                  diffusivity_args,
                  bc_kwargs,
                  tolerance=1e-10):
        """
        Solves a BVP in a 2D Boussinesq box.

        The BVP calculates updated temperature / pressure fields, then updates 
        the solver states which are tracked in self.solver_states.  
        This automatically updates the IVP's fields.

        """
        super(BoussinesqBVPSolver, self).solve_BVP()
        nz = atmosphere_kwargs['nz']
        # Create space for the returned profiles on all processes.
        return_dict = OrderedDict()
        for v in self.VARS.keys():
            return_dict[v] = np.zeros(self.nz, dtype=np.float64)

        # No need to waste processor power on multiple bvps, only do it on one
        if self.rank == 0:
            vel_adjust_factor = 1
            atmosphere = self.atmosphere_class(dimensions=1,
                                               comm=MPI.COMM_SELF,
                                               **atmosphere_kwargs)
            atmosphere.problem = de.NLBVP(atmosphere.domain,
                                          variables=['T1', 'T1_z', 'p1'],
                                          ncc_cutoff=tolerance)

            #Zero out old varables to make atmospheric substitutions happy.
            old_vars = ['u', 'w', 'dx(A)', 'uz', 'wz']
            for sub in old_vars:
                atmosphere.problem.substitutions[sub] = '0'

            atmosphere._set_parameters(*diffusivity_args)
            atmosphere._set_subs()

            # Create the appropriate enthalpy flux profile based on boundary conditions
            self._update_profiles_dict(bc_kwargs, atmosphere,
                                       vel_adjust_factor)

            #Add time and horizontally averaged profiles from IVP to the problem as parameters
            for k in self.FIELDS.keys():
                f = atmosphere._new_ncc()
                f.set_scales(
                    self.nz / nz, keep_data=True
                )  #If nz(bvp) =/= nz(ivp), this allows interaction between them
                if len(self.profiles_dict[k].shape) == 2:
                    f['g'] = self.profiles_dict[k].mean(axis=0)
                else:
                    f['g'] = self.profiles_dict[k]
                atmosphere.problem.parameters[k] = f

            self._set_eqns(atmosphere.problem)
            self._set_BCs(atmosphere, bc_kwargs)

            # Solve the BVP
            solver = atmosphere.problem.build_solver()

            pert = solver.perturbations.data
            pert.fill(1 + tolerance)
            while np.sum(np.abs(pert)) > tolerance:
                solver.newton_iteration()
                logger.info('Perturbation norm: {}'.format(np.sum(
                    np.abs(pert))))

            T1 = solver.state['T1']
            T1_z = solver.state['T1_z']
            P1 = solver.state['p1']

            #Appropriately adjust T1 in IVP
            T1.set_scales(self.nz / nz, keep_data=True)
            return_dict['T1_IVP'] += T1['g']

            #Appropriately adjust T1_z in IVP
            T1_z.set_scales(self.nz / nz, keep_data=True)
            return_dict['T1_z_IVP'] += T1_z['g']

            #Appropriately adjust p in IVP
            P1.set_scales(self.nz / nz, keep_data=True)
            return_dict['p_IVP'] += P1['g']
        else:
            for v in self.VARS.keys():
                return_dict[v] *= 0
        logger.info(return_dict)

        self.comm.Barrier()
        # Communicate output profiles from proc 0 to all others.
        for v in self.VARS.keys():
            glob = np.zeros(self.nz)
            self.comm.Allreduce(return_dict[v], glob, op=MPI.SUM)
            return_dict[v] = glob

        vel_adj_loc = np.zeros(1)
        vel_adj_glob = np.zeros(1)
        if self.rank == 0:
            vel_adj_loc[0] = vel_adjust_factor
        self.comm.Allreduce(vel_adj_loc, vel_adj_glob, op=MPI.SUM)

        # Actually update IVP states
        for v in self.VARS.keys():
            #Subtract out current avg
            self.solver_states[v].set_scales(1, keep_data=True)
            self.solver_states[v]['g'] -= self.solver_states[v]['g'].mean(
                axis=0)
            #Put in right avg
            self.solver_states[v].set_scales(1, keep_data=True)
            self.solver_states[v]['g'] += return_dict[v][
                self.n_per_proc * self.rank:self.n_per_proc * (self.rank + 1)]
        for v in self.VEL_VARS.keys():
            self.vel_solver_states[v]['g'] *= vel_adj_glob[0]

        self._reset_fields()
Esempio n. 10
0
# Build domain
z_basis = de.Chebyshev('z', Nz, interval=(0, Lz), dealias=2)
domain = de.Domain([z_basis], grid_dtype=np.float64)

phi = domain.new_field()
phi_rho_g = domain.new_field()
z = domain.grid(0)

phi['g'] = phi_0 + (1 - phi_0) * a * z
rho_g_init = rho_0 * np.exp(-z * b / rho_0)
phi_rho_g['g'] = phi['g'] * rho_g_init

# Setup problem
problem = de.NLBVP(domain,
                   variables=['w_g', 'w_m', 'wz_m'],
                   ncc_cutoff=ncc_cutoff)
problem.parameters['alpha'] = alpha
problem.parameters['beta'] = beta
problem.parameters['B2'] = 1
problem.parameters['B3'] = a
problem.parameters['phi'] = phi
problem.parameters['phi_rho_g'] = phi_rho_g
problem.add_equation(
    "alpha*(w_m - w_g) = beta*dz(phi_rho_g) + phi_rho_g - beta*phi_rho_g * dz(phi) / phi",
    tau=False)
problem.add_equation(
    "(4/3)*alpha*(dz(wz_m)) - alpha*(w_m - w_g) = (phi - phi_rho_g) + (4/3)*alpha*(1+phi**2)*dz(phi)/phi*wz_m - phi*(phi - phi_rho_g)",
    tau=True)
problem.add_equation("wz_m - dz(w_m) = 0", tau=True)
problem.add_bc("left(w_m) = B2")
Esempio n. 11
0
def compute_background(domain, params, plot=False):

    # Setup problem
    problem = de.NLBVP(domain,
                       variables=['phi', 'phi_rho_g', 'w_g', 'w_m', 'wz_m'],
                       ncc_cutoff=params.bvp_ncc_cutoff)
    problem.parameters['alpha'] = params.alpha
    problem.parameters['beta'] = params.beta
    problem.parameters['B0'] = params.phi_0
    problem.parameters['B1'] = params.phi_0 * params.rho_0
    problem.parameters['B2'] = 1
    problem.parameters['B3'] = params.a
    problem.substitutions['dt(A)'] = "0*A"
    problem.add_equation("- dt(phi) + dz(w_m) = dz(phi * w_m)", tau=True)
    problem.add_equation(
        "dt(phi_rho_g) + dz(phi_rho_g) = dz(phi_rho_g) - dz(phi_rho_g * w_g)",
        tau=True)
    problem.add_equation(
        "alpha*(w_m - w_g) - beta*dz(phi_rho_g) - phi_rho_g = - beta*phi_rho_g * dz(phi) / phi",
        tau=False)
    problem.add_equation(
        "(4/3)*alpha*(dz(wz_m)) - alpha*(w_m - w_g) - (phi - phi_rho_g) = (4/3)*alpha*(1+phi**2)*dz(phi)/phi*wz_m - phi*(phi - phi_rho_g)",
        tau=True)
    problem.add_equation("wz_m - dz(w_m) = 0", tau=True)
    problem.add_bc("left(phi) = B0")
    problem.add_bc("left(phi_rho_g) = B1")
    problem.add_bc("left(w_m) = B2")
    problem.add_bc("left(wz_m) = B3")

    # Setup initial guess
    solver = problem.build_solver()
    logger.info('Solver built')

    # Initial conditions
    z = domain.grid(0)
    phi = solver.state['phi']
    phi_rho_g = solver.state['phi_rho_g']
    w_g = solver.state['w_g']
    w_m = solver.state['w_m']
    wz_m = solver.state['wz_m']

    phi['g'] = params.phi_0 + (1 - params.phi_0) * params.a * z
    rho_g_init = params.rho_0 * np.exp(-z * params.b / params.rho_0)
    phi_rho_g['g'] = phi['g'] * rho_g_init
    w_g['g'] = params.wg_0 * (1 + params.a * z)
    w_m['g'] = 1 + params.a * z

    # Iterations
    pert = solver.perturbations.data
    pert.fill(1 + params.tolerance)
    start_time = time.time()
    while np.sum(np.abs(pert)) > params.tolerance:
        solver.newton_iteration()
        logger.info('Perturbation norm: {}'.format(np.sum(np.abs(pert))))
    end_time = time.time()
    logger.info('-' * 20)
    logger.info('Iterations: {}'.format(solver.iteration))
    logger.info('Run time: %.2f sec' % (end_time - start_time))

    if plot:
        rho_g = (phi_rho_g / phi).evaluate()

        import matplotlib
        matplotlib.use("Agg")
        import matplotlib.pyplot as plt
        fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4)
        phi.set_scales(1)
        rho_g.set_scales(1)
        w_g.set_scales(1)
        w_m.set_scales(1)
        ax1.plot(phi['g'], z, '.-')
        ax1.set_title('phi')
        ax2.plot(rho_g['g'], z, '.-')
        ax2.set_title('rho_g')
        ax3.plot(w_m['g'], z, '.-')
        ax3.set_title('w_m')
        ax4.plot(w_g['g'], z, '.-')
        ax4.set_title('w_g')
        plt.savefig("background.pdf")

        fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
        ax1.plot(np.abs(phi['c']), '.-')
        ax1.set_title('phi')
        ax1.set_yscale('log')
        ax2.plot(np.abs(rho_g['c']), '.-')
        ax2.set_title('rho_g')
        ax2.set_yscale('log')
        ax3.plot(np.abs(w_m['c']), '.-')
        ax3.set_title('w_m')
        ax3.set_yscale('log')
        ax4.plot(np.abs(w_g['c']), '.-')
        ax4.set_title('w_g')
        ax4.set_yscale('log')
        plt.savefig("background_coeffs.pdf")

    return solver
gamma = 5/3
m_ad = 1/(gamma-1)
m = m_poly
logger.info("m={}, m_ad = {}, m_poly=(3-{})/(1+{})={}".format(m, m_ad, b, a, m_poly))
ε = 0.5 #1e-3
Lz = 5 ; Q = 1-ε

tau_0_BB14 = 4e-4*np.array([1e4,1e5,1e6,1e7])*5
F_over_cE_BB14 = 1/4*(np.array([26600, 16300,9300,5200])/38968)**4
Q_BB14 = tau_0_BB14*F_over_cE_BB14

z_basis = de.Chebyshev('z', nz, interval=(0,Lz), dealias=2)
domain = de.Domain([z_basis], np.float64, comm=MPI.COMM_SELF)

problem = de.NLBVP(domain, variables=['ln_T', 'ln_rho'], ncc_cutoff=ncc_cutoff)
problem.parameters['a'] = a
problem.parameters['b'] = b
problem.parameters['g'] = g = (m+1)
problem.parameters['Lz'] = Lz
problem.parameters['gamma'] = gamma
problem.parameters['ε'] = ε
problem.parameters['Q'] = Q
problem.parameters['lnT0'] = lnT0 = 0
problem.parameters['lnρ0'] = lnρ0 = m*lnT0
problem.substitutions['ρκ(ln_rho,ln_T)'] = "exp(ln_rho*(a+1)+ln_T*(b))"
problem.add_equation("dz(ln_T) = -Q*exp(ln_rho*(a+1)+ln_T*(b-4))")
problem.add_equation("dz(ln_T) + dz(ln_rho) = -g*exp(-ln_T)")
problem.add_bc("left(ln_T)   = lnT0")
problem.add_bc("left(ln_rho) = lnρ0")
Esempio n. 13
0
    def solve_BVP(self,
                  atmosphere_kwargs,
                  diffusivity_kwargs,
                  tolerance=1e-13):
        """
        Solves a BVP in a 2D FC_ConstHeating atmosphere under the kappa/mu formulation of the equations.
        Run parameters are specified, and should be similar to those of the bvp.

        The BVP calculates updated rho / temperature fields, then updates the solver states which are
        tracked in self.solver_states.  This automatically updates the IVP's fields.

        """
        super(FC_BVP_solver, self).solve_BVP()
        nz = atmosphere_kwargs['nz']

        # No need to waste processor power on multiple bvps, only do it on one
        if self.rank == 0:
            atmosphere = self.atmosphere_class(dimensions=1,
                                               comm=MPI.COMM_SELF,
                                               **atmosphere_kwargs)
            #Variables are T, dz(T), rho, integrated mass
            atmosphere.problem = de.NLBVP(atmosphere.domain, variables=['T1', 'T1_z', 'rho1', 'M1'],\
                                            ncc_cutoff=tolerance)

            #Zero out old varables to make atmospheric substitutions happy.
            old_vars = ['u', 'w', 'ln_rho1', 'v', 'u_z', 'w_z', 'v_z', 'dx(A)']
            for sub in old_vars:
                atmosphere.problem.substitutions[sub] = '0'

            atmosphere._set_diffusivities(**diffusivity_kwargs)
            atmosphere._set_parameters()
            atmosphere._set_subs()

            #Add time and horizontally averaged profiles from IVP to the problem as parameters
            for k in self.FIELDS.keys():
                f = atmosphere._new_ncc()
                f.set_scales(
                    self.nz / nz, keep_data=True
                )  #If nz(bvp) =/= nz(ivp), this allows interaction between them
                f['g'] = self.profiles_dict[k]
                atmosphere.problem.parameters[k] = f

            self._set_subs(atmosphere.problem)
            self._set_eqns(atmosphere.problem)
            self._set_BCs(atmosphere.problem)

            # Solve the BVP
            solver = atmosphere.problem.build_solver()

            pert = solver.perturbations.data
            pert.fill(1 + tolerance)
            while np.sum(np.abs(pert)) > tolerance:
                solver.newton_iteration()
                logger.info('Perturbation norm: {}'.format(np.sum(
                    np.abs(pert))))

            T1 = solver.state['T1']
            T1_z = solver.state['T1_z']
            rho1 = solver.state['rho1']

        # Create space for the returned profiles on all processes.
        return_dict = dict()
        for v in self.VARS.keys():
            return_dict[v] = np.zeros(self.nz, dtype=np.float64)

        if self.rank == 0:
            #Appropriately adjust T1 in IVP
            T1.set_scales(self.nz / nz, keep_data=True)
            return_dict['T1_IVP'] = T1['g'] + self.profiles_dict[
                'T1_IVP'] - self.profiles_dict_curr['T1_IVP']

            #Appropriately adjust T1_z in IVP
            T1_z.set_scales(self.nz / nz, keep_data=True)
            return_dict['T1_z_IVP'] = T1_z['g'] + self.profiles_dict[
                'T1_z_IVP'] - self.profiles_dict_curr['T1_z_IVP']

            #Appropriately adjust ln_rho1 in IVP
            rho1.set_scales(self.nz / nz, keep_data=True)
            return_dict['ln_rho1_IVP'] = np.log(
                1 + (rho1['g'] + self.profiles_dict['rho_full_IVP'] -
                     self.profiles_dict_curr['rho_full_IVP']) /
                self.profiles_dict_curr['rho_full_IVP'])
            print('returning the following avg profiles from BVP\n',
                  return_dict)

        self.comm.Barrier()
        # Communicate output profiles from proc 0 to all others.
        for v in self.VARS.keys():
            glob = np.zeros(self.nz)
            self.comm.Allreduce(return_dict[v], glob, op=MPI.SUM)
            return_dict[v] = glob

        # Actually update IVP states
        for v in self.VARS.keys():
            self.solver_states[v].set_scales(1, keep_data=True)
            self.solver_states[v]['g'] += return_dict[v][
                self.n_per_proc * self.rank:self.n_per_proc * (self.rank + 1)]

        self._reset_fields()
Esempio n. 14
0
from dedalus import public as de

import logging
logger = logging.getLogger(__name__)


# Parameters
n = 3.25

# Build domain
x_basis = de.Chebyshev('x', 128, interval=(0, 1), dealias=2)
domain = de.Domain([x_basis], np.float64)

# Setup problem
problem = de.NLBVP(domain, variables=['f', 'fx', 'R'])
problem.parameters['n'] = n
problem.add_equation("x*dx(fx) + 2*fx = -x*(R**2)*(f**n)")
problem.add_equation("fx - dx(f) = 0")
problem.add_equation("dx(R) = 0")
problem.add_bc("left(f) = 1")
problem.add_bc("left(fx) = 0")
problem.add_bc("right(f) = 0")

# Setup initial guess
solver = problem.build_solver()
x = domain.grid(0, scales=domain.dealias)
f = solver.state['f']
fx = solver.state['fx']
R = solver.state['R']
f['g'] = np.cos(np.pi/2 * x)*0.9
Esempio n. 15
0
def structure_bvp(atmo_class, atmo_args, atmo_kwargs, profiles, scalars):
    """
    Solves a BVP to get the right FT atmospheric structure

    Inputs:
    -------
        atmo_class : The class type of the atmosphere object
        atmo_args : tuple
            args for atmo_class.__init__()
        atmo_kwargs : dict
            kwargs for atmo_class.__init__()
        profiles : OrderedDict
            A dictionary with profiles required for the BVP
        scalars : OrderedDict
            A dictionary with scalar values required for the BVP
    """

    # Grab important raw TT values
    dS_TT = scalars['s_over_cp_z']
    Nu = scalars['Nu']
    T1_TT = profiles['T1']
    UdotGradw_TT = profiles['UdotGradw']

    # Construct Dedalus setup
    atmosphere = atmo_class(*atmo_args, **atmo_kwargs)
    Lz = atmosphere.Lz
    z_basis = de.Chebyshev('z', len(T1_TT), interval=[0, Lz], dealias=1)
    domain = de.Domain([
        z_basis,
    ], grid_dtype=np.float64, comm=MPI.COMM_SELF)
    problem = de.NLBVP(domain, variables=['dS', 'S', 'ln_rho1', 'M1'])
    atmosphere.build_atmosphere(domain, problem)
    z = domain.grid(0)

    # Remove the 1/Cp from dS/Cp
    dS_TT *= atmosphere.Cp

    # Solve out for Temp profile of the FT case
    S0 = domain.new_field()
    T_TT = domain.new_field()
    T1_FT = domain.new_field()
    UdotGradw = domain.new_field()

    grad_ad = -(atmosphere.g / atmosphere.Cp)
    T_TT['g'] = atmosphere.T0['g'] + T1_TT
    T_ad = 1 + grad_ad * (z - Lz)
    dT_ad_TT = np.abs(
        np.mean(T_TT.interpolate(z=Lz)['g'] -
                T_TT.interpolate(z=0)['g'])) - np.abs(grad_ad * Lz)
    dT_ad_FT = dT_ad_TT / Nu
    T1_FT['g'] = dT_ad_FT * (
        (T_TT['g'] - T_ad) / dT_ad_TT) + T_ad - atmosphere.T0['g']

    # Setup S0, other constants
    S0['g'] = atmosphere.Cp * (
        (1 / atmosphere.ɣ) * np.log(atmosphere.T0['g']) -
        ((atmosphere.ɣ - 1) / atmosphere.ɣ) * np.log(atmosphere.rho0['g']))
    dS0 = np.mean(S0.interpolate(z=Lz)['g'] - S0.interpolate(z=0)['g'])
    evolved_Ra_factor = (dS_TT / dS0)
    UdotGradw['g'] = UdotGradw_TT

    # Feed parameters into the problem (many are fed in through atmosphere class)
    problem.parameters['T1_FT'] = T1_FT
    problem.parameters['dS_TT'] = dS_TT
    problem.parameters['UdotGradw_TT'] = UdotGradw
    problem.substitutions['ln_rho0'] = 'log(rho0)'

    # Hydrostatic equilibrium (modified) + mass conservation.
    problem.add_equation(
        "(T0 + T1_FT)*dz(ln_rho1) = -dz(T1_FT) - T1_FT*ln_rho0_z + (dS/dS_TT)*UdotGradw_TT"
    )
    problem.add_equation("dz(M1) = rho0*(exp(ln_rho1) - 1)")
    problem.add_equation(
        "S/Cp = (1/ɣ) * log(T0 + T1_FT) - ((ɣ-1)/ɣ)*(ln_rho0 + ln_rho1)")
    problem.add_equation("dS = right(S) - left(S)")
    problem.add_bc(" left(M1) = 0")
    problem.add_bc("right(M1) = 0")

    # Solve NLBVP
    tol = 1e-10
    solver = problem.build_solver()
    dS = solver.state['dS']
    ln_rho1_FT = solver.state['ln_rho1']
    pert = solver.perturbations.data
    pert.fill(1 + tol)
    while np.sum(np.abs(pert)) > tol:
        solver.newton_iteration()
        print('pert norm: {} / dS: {:.2e}'.format(np.sum(np.abs(pert)),
                                                  np.mean(dS['g'])))

    dS_FT = np.mean(dS['g'])
    FT_Ra_factor = (dS0 / dS_FT) * evolved_Ra_factor

    return T1_FT['g'], ln_rho1_FT[
        'g'], dS_FT / dS_TT, dT_ad_FT / dT_ad_TT, FT_Ra_factor
Esempio n. 16
0
import logging
logger = logging.getLogger(__name__)

# Parameters
Nx = 128
n = 3.25
ncc_cutoff = 1e-4
tolerance = 1e-8

# Build domain
x_basis = de.Chebyshev('x', Nx, interval=(0, 1), dealias=2)
domain = de.Domain([x_basis], np.float64)

# Setup problem
problem = de.NLBVP(domain, variables=['f', 'fx', 'R'], ncc_cutoff=ncc_cutoff)
problem.meta['R']['x']['constant'] = True
problem.parameters['n'] = n
problem.add_equation("x*dx(fx) + 2*fx = -x*(R**2)*(f**n)", tau=False)
problem.add_equation("fx - dx(f) = 0")
problem.add_bc("left(f) = 1")
problem.add_bc("right(f) = 0")

# Setup initial guess
solver = problem.build_solver()
x = domain.grid(0)
f = solver.state['f']
fx = solver.state['fx']
R = solver.state['R']
f['g'] = np.cos(np.pi / 2 * x) * 0.9
f.differentiate('x', out=fx)
Esempio n. 17
0
dtype = np.float64

# Bases
coords = d3.SphericalCoordinates('phi', 'theta', 'r')
dist = d3.Distributor(coords, dtype=dtype)
basis = d3.BallBasis(coords, (1, 1, Nr), radius=1, dtype=dtype, dealias=dealias)

# Fields
f = dist.Field(name='f', bases=basis)
tau = dist.Field(name='tau', bases=basis.S2_basis(radius=1))

# Substitutions
lift = lambda A: d3.Lift(A, basis, -1)

# Problem
problem = d3.NLBVP([f, tau], namespace=locals())
problem.add_equation("lap(f) + lift(tau) = - f**n")
problem.add_equation("f(r=1) = 0")

# Initial guess
phi, theta, r = dist.local_grids(basis)
R0 = 5
f['g'] = R0**(2/(n-1)) * (1 - r**2)**2

# Solver
solver = problem.build_solver(ncc_cutoff=ncc_cutoff)
pert_norm = np.inf
f.change_scales(dealias)
steps = [f['g'].ravel().copy()]
while pert_norm > tolerance:
    solver.newton_iteration()