def run_strat_sim(set_ICs, name, params): snapshots_dir = SNAPSHOTS_DIR % name logger = logging.getLogger(name) solver, domain = get_solver(params) # Initial conditions set_ICs(solver, domain, params) # filename = '{s}/{s}_s1.h5'.format(s=snapshots_dir) # write, dt = solver.load_state(filename, -30) # print("=====strat_helper.py=====", "loaded", write) cfl = CFL(solver, initial_dt=params['DT'], cadence=10, max_dt=5, min_dt=0.01, safety=0.5, threshold=0.10) cfl.add_velocities(('ux', 'uz')) cfl.add_frequency(params['DT']) snapshots = solver.evaluator.add_file_handler(snapshots_dir, sim_dt=params['T_F'] / params['NUM_SNAPSHOTS']) snapshots.add_system(solver.state) # Flow properties flow = GlobalFlowProperty(solver, cadence=10) flow.add_property("sqrt(ux*ux + uz*uz) / NU", name='Re') # Main loop logger.info('Starting sim...') slices = domain.dist.coeff_layout.slices(scales=1) (len_x, len_z) = domain.dist.coeff_layout.global_shape(scales=1) # mask kicks in 1/3 of the way, gaussian decay len_x_damp = len_x - (len_x // 3) len_z_damp = len_z - (len_z // 3) x_mask = np.concatenate( (np.ones(len_x // 3), np.exp(-16 * np.arange(len_x_damp)**2 / len_x_damp**2))) z_mask = np.concatenate( (np.ones(len_z // 3), np.exp(-16 * np.arange(len_z_damp)**2 / len_z_damp**2))) mask = np.outer(x_mask, z_mask) while solver.ok: cfl_dt = cfl.compute_dt() if params.get('USE_CFL') else params['DT'] solver.step(cfl_dt) curr_iter = solver.iteration for field in solver.state.fields: field['c'] *= mask[slices] if curr_iter % int( (params['T_F'] / params['DT']) / params['NUM_SNAPSHOTS']) == 0: logger.info('Reached time %f out of %f, timestep %f vs max %f', solver.sim_time, solver.stop_sim_time, cfl_dt, params['DT']) logger.info('Max Re = %f' % flow.max('Re'))
def __init__(self, solver_IVP, de_domain_IVP, root_dir, file_dir=None): """ Initialize the FieldAverager. Arguments: ---------- solver_IVP : Dedalus Solver object The solver from the IVP in which averages are being taken de_domain_IVP : DedalusDomain object The domain on which the IVP is being solved root_dir : string Root output directory file_dir : string, optional Output average files to root_dir/file_dir. If None, output to root_dir/OUT_DIR. """ self.solver_IVP = solver_IVP self.de_domain_IVP = de_domain_IVP self.rank = de_domain_IVP.domain.dist.comm_cart.rank if len(de_domain_IVP.domain.dist.mesh) == 0: self.nz_per_proc = int(de_domain_IVP.resolution[0] / de_domain_IVP.domain.dist.comm_cart.size) else: self.nz_per_proc = int(de_domain_IVP.resolution[0] / de_domain_IVP.domain.dist.mesh[-1]) self.flow = GlobalFlowProperty(solver_IVP, cadence=1) self.measured_profiles, self.avg_profiles, self.local_l2 = OrderedDict( ), OrderedDict(), OrderedDict() for k, fd in self.FIELDS.items(): self.flow.add_property('plane_avg({})'.format(fd), name='{}'.format(k)) self.measured_profiles[k] = np.zeros((2, self.nz_per_proc)) self.avg_profiles[k] = np.zeros(self.nz_per_proc) self.local_l2[k] = np.zeros(self.nz_per_proc) self.avg_times = np.zeros(2) self.elapsed_avg_time = 0 self.n_files_saved = 0 if file_dir is None: file_dir = self.OUT_DIR self.file_dir = '{:s}/{:s}/'.format(root_dir, file_dir) mpi_makedirs(self.file_dir)
def run_strat_sim(set_ICs, name, params): snapshots_dir = SNAPSHOTS_DIR % name filename = '{s}/{s}_s1.h5'.format(s=snapshots_dir) logger = logging.getLogger(name) solver, domain = get_solver(params) # Initial conditions dt = params['DT'] _, dt = set_ICs(name, solver, domain, params) cfl = CFL(solver, initial_dt=dt, cadence=10, max_dt=params['DT'], min_dt=0.01, safety=0.5, threshold=0.10) cfl.add_velocities(('ux', 'uz')) cfl.add_frequency(params['DT']) snapshots = solver.evaluator.add_file_handler(snapshots_dir, sim_dt=params['T_F'] / params['NUM_SNAPSHOTS']) snapshots.add_system(solver.state) # Flow properties flow = GlobalFlowProperty(solver, cadence=10) flow.add_property('sqrt((ux / NU)**2 + (uz / NU)**2)', name='Re') # Main loop logger.info('Starting sim...') while solver.ok: cfl_dt = cfl.compute_dt() if params.get('USE_CFL') else params['DT'] # if cfl_dt < params['DT'] / 8: # small step sizes if strongly cfl limited # cfl_dt /= 2 solver.step(cfl_dt) curr_iter = solver.iteration if curr_iter % int( (params['T_F'] / params['DT']) / params['NUM_SNAPSHOTS']) == 0: logger.info('Reached time %f out of %f, timestep %f vs max %f', solver.sim_time, solver.stop_sim_time, cfl_dt, params['DT']) logger.info('Max Re = %f' % flow.max('Re'))
def run_strat_sim(name, params): populate_globals(params) snapshots_dir = SNAPSHOTS_DIR % name solver, domain = get_solver(params) # Initial conditions _, dt = set_ic(name, solver, domain, params) cfl = CFL(solver, initial_dt=dt, cadence=5, max_dt=DT, min_dt=0.007, safety=0.5, threshold=0.10) cfl.add_velocities(('ux', 'uz')) cfl.add_frequency(DT) snapshots = solver.evaluator.add_file_handler(snapshots_dir, sim_dt=T_F / NUM_SNAPSHOTS) snapshots.add_system(solver.state) snapshots.add_task("integ(RHO0 * ux * uz, 'x') / XMAX", name='S_{px}') # Flow properties flow = GlobalFlowProperty(solver, cadence=10) flow.add_property('sqrt(ux**2 + ux**2)', name='u') # Main loop logger.info('Starting sim...') while solver.ok: cfl_dt = cfl.compute_dt() if NL else DT solver.step(cfl_dt) curr_iter = solver.iteration if curr_iter % int((T_F / DT) / NUM_SNAPSHOTS) == 0: logger.info('Reached time %f out of %f, timestep %f vs max %f', solver.sim_time, solver.stop_sim_time, cfl_dt, DT) logger.info('Max u = %e' % flow.max('u'))
def __init__(self, nz, solver_ivp, dist_ivp, ae_fields, extra_fields, P, R, first_ae_wait_time=30, ae_wait_time=20, first_ae_avg_time=20, ae_avg_time=10, first_ae_avg_thresh=1e-2, ae_avg_thresh=1e-3, ivp_convergence_thresh=1e-2): """ Initialize the object by grabbing solver states and making room for profile averages Arguments: ---------- All arguments have identical descriptions to their description in the class level docstring. """ self.ivp_convergence_thresh = ivp_convergence_thresh self.first_ae_wait_time = self.curr_ae_wait_time = first_ae_wait_time self.first_ae_avg_time = self.curr_ae_avg_time = first_ae_avg_time self.first_ae_avg_thresh = self.curr_ae_avg_thresh = first_ae_avg_thresh self.ae_wait_time = ae_wait_time self.ae_avg_time = ae_avg_time self.ae_avg_thresh = ae_avg_thresh self.nz = nz self.solver_ivp = solver_ivp self.dist_ivp = dist_ivp self.ae_fields = ae_fields self.extra_fields = extra_fields self.P, self.R = P, R self.doing_ae, self.finished_ae, self.pe_switch = False, False, False #Set up profiles and simulation tracking self.flow = GlobalFlowProperty(solver_ivp, cadence=1) self.z_slices = self.dist_ivp.grid_layout.slices(scales=1)[-1] self.nz_per_proc = self.dist_ivp.grid_layout.local_shape(scales=1)[-1] self.measured_times = np.zeros(2) self.elapsed_avg_time = 0 self.measured_profiles, self.avg_profiles, self.local_l2 = OrderedDict( ), OrderedDict(), OrderedDict() for k in ae_fields: self.flow.add_property('plane_avg({})'.format(k), name='{}'.format(k)) self.measured_profiles[k] = np.zeros((2, self.nz_per_proc)) self.avg_profiles[k] = np.zeros(self.nz_per_proc) self.local_l2[k] = np.zeros(self.nz_per_proc) for k in extra_fields: self.flow.add_property('plane_avg({})'.format(k), name='{}'.format(k)) self.flow.add_property('Pe', name='Pe') if self.dist_ivp.comm_cart.rank == 0: self.AE_basis = de.Chebyshev('z', self.nz, interval=[-1. / 2, 1. / 2], dealias=3. / 2) self.AE_domain = de.Domain([ self.AE_basis, ], grid_dtype=np.float64, comm=MPI.COMM_SELF) else: self.AE_basis = self.AE_domain = None
class BoussinesqAESolver: """ Logic for coupling into a Dedalus IVP solve of Boussinesq, Rayleigh-Benard Convection. Currently only implemented for mixed thermal boundary conditions (fixed-flux at bottom, fixed-temp at top). Attributes: ----------- (first_/curr_)ae_wait_time: float Freefall times to wait before collecting averages on (first/current) AE solve (first_/curr_)ae_avg_time: float Minimum number of freefall times over which to take averages on (first/current) AE solve (first_/curr_)ae_avg_thresh: float Convergence criterion, in % diff, of profiles before (first/current) AE BVP solve triggers AE_basis : Dedalus Chebyshev 1D z-basis for AE solve AE_domain : Dedalus Domain Domain object for AE solve ae_fields : list Strings of variables whose profiles must converge on AE solves avg_profiles : OrderedDict Contains time-averaged profiles dist_ivp : Dedalus Distributor MPI distributor from convection DNS doing_ae : bool If True, profiles are actively being averaged for an AE solve elapsed_avg_time : float Total sim time that has passed over the averaging window extra_fields : list Fields to track the instantaneous vertical profile of from the DNS. finished_ae : bool If True, AE has converged within ivp_convergence_thresh flow : Dedalus GlobalFlowProperty Tracks instantaneous profiles in the DNS ivp_convergence_thresh: float When AE changes the current simulation's temp profile by this % or lower, consider solution converged. local_l2 : OrderedDict Contains info about change in profile from previous to current average. measured_profiles : OrderedDict Contains info about the current and previous instantaneous profile values measured_times : NumPy Array Sim time at measurement of current and previous profile values nz : int Chebyshev coefficient resolution nz_per_proc : int z data points in grid space on the local processor P, R : floats The values of 1/sqrt(Rayleigh*Prandtl) and 1/sqrt(Rayleigh/Prandtl) pe_switch : bool True if the avg Pe in the sim grid is > 1 solver_ivp : Dedalus InitialValueSolver Solver object from convection DNS z_slices : list z indices of the local processor """ def __init__(self, nz, solver_ivp, dist_ivp, ae_fields, extra_fields, P, R, first_ae_wait_time=30, ae_wait_time=20, first_ae_avg_time=20, ae_avg_time=10, first_ae_avg_thresh=1e-2, ae_avg_thresh=1e-3, ivp_convergence_thresh=1e-2): """ Initialize the object by grabbing solver states and making room for profile averages Arguments: ---------- All arguments have identical descriptions to their description in the class level docstring. """ self.ivp_convergence_thresh = ivp_convergence_thresh self.first_ae_wait_time = self.curr_ae_wait_time = first_ae_wait_time self.first_ae_avg_time = self.curr_ae_avg_time = first_ae_avg_time self.first_ae_avg_thresh = self.curr_ae_avg_thresh = first_ae_avg_thresh self.ae_wait_time = ae_wait_time self.ae_avg_time = ae_avg_time self.ae_avg_thresh = ae_avg_thresh self.nz = nz self.solver_ivp = solver_ivp self.dist_ivp = dist_ivp self.ae_fields = ae_fields self.extra_fields = extra_fields self.P, self.R = P, R self.doing_ae, self.finished_ae, self.pe_switch = False, False, False #Set up profiles and simulation tracking self.flow = GlobalFlowProperty(solver_ivp, cadence=1) self.z_slices = self.dist_ivp.grid_layout.slices(scales=1)[-1] self.nz_per_proc = self.dist_ivp.grid_layout.local_shape(scales=1)[-1] self.measured_times = np.zeros(2) self.elapsed_avg_time = 0 self.measured_profiles, self.avg_profiles, self.local_l2 = OrderedDict( ), OrderedDict(), OrderedDict() for k in ae_fields: self.flow.add_property('plane_avg({})'.format(k), name='{}'.format(k)) self.measured_profiles[k] = np.zeros((2, self.nz_per_proc)) self.avg_profiles[k] = np.zeros(self.nz_per_proc) self.local_l2[k] = np.zeros(self.nz_per_proc) for k in extra_fields: self.flow.add_property('plane_avg({})'.format(k), name='{}'.format(k)) self.flow.add_property('Pe', name='Pe') if self.dist_ivp.comm_cart.rank == 0: self.AE_basis = de.Chebyshev('z', self.nz, interval=[-1. / 2, 1. / 2], dealias=3. / 2) self.AE_domain = de.Domain([ self.AE_basis, ], grid_dtype=np.float64, comm=MPI.COMM_SELF) else: self.AE_basis = self.AE_domain = None def _broadcast_ae_solution(self, solver): """ Communicate AE solve info from process 0 to all processes """ base_keys = ['T1', 'Xi', 'T1_z'] ae_profiles = OrderedDict() for f in base_keys: ae_profiles[f] = np.zeros(self.nz) for f in ['Xi_mean', 'delta_T1']: ae_profiles[f] = np.zeros(1) if self.dist_ivp.comm_cart.rank == 0: for f in base_keys: state = solver.state[f] state.set_scales(1, keep_data=True) ae_profiles[f] = np.copy(state['g']) ae_profiles['Xi_mean'] = np.mean( solver.state['Xi'].integrate()['g']) ae_profiles['delta_T1'] = np.mean(solver.state['delta_T1']['g']) for f in ae_profiles.keys(): ae_profiles[f] = self.dist_ivp.comm_cart.bcast(ae_profiles[f], root=0) return ae_profiles def _check_convergence(self): """Check if each field in self.ae_fields is converged, return True if so.""" if (self.solver_ivp.sim_time - self.curr_ae_wait_time) > self.curr_ae_avg_time: maxs = list() for f in self.ae_fields: maxs.append(self._get_profile_max(self.local_l2[f])) logger.info( 'AE: Max abs L2 norm for convergence: {:.4e} / {:.4e}'.format( np.median(maxs), self.curr_ae_avg_thresh)) if np.median(maxs) < self.curr_ae_avg_thresh: return True else: return False def _communicate_profile(self, profile): """ Construct and return a global z-profile using local pieces. Arguments: ---------- profile : NumPy array contains the local piece of the profile """ loc, glob = [np.zeros(self.nz) for i in range(2)] if len(self.dist_ivp.mesh) == 0: loc[self.z_slices] = profile elif self.dist_ivp.comm_cart.rank < self.dist_ivp.mesh[-1]: loc[self.z_slices] = profile self.dist_ivp.comm_cart.Allreduce(loc, glob, op=MPI.SUM) return glob def _get_local_profile(self, key): """ Grab the specified profile from the DNS and return it as a 1D array. Arguments: ---------- prof_name: string The name of the profile to grab. """ this_field = self.flow.properties['{}'.format(key)]['g'] if len(this_field.shape) == 3: profile = this_field[0, 0, :] else: profile = this_field[0, :] return profile def _get_profile_max(self, profile): """ Return a profile's global maximum; utilize local pieces and communication. Arguments: ---------- profile : NumPy array contains the local piece of a profile """ loc, glob = [np.zeros(1) for i in range(2)] if len(self.dist_ivp.mesh) == 0: loc[0] = np.max(profile) elif self.dist_ivp.comm_cart.rank < self.dist_ivp.mesh[-1]: loc[0] = np.max(profile) self.dist_ivp.comm_cart.Allreduce(loc, glob, op=MPI.MAX) return glob[0] def _reset_profiles(self): """ Reset all local fields after doing a BVP """ for fd in self.ae_fields: self.avg_profiles[fd] *= 0 self.measured_profiles[fd] *= 0 self.local_l2[fd] *= 0 self.measured_times *= 0 self.measured_times[1] = self.solver_ivp.sim_time self.elapsed_avg_time = 0 def _set_AE_equations(self, problem): """ Set the horizontally-averaged boussinesq equations """ problem.add_equation("Xi = (P/tot_flux)") problem.add_equation("delta_T1 = left(T1) - right(T1)") problem.add_equation("dz(T1) - T1_z = 0") problem.add_equation(("P*dz(T1_z) = dz(Xi*enth_flux)")) problem.add_equation(("dz(p) - T1 = Xi*momentum_rhs_z")) problem.add_bc("left(T1_z) = 0") problem.add_bc("right(T1) = 0") problem.add_bc('right(p) = 0') def _update_avg_profiles(self): """ Update the averages of tracked z-profiles. """ first = False # times self.measured_times[0] = self.solver_ivp.sim_time this_dt = self.measured_times[0] - self.measured_times[1] if self.elapsed_avg_time == 0: first = True self.elapsed_avg_time += this_dt self.measured_times[1] = self.measured_times[0] # profiles for k in self.ae_fields: self.measured_profiles[k][0, :] = self._get_local_profile(k) if first: self.avg_profiles[k] *= 0 self.local_l2[k] *= 0 else: old_avg = self.avg_profiles[k] / (self.elapsed_avg_time - this_dt) self.avg_profiles[k] += (this_dt / 2) * np.sum( self.measured_profiles[k], axis=0) new_avg = self.avg_profiles[k] / self.elapsed_avg_time self.local_l2[k] = np.abs((new_avg - old_avg) / new_avg) self.measured_profiles[k][1, :] = self.measured_profiles[k][0, :] def _update_simulation_state(self, ae_profiles, avg_fields): """ Update T1 and T1_z with AE profiles """ u_scaling = ae_profiles['Xi_mean']**(1. / 3) thermo_scaling = u_scaling**(2) #Get instantaneous thermo profiles [ self.flow.properties[f].set_scales(1, keep_data=True) for f in ('T1', 'delta_T1') ] T1_prof = self.flow.properties['T1']['g'] old_delta_T1 = np.mean(self.flow.properties['delta_T1']['g']) new_delta_T1 = ae_profiles['delta_T1'] T1 = self.solver_ivp.state['T1'] T1_z = self.solver_ivp.state['T1_z'] #Adjust Temp T1.set_scales(1, keep_data=True) T1['g'] -= T1_prof T1.set_scales(1, keep_data=True) T1['g'] *= thermo_scaling T1.set_scales(1, keep_data=True) T1['g'] += ae_profiles['T1'][self.z_slices] T1.set_scales(1, keep_data=True) T1.differentiate('z', out=self.solver_ivp.state['T1_z']) #Adjust velocity vel_fields = ['u', 'w'] if len(T1['g'].shape) == 3: vel_fields.append('v') for k in vel_fields: self.solver_ivp.state[k].set_scales(1, keep_data=True) self.solver_ivp.state[k]['g'] *= u_scaling #See how much delta T over domain has changed. diff = np.mean(np.abs(1 - new_delta_T1 / old_delta_T1)) return diff 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
class FieldAverager: """ Does averaging for accelerated evolution. WIP. """ FIELDS = None OUT_DIR = 'averager' def __init__(self, solver_IVP, de_domain_IVP, root_dir, file_dir=None): """ Initialize the FieldAverager. Arguments: ---------- solver_IVP : Dedalus Solver object The solver from the IVP in which averages are being taken de_domain_IVP : DedalusDomain object The domain on which the IVP is being solved root_dir : string Root output directory file_dir : string, optional Output average files to root_dir/file_dir. If None, output to root_dir/OUT_DIR. """ self.solver_IVP = solver_IVP self.de_domain_IVP = de_domain_IVP self.rank = de_domain_IVP.domain.dist.comm_cart.rank if len(de_domain_IVP.domain.dist.mesh) == 0: self.nz_per_proc = int(de_domain_IVP.resolution[0] / de_domain_IVP.domain.dist.comm_cart.size) else: self.nz_per_proc = int(de_domain_IVP.resolution[0] / de_domain_IVP.domain.dist.mesh[-1]) self.flow = GlobalFlowProperty(solver_IVP, cadence=1) self.measured_profiles, self.avg_profiles, self.local_l2 = OrderedDict( ), OrderedDict(), OrderedDict() for k, fd in self.FIELDS.items(): self.flow.add_property('plane_avg({})'.format(fd), name='{}'.format(k)) self.measured_profiles[k] = np.zeros((2, self.nz_per_proc)) self.avg_profiles[k] = np.zeros(self.nz_per_proc) self.local_l2[k] = np.zeros(self.nz_per_proc) self.avg_times = np.zeros(2) self.elapsed_avg_time = 0 self.n_files_saved = 0 if file_dir is None: file_dir = self.OUT_DIR self.file_dir = '{:s}/{:s}/'.format(root_dir, file_dir) mpi_makedirs(self.file_dir) def get_local_profile(self, prof_name): """ Grabs one of the local flow tracker's profiles. Assumes no horizontal variation of profile. Arguments: ---------- prof_name: string The name of the profile to grab. """ this_field = self.flow.properties['{}'.format(prof_name)]['g'] if self.de_domain_IVP.dimensions == 3: profile = this_field[0, 0, :] else: profile = this_field[0, :] return profile def local_to_global_average(self, profile): """ Given the local piece of a dedalus z-profile, find the global z-profile. Arguments: ---------- profile : NumPy array contains the local piece of the profile """ loc, glob = [ np.zeros(self.de_domain_IVP.resolution[0]) for i in range(2) ] if len(self.de_domain_IVP.domain.dist.mesh) == 0: loc[self.nz_per_proc * self.rank:self.nz_per_proc * (self.rank + 1)] = profile elif self.rank < self.de_domain_IVP.domain.dist.mesh[-1]: loc[self.nz_per_proc * self.rank:self.nz_per_proc * (self.rank + 1)] = profile self.de_domain_IVP.domain.dist.comm_cart.Allreduce(loc, glob, op=MPI.SUM) return glob def find_global_max(self, profile): """ Given a local piece of a global profile, find the global maximum. Arguments: ---------- profile : NumPy array contains the local piece of a profile """ loc, glob = [np.zeros(1) for i in range(2)] if len(self.de_domain_IVP.domain.dist.mesh) == 0: loc[0] = np.max(profile) elif self.rank < self.de_domain_IVP.domain.dist.mesh[-1]: loc[0] = np.max(profile) self.de_domain_IVP.domain.dist.comm_cart.Allreduce(loc, glob, op=MPI.MAX) return glob[0] def update_avgs(self): """ Updates the averages of z-profiles. To be called every timestep. """ first = False #Times self.avg_times[0] = self.solver_IVP.sim_time this_dt = self.avg_times[0] - self.avg_times[1] if self.elapsed_avg_time == 0: first = True self.elapsed_avg_time += this_dt self.avg_times[1] = self.avg_times[0] #Profiles for k in self.FIELDS.keys(): self.measured_profiles[k][0, :] = self.get_local_profile(k) if first: self.avg_profiles[k] *= 0 self.local_l2[k] *= 0 else: old_avg = self.avg_profiles[k] / (self.elapsed_avg_time - this_dt) self.avg_profiles[k] += (this_dt / 2) * np.sum( self.measured_profiles[k], axis=0) new_avg = self.avg_profiles[k] / self.elapsed_avg_time self.local_l2[k] = np.abs((new_avg - old_avg) / new_avg) self.measured_profiles[k][1, :] = self.measured_profiles[k][0, :] def save_file(self): """ Saves profiles dict to file """ z_profile = self.local_to_global_average( self.de_domain_IVP.z.flatten()) profiles = OrderedDict() for k, item in self.avg_profiles.items(): profiles[k] = self.local_to_global_average(item / self.elapsed_avg_time) if self.rank == 0: file_name = self.file_dir + "profile_dict_file_{:04d}.h5".format( self.n_files_saved + 1) with h5py.File(file_name, 'w') as f: for k, item in profiles.items(): f[k] = item f['z'] = z_profile self.n_files_saved += 1 def reset_fields(self): """ Reset all local fields after doing a BVP """ for fd, info in self.FIELDS.items(): self.avg_profiles[fd] *= 0 self.measured_profiles[fd] *= 0 self.local_l2[fd] *= 0 self.avg_times *= 0 self.avg_times[1] = self.solver_IVP.sim_time self.elapsed_avg_time = 0
dt = DT cfl = CFL(solver, initial_dt=dt, cadence=5, max_dt=DT, min_dt=0.007, safety=0.5, threshold=0.10) cfl.add_velocities(('ux', 'uz')) cfl.add_frequency(DT) snapshots = solver.evaluator.add_file_handler(snapshots_dir, sim_dt=T_F / NUM_SNAPSHOTS) snapshots.add_system(solver.state) # Flow properties flow = GlobalFlowProperty(solver, cadence=10) flow.add_property('sqrt(ux**2 + ux**2)', name='u') # Main loop logger.info('Starting sim...') while solver.ok: cfl_dt = cfl.compute_dt() solver.step(cfl_dt) curr_iter = solver.iteration if curr_iter % int((T_F / DT) / NUM_SNAPSHOTS) == 0: logger.info('Reached time %f out of %f, timestep %f vs max %f', solver.sim_time, solver.stop_sim_time, cfl_dt, DT) logger.info('Max u = %e' % flow.max('u'))