def computeSource_linear_forcing(self, dvScale=None, computeRHS=True, **ignored): """ Source function to be added to spectralLES solver instance inclusion of keyword dvScale necessary to actually compute the source term Takes one keyword argument: dvScale: (optional) user-provided linear scaling computeRHS: (default=True) add source term to RHS accumulator """ # Update the HIT forcing function self.W_hat[:] = self.U_hat*self.hit_filter if dvScale is None: irfft3(self.comm, self.W_hat[0], self.W[0]) irfft3(self.comm, self.W_hat[1], self.W[1]) irfft3(self.comm, self.W_hat[2], self.W[2]) dvScale = self.epsilon*self.Nx/self.comm.allreduce( psum(self.U*self.W)) if computeRHS: self.dU += dvScale*self.W_hat return dvScale
def computeSource_HIT_random_forcing(self, rseed=None, **ignored): """ Source function to be added to spectralLES solver instance Takes one keyword argument: rseed: (positive integer, optional), changes the random seed of the pseudo-RNG inside the np.random module """ mpi_reduce = self.comm.allreduce # -------------------------------------------------------------- # generate a random, band-pass-filtered velocity field self.compute_random_HIT_spectrum(-5. / 3., self.nk[-1], rseed) self.W_hat *= self.forcing_filter # -------------------------------------------------------------- # scale to constant energy injection rate irfft3(self.comm, self.W_hat[0], self.W[0]) irfft3(self.comm, self.W_hat[1], self.W[1]) irfft3(self.comm, self.W_hat[2], self.W[2]) dvScale = self.epsilon * self.Nx / mpi_reduce(psum(self.W * self.U)) self.W_hat *= dvScale # -------------------------------------------------------------- # add forcing term to the RHS accumulator self.dU += self.W_hat return dvScale
def initialize_HIT_random_spectrum(self, Einit=None, kexp=-5./6., kpeak=None, rseed=None): """ Generates a random, incompressible, velocity initial condition with a scaled Gamie-Ostriker isotropic turbulence spectrum """ if Einit is None: Einit = 0.72*(self.epsilon*self.L.max())**(2./3.) # the constant of 0.72 is empirically-based if kpeak is None: a = self.L/self.L.min() # domain size aspect ratios kpeak = np.max((self.nx//8)/a) # this gives kmax/4 self.compute_random_HIT_spectrum(kexp, kpeak, rseed) # Solenoidally-project, U_hat*(1-ki*kj/k^2) self.W_hat -= np.sum(self.W_hat*self.K_Ksq, axis=0)*self.K # - Third, scale to Einit irfft3(self.comm, self.W_hat[0], self.U[0]) irfft3(self.comm, self.W_hat[1], self.U[1]) irfft3(self.comm, self.W_hat[2], self.U[2]) Urms = sqrt(2.0*Einit) self.U *= Urms*sqrt(self.Nx/self.comm.allreduce(psum(self.U**2))) # transform to finish initial conditions rfft3(self.comm, self.U[0], self.U_hat[0]) rfft3(self.comm, self.U[1], self.U_hat[1]) rfft3(self.comm, self.U[2], self.U_hat[2]) return
def computeSource_linear_forcing(self, dvScale=None, computeRHS=True, **ignored): """ Source function to be added to spectralLES solver instance inclusion of keyword dvScale necessary to actually compute the source term Takes one keyword argument: dvScale: (optional) user-provided linear scaling computeRHS: (default=True) add source term to RHS accumulator """ mpi_reduce = self.comm.allreduce # -------------------------------------------------------------- # Band-pass filter the solution velocity field self.W_hat[:] = self.U_hat*self.forcing_filter # -------------------------------------------------------------- # scale to constant energy injection rate if dvScale is None: irfft3(self.comm, self.W_hat[0], self.W[0]) irfft3(self.comm, self.W_hat[1], self.W[1]) irfft3(self.comm, self.W_hat[2], self.W[2]) dvScale = self.epsilon*self.Nx/mpi_reduce(psum(self.U*self.W)) # adding 0.0 to turn off the forcing function! self.W_hat *= dvScale # -------------------------------------------------------------- # add forcing term to the RHS accumulator if computeRHS: self.dU += self.W_hat return dvScale
def compute_dvScale_constant_injection(self): """ empty docstring! """ mpi_reduce = self.comm.allreduce # Band-pass filter the solution velocity field self.W_hat[:] = self.U_hat * self.forcing_filter # scale to constant energy injection rate irfft3(self.comm, self.W_hat[0], self.W[0]) irfft3(self.comm, self.W_hat[1], self.W[1]) irfft3(self.comm, self.W_hat[2], self.W[2]) dvScale = self.epsilon * self.Nx / mpi_reduce(psum(self.U * self.W)) return dvScale
def computeSource_HIT_random_forcing(self, rseed=None, **ignored): """ Source function to be added to spectralLES solver instance Takes one keyword argument: rseed: (positive integer, optional), changes the random seed of the pseudo-RNG inside the np.random module """ self.compute_random_HIT_spectrum(-5./3., self.nk[-1], rseed) self.W_hat *= self.hit_filter irfft3(self.comm, self.W_hat[0], self.W[0]) irfft3(self.comm, self.W_hat[1], self.W[1]) irfft3(self.comm, self.W_hat[2], self.W[2]) dvScale = self.epsilon/self.comm.allreduce(psum(self.W*self.U)) self.W_hat *= dvScale self.dU += self.W_hat return dvScale
def ales244_static_les_test(pp=None, sp=None): """ Arguments: ---------- pp: (optional) program parameters, parsed by argument parser provided by this file sp: (optional) solver parameters, parsed by spectralLES.parser """ if comm.rank == 0: print("\n----------------------------------------------------------") print("MPI-parallel Python spectralLES simulation of problem \n" "`Homogeneous Isotropic Turbulence' started with " "{} tasks at {}.".format(comm.size, timeofday())) print("----------------------------------------------------------") # if function called without passing in parsed arguments, then parse # the arguments from the command line if pp is None: pp = hit_parser.parse_known_args()[0] if sp is None: sp = spectralLES.parser.parse_known_args()[0] if comm.rank == 0: print('\nProblem Parameters:\n-------------------') for k, v in vars(pp).items(): print(k, v) print('\nSpectralLES Parameters:\n-----------------------') for k, v in vars(sp).items(): print(k, v) print("\n----------------------------------------------------------\n") assert len(set(pp.N)) == 1, ('Error, this beta-release HIT program ' 'requires equal mesh dimensions') N = pp.N[0] assert len(set(pp.L)) == 1, ('Error, this beta-release HIT program ' 'requires equal domain dimensions') L = pp.L[0] if N % comm.size > 0: if comm.rank == 0: print('Error: job started with improper number of MPI tasks for ' 'the size of the data specified!') MPI.Finalize() sys.exit(1) # ------------------------------------------------------------------------- # Configure the solver, writer, and analyzer # -- construct solver instance from sp's attribute dictionary solver = ales244_solver(comm, **vars(sp)) U_hat = solver.U_hat U = solver.U omega = solver.omega K = solver.K # -- configure solver instance to solve the NSE with the vorticity # formulation of the advective term, linear forcing, and # the ales244 SGS model solver.computeAD = solver.computeAD_vorticity_form Sources = [ solver.computeSource_linear_forcing, solver.computeSource_ales244_SGS ] H_244 = np.loadtxt('h_ij.dat', usecols=(1, 2, 3, 4, 5, 6), unpack=True) kwargs = {'H_244': H_244, 'dvScale': None} # -- form HIT initial conditions from either user-defined values or # physics-based relationships using epsilon and L Urms = 1.2 * (pp.epsilon * L)**(1. / 3.) # empirical coefficient Einit = getattr(pp, 'Einit', None) or Urms**2 # == 2*KE_equilibrium kexp = getattr(pp, 'kexp', None) or -1. / 3. # -> E(k) ~ k^(-2./3.) kpeak = getattr(pp, 'kpeak', None) or N // 4 # ~ kmax/2 # -- currently using a fixed random seed of comm.rank for testing solver.initialize_HIT_random_spectrum(Einit, kexp, kpeak, rseed=comm.rank) # -- configure the writer and analyzer from both pp and sp attributes writer = mpiWriter(comm, odir=pp.odir, N=N) analyzer = mpiAnalyzer(comm, odir=pp.adir, pid=pp.pid, L=L, N=N, config='hit', method='spectral') Ek_fmt = "\widehat{{{0}}}^*\widehat{{{0}}}".format # ------------------------------------------------------------------------- # Setup the various time and IO counters tauK = sqrt(pp.nu / pp.epsilon) # Kolmogorov time-scale taul = 0.2 * L * sqrt(3) / Urms # 0.2 is empirical coefficient c = pp.cfl * sqrt(2 * Einit) / Urms dt = solver.new_dt_constant_nu(c) # use as estimate if pp.tlimit == np.Inf: # put a very large but finite limit on the run pp.tlimit = 262 * taul # such as (256+6)*tau, for spinup and 128 samples dt_rst = getattr(pp, 'dt_rst', None) or 2 * taul dt_spec = getattr(pp, 'dt_spec', None) or max(0.1 * taul, tauK, 10 * dt) dt_drv = getattr(pp, 'dt_drv', None) or max(tauK, 10 * dt) t_sim = t_rst = t_spec = t_drv = 0.0 tstep = irst = ispec = 0 # ------------------------------------------------------------------------- # Run the simulation while t_sim < pp.tlimit + 1.e-8: # -- Update the dynamic dt based on CFL constraint dt = solver.new_dt_constant_nu(pp.cfl) t_test = t_sim + 0.5 * dt # -- output log messages every step if needed/wanted KE = 0.5 * comm.allreduce(psum(np.square(U))) / solver.Nx if comm.rank == 0: print("cycle = %7d time = %15.8e dt = %15.8e KE = %15.8e" % (tstep, t_sim, dt, KE)) # - output snapshots and data analysis products if t_test >= t_spec: analyzer.spectral_density(U_hat, '%3.3d_u' % ispec, 'velocity PSD\t%s' % Ek_fmt('u_i')) irfft3(comm, 1j * (K[0] * U_hat[1] - K[1] * U_hat[0]), omega[2]) irfft3(comm, 1j * (K[2] * U_hat[0] - K[0] * U_hat[2]), omega[1]) irfft3(comm, 1j * (K[1] * U_hat[2] - K[2] * U_hat[1]), omega[0]) analyzer.spectral_density(omega, '%3.3d_omga' % ispec, 'vorticity PSD\t%s' % Ek_fmt('\omega_i')) t_spec += dt_spec ispec += 1 if t_test >= t_rst: writer.write_scalar('Velocity1_%3.3d.rst' % irst, U[0], np.float64) writer.write_scalar('Velocity2_%3.3d.rst' % irst, U[1], np.float64) writer.write_scalar('Velocity3_%3.3d.rst' % irst, U[2], np.float64) t_rst += dt_rst irst += 1 # -- Update the forcing pattern if t_test >= t_drv: # call solver.computeSource_linear_forcing to compute dvScale only kwargs['dvScale'] = Sources[0](computeRHS=False) t_drv += dt_drv if comm.rank == 0: print("------ updated linear forcing pattern ------") # -- integrate the solution forward in time solver.RK4_integrate(dt, *Sources, **kwargs) t_sim += dt tstep += 1 sys.stdout.flush() # forces Python 3 to flush print statements # ------------------------------------------------------------------------- # Finalize the simulation irfft3(comm, 1j * (K[0] * U_hat[1] - K[1] * U_hat[0]), omega[2]) irfft3(comm, 1j * (K[2] * U_hat[0] - K[0] * U_hat[2]), omega[1]) irfft3(comm, 1j * (K[1] * U_hat[2] - K[2] * U_hat[1]), omega[0]) analyzer.spectral_density(U_hat, '%3.3d_u' % ispec, 'velocity PSD\t%s' % Ek_fmt('u_i')) analyzer.spectral_density(omega, '%3.3d_omga' % ispec, 'vorticity PSD\t%s' % Ek_fmt('\omega_i')) writer.write_scalar('Velocity1_%3.3d.rst' % irst, U[0], np.float64) writer.write_scalar('Velocity2_%3.3d.rst' % irst, U[1], np.float64) writer.write_scalar('Velocity3_%3.3d.rst' % irst, U[2], np.float64) return
def ABC_static_test(pp=None, sp=None): """ Arguments: ---------- pp: (optional) program parameters, parsed by argument parser provided by this file sp: (optional) solver parameters, parsed by spectralLES.parser """ if comm.rank == 0: print("\n----------------------------------------------------------") print("MPI-parallel Python spectralLES simulation of problem \n" "`Homogeneous Isotropic Turbulence' started with " "{} tasks at {}.".format(comm.size, timeofday())) print("----------------------------------------------------------") # ------------------------------------------------------------------ # Get the problem and solver parameters and assert compliance if pp is None: pp = hit_parser.parse_known_args()[0] if sp is None: sp = spectralLES.parser.parse_known_args()[0] if comm.rank == 0: print('\nProblem Parameters:\n-------------------') for k, v in vars(pp).items(): print(k, v) print('\nSpectralLES Parameters:\n-----------------------') for k, v in vars(sp).items(): print(k, v) print("\n----------------------------------------------------------\n") assert len(set(pp.N)) == 1, ('Error, this beta-release HIT program ' 'requires equal mesh dimensions') N = pp.N[0] assert len(set(pp.L)) == 1, ('Error, this beta-release HIT program ' 'requires equal domain dimensions') L = pp.L[0] if N % comm.size > 0: if comm.rank == 0: print('Error: job started with improper number of MPI tasks' ' for the size of the data specified!') MPI.Finalize() sys.exit(1) # ------------------------------------------------------------------ # Configure the LES solver solver = staticGeneralizedEddyViscosityLES( Smagorinsky=True, comm=comm, **vars(sp)) solver.computeAD = solver.computeAD_vorticity_form Sources = [solver.computeSource_linear_forcing, solver.computeSource_Smagorinsky_SGS, # solver.computeSource_4termGEV_SGS, ] # C1 = np.array([-6.39e-02]) C3 = np.array([-3.75e-02, 6.2487e-02, 6.9867e-03, 0.0]) C4 = np.array([-3.15e-02, -5.25e-02, 2.7e-02, 2.7e-02]) kwargs = dict(C1=-6.39e-02, C=C3*solver.D_les**2, dvScale=None) U_hat = solver.U_hat U = solver.U Kmod = np.floor(np.sqrt(solver.Ksq)).astype(int) # ------------------------------------------------------------------ # form HIT initial conditions from either user-defined values or # physics-based relationships Urms = 1.083*(pp.epsilon*L)**(1./3.) # empirical coefficient Einit= getattr(pp, 'Einit', None) or Urms**2 # == 2*KE_equilibrium kexp = getattr(pp, 'kexp', None) or -1./3. # -> E(k) ~ k^(-2./3.) kpeak= getattr(pp, 'kpeak', None) or N//4 # ~ kmax/2 # currently using a fixed random seed for testing solver.initialize_HIT_random_spectrum(Einit, kexp, kpeak, rseed=comm.rank) # ------------------------------------------------------------------ # Configure a spatial field writer writer = mpiWriter(comm, odir=pp.odir, N=N) Ek_fmt = "\widehat{{{0}}}^*\widehat{{{0}}}".format # ------------------------------------------------------------------------- # Setup the various time and IO counters tauK = sqrt(pp.nu/pp.epsilon) # Kolmogorov time-scale taul = 0.11*sqrt(3)*L/Urms # 0.11 is empirical coefficient if pp.tlimit == np.Inf: pp.tlimit = 200*taul dt_rst = getattr(pp, 'dt_rst', None) or taul dt_spec= getattr(pp, 'dt_spec', None) or 0.2*taul dt_drv = getattr(pp, 'dt_drv', None) or 0.25*tauK t_sim = t_rst = t_spec = t_drv = 0.0 tstep = irst = ispec = 0 tseries = [] if comm.rank == 0: print('\ntau_ell = %.6e\ntau_K = %.6e\n' % (taul, tauK)) # ------------------------------------------------------------------------- # Run the simulation if comm.rank == 0: t1 = time.time() while t_sim < pp.tlimit+1.e-8: # -- Update the dynamic dt based on CFL constraint dt = solver.new_dt_constant_nu(pp.cfl) t_test = t_sim + 0.5*dt # -- output/store a log every step if needed/wanted KE = 0.5*comm.allreduce(psum(np.square(U)))/solver.Nx tseries.append([tstep, t_sim, KE]) # -- output KE and enstrophy spectra if t_test >= t_spec: # -- output message log to screen on spectrum output only if comm.rank == 0: print("cycle = %7d time = %15.8e dt = %15.8e KE = %15.8e" % (tstep, t_sim, dt, KE)) # -- output kinetic energy spectrum to file spect3d = np.sum(np.real(U_hat*np.conj(U_hat)), axis=0) spect3d[..., 0] *= 0.5 spect1d = shell_average(comm, spect3d, Kmod) if comm.rank == 0: fname = '%s/%s-%3.3d_KE.spectra' % (pp.adir, pp.pid, ispec) fh = open(fname, 'w') metadata = Ek_fmt('u_i') fh.write('%s\n' % metadata) spect1d.tofile(fh, sep='\n', format='% .8e') fh.close() t_spec += dt_spec ispec += 1 # -- output physical-space solution fields for restarting and analysis if t_test >= t_rst: writer.write_scalar('%s-Velocity1_%3.3d.rst' % (pp.pid, irst), U[0], np.float64) writer.write_scalar('%s-Velocity2_%3.3d.rst' % (pp.pid, irst), U[1], np.float64) writer.write_scalar('%s-Velocity3_%3.3d.rst' % (pp.pid, irst), U[2], np.float64) t_rst += dt_rst irst += 1 # -- Update the forcing mean scaling if t_test >= t_drv: # call solver.computeSource_linear_forcing to compute dvScale only kwargs['dvScale'] = Sources[0](computeRHS=False) t_drv += dt_drv # -- integrate the solution forward in time solver.RK4_integrate(dt, *Sources, **kwargs) t_sim += dt tstep += 1 sys.stdout.flush() # forces Python 3 to flush print statements # ------------------------------------------------------------------------- # Finalize the simulation if comm.rank == 0: t2 = time.time() print('Program took %12.7f s' % ((t2-t1))) KE = 0.5*comm.allreduce(psum(np.square(U)))/solver.Nx tseries.append([tstep, t_sim, KE]) if comm.rank == 0: fname = '%s/%s-%3.3d_KE_tseries.txt' % (pp.adir, pp.pid, ispec) header = 'Kinetic Energy Timeseries,\n# columns: tstep, time, KE' np.savetxt(fname, tseries, fmt='%10.5e', header=header) print("cycle = %7d time = %15.8e dt = %15.8e KE = %15.8e" % (tstep, t_sim, dt, KE)) print("\n----------------------------------------------------------") print("MPI-parallel Python spectralLES simulation finished at {}." .format(timeofday())) print("----------------------------------------------------------") # -- output kinetic energy spectrum to file spect3d = np.sum(np.real(U_hat*np.conj(U_hat)), axis=0) spect3d[..., 0] *= 0.5 spect1d = shell_average(comm, spect3d, Kmod) if comm.rank == 0: fh = open('%s/%s-%3.3d_KE.spectra' % (pp.adir, pp.pid, ispec), 'w') metadata = Ek_fmt('u_i') fh.write('%s\n' % metadata) spect1d.tofile(fh, sep='\n', format='% .8e') fh.close() # -- output physical-space solution fields for restarting and analysis writer.write_scalar('%s-Velocity1_%3.3d.rst' % (pp.pid, irst), U[0], np.float64) writer.write_scalar('%s-Velocity2_%3.3d.rst' % (pp.pid, irst), U[1], np.float64) writer.write_scalar('%s-Velocity3_%3.3d.rst' % (pp.pid, irst), U[2], np.float64) return
def staticSmag_HIT_demo(pp=None, sp=None): """ Arguments: ---------- pp: (optional) program parameters, parsed by argument parser provided by this file sp: (optional) solver parameters, parsed by staticSmagorinskyLES.parser """ if comm.rank == 0: print("\n----------------------------------------------------------") print("MPI-parallel Python spectralLES simulation of problem \n" "`Homogeneous Isotropic Turbulence' started with " "{} tasks at {}.".format(comm.size, timeofday())) print("----------------------------------------------------------") # if function called without passing in parsed arguments, then parse # the arguments from the command line if pp is None: pp = hit_parser.parse_known_args()[0] if sp is None: sp = staticSmagorinskyLES.parser.parse_known_args()[0] if comm.rank == 0: print('\nProblem Parameters:\n-------------------') for k, v in vars(pp).items(): print(k, v) print('\nSpectralLES Parameters:\n-----------------------') for k, v in vars(sp).items(): print(k, v) print("\n----------------------------------------------------------\n") assert len(set(pp.N)) == 1, ('Error, this beta-release HIT program ' 'requires equal mesh dimensions') N = pp.N[0] assert len(set(pp.L)) == 1, ('Error, this beta-release HIT program ' 'requires equal domain dimensions') L = pp.L[0] if N % comm.size > 0: if comm.rank == 0: print('Error: job started with improper number of MPI tasks for ' 'the size of the data specified!') MPI.Finalize() sys.exit(1) # ------------------------------------------------------------------ # Configure the LES solver solver = staticSmagorinskyLES(comm=comm, **vars(sp)) solver.computeAD = solver.computeAD_vorticity_form Sources = [ solver.computeSource_linear_forcing, solver.computeSource_Smagorinsky_SGS, ] Ck = 1.6 Cs = sqrt((pi**-2) * ((3 * Ck)**-1.5)) # == 0.098... # Cs = 0.22 kwargs = { 'dvScale': None, 'Cs': Cs, } U_hat = solver.U_hat U = solver.U Kmod = np.floor(np.sqrt(solver.Ksq)).astype(int) # ------------------------------------------------------------------ # form HIT initial conditions from either user-defined values or # physics-based relationships Urms = 1.083 * (pp.epsilon * L)**(1. / 3.) # empirical coefficient Einit = getattr(pp, 'Einit', None) or Urms**2 # == 2*KE_equilibrium kexp = getattr(pp, 'kexp', None) or -1. / 3. # -> E(k) ~ k^(-2./3.) kpeak = getattr(pp, 'kpeak', None) or N // 4 # ~ kmax/2 # -- currently using a fixed random seed of comm.rank for testing solver.initialize_HIT_random_spectrum(Einit, kexp, kpeak, rseed=comm.rank) # ------------------------------------------------------------------ # Configure a spatial field writer # writer = mpiWriter(comm, odir=pp.odir, N=N) # MAKE ODIR, CHECKING IF IT IS A VALID PATH. if comm.rank == 0: try: os.makedirs(pp.odir) except OSError as e: if not os.path.isdir(pp.odir): raise e else: status = e finally: if os.path.isdir(pp.odir): status = 0 else: status = None status = comm.bcast(status) if status != 0: MPI.Finalize() sys.exit(999) Ek_fmt = "\\widehat{{{0}}}^*\\widehat{{{0}}}".format # ------------------------------------------------------------------------- # Setup the various time and IO counters tauK = sqrt(pp.nu / pp.epsilon) # Kolmogorov time-scale taul = 0.11 * sqrt(3) * L / Urms # 0.11 is empirical coefficient if pp.tlimit == np.Inf: pp.tlimit = 200 * taul dt_rst = getattr(pp, 'dt_rst', None) or taul dt_spec = getattr(pp, 'dt_spec', None) or 0.2 * taul dt_drv = getattr(pp, 'dt_drv', None) or 0.25 * tauK t_sim = t_rst = t_spec = t_drv = 0.0 tstep = irst = ispec = 0 tseries = [] if comm.rank == 0: print('\ntau_ell = %.6e\ntau_K = %.6e\n' % (taul, tauK)) # ------------------------------------------------------------------------- # Run the simulation while t_sim < pp.tlimit + 1.e-8: # -- Update the dynamic dt based on CFL constraint dt = solver.new_dt_constant_nu(pp.cfl) t_test = t_sim + 0.5 * dt # -- output/store a log every step if needed/wanted KE = 0.5 * comm.allreduce(psum(np.square(U))) / solver.Nx tseries.append([tstep, t_sim, KE]) # -- output KE and enstrophy spectra if t_test >= t_spec: # -- output message log to screen on spectrum output only if comm.rank == 0: print("cycle = %7d time = %15.8e dt = %15.8e KE = %15.8e" % (tstep, t_sim, dt, KE)) # -- output kinetic energy spectrum to file spect3d = np.sum(np.real(U_hat * np.conj(U_hat)), axis=0) spect3d[..., 0] *= 0.5 spect1d = shell_average(comm, spect3d, Kmod) if comm.rank == 0: fname = '%s/%s-%3.3d_KE.spectra' % (pp.odir, pp.pid, ispec) fh = open(fname, 'w') metadata = Ek_fmt('u_i') fh.write('%s\n' % metadata) spect1d.tofile(fh, sep='\n', format='% .8e') fh.close() t_spec += dt_spec ispec += 1 # # -- output physical-space solution fields for restarting and analysis # if t_test >= t_rst: # writer.write_scalar('%s-Velocity1_%3.3d.rst' % # (pp.pid, irst), U[0], np.float64) # writer.write_scalar('%s-Velocity2_%3.3d.rst' % # (pp.pid, irst), U[1], np.float64) # writer.write_scalar('%s-Velocity3_%3.3d.rst' % # (pp.pid, irst), U[2], np.float64) # t_rst += dt_rst # irst += 1 # -- Update the forcing mean scaling if t_test >= t_drv: # call solver.computeSource_linear_forcing to compute dvScale only kwargs['dvScale'] = Sources[0](computeRHS=False) t_drv += dt_drv # -- integrate the solution forward in time solver.RK4_integrate(dt, *Sources, **kwargs) t_sim += dt tstep += 1 sys.stdout.flush() # forces Python 3 to flush print statements # ------------------------------------------------------------------------- # Finalize the simulation KE = 0.5 * comm.allreduce(psum(np.square(U))) / solver.Nx tseries.append([tstep, t_sim, KE]) if comm.rank == 0: fname = '%s/%s-%3.3d_KE_tseries.txt' % (pp.adir, pp.pid, ispec) header = 'Kinetic Energy Timeseries,\n# columns: tstep, time, KE' np.savetxt(fname, tseries, fmt='%10.5e', header=header) print("cycle = %7d time = %15.8e dt = %15.8e KE = %15.8e" % (tstep, t_sim, dt, KE)) print("\n----------------------------------------------------------") print("MPI-parallel Python spectralLES simulation finished at {}.". format(timeofday())) print("----------------------------------------------------------") # -- output kinetic energy spectrum to file spect3d = np.sum(np.real(U_hat * np.conj(U_hat)), axis=0) spect3d[..., 0] *= 0.5 spect1d = shell_average(comm, spect3d, Kmod) if comm.rank == 0: fh = open('%s/%s-%3.3d_KE.spectra' % (pp.adir, pp.pid, ispec), 'w') metadata = Ek_fmt('u_i') fh.write('%s\n' % metadata) spect1d.tofile(fh, sep='\n', format='% .8e') fh.close() # # -- output physical-space solution fields for restarting and analysis # writer.write_scalar('%s-Velocity1_%3.3d.rst' % # (pp.pid, irst), U[0], np.float64) # writer.write_scalar('%s-Velocity2_%3.3d.rst' % # (pp.pid, irst), U[1], np.float64) # writer.write_scalar('%s-Velocity3_%3.3d.rst' % # (pp.pid, irst), U[2], np.float64) return