An Introduction to Computational
Fluctuating Hydrodynamics
These notes are an introduction to fluctuating hydrodynamics (FHD) and the formulation of numerical schemes for the resulting stochastic partial differential equations (PDEs). Fluctuating hydrodynamics was originally introduced by Landau and Lifshitz [1] as a way to put thermal fluctuations into a continuum framework by including a stochastic forcing to each dissipative transport process (e.g., heat flux). While FHD has been useful in modeling transport and fluid dynamics at the mesoscopic scale, theoretical calculations have been feasible only with simplifying assumptions. As such there is great interest in numerical schemes for Computational Fluctuating Hydrodynamics (CFHD). There are a variety of algorithms (e.g., spectral, finite element, lattice Boltzmann) but in this introduction we focus on finite volume schemes. Accompanying these notes is a demonstration program in Python available on GitHub.
Stochastic Heat Equation
Our first example is the stochastic heat equation (SHE) for the transport of internal energy by thermal diffusion. This section presents a short derivation, for details see [2]. We start with the continuity equation for energy
(1) |
where is the (constant) mass density and is the specific internal energy. The heat flux, , can be separated into deterministic and stochastic contributions (denoted by and , respectively) and is written in Onsager form as
(2) |
where is the Onsager coefficient and is the thermodynamic force. Fluctuation-dissipation gives that the stochastic flux has zero mean and correlation
(3) |
where is the Boltzmann constant and denotes the Dirac delta function. Readers familiar with the Langevin equation for Brownian motion [3] will notice the similarities between that stochastic ordinary differential equation (ODE) and the above stochastic PDE.
From non-equilibrium thermodynamics [2, 4], the deterministic total rate of entropy change in a region is
(4) |
where is the thermodynamic flux. The first term is the internal entropy production and the second is the change due to heat flow at the boundary. Using the Gibbs equation, , and Eq. (1) gives
(5) |
The last equality uses the phenomenological Fourier law for heat flow, , where is the thermal conductivity. Applying Green’s first identity gives
(6) |
The entropy expressions (4) and (5) can be equated, and so the chain rule gives
(7) |
From this equality, , and Eq. (2), we can identity the thermodynamic force , the thermodynamics flux , and the Onsager coefficient to be [4, 5]
(8) |
respectively. The noise correlation is then given by111Formally, the temperature in the noise should be the deterministic value but in CFHD the instantaneous temperature is typically used.
(9) |
Finally, by writing , where is the specific heat at constant volume, the SHE is given as
(10) |
where is a Gaussian white noise vector field uncorrelated in space and time, that is,
(11) |
where is a Cartesian coordinate direction and is Kronecker delta.
For simplicity we focus on the one-dimensional case (e.g., thin rod) and write the SHE in compact form as
(12) | ||||
(13) |
where and are taken to be constants. In the one-dimensional case the noise variance is
(14) |
where is the cross-sectional area of the system.
CFHD Schemes for SHE
Equation (13) can be numerically integrated in time to produce sample trajectories for . We discretize space and time as and so temperature is . We use forward difference in time
(15) |
and centered differences in space
(16) |
Note that for the spatial index the integer values are at cell centers while half-integer values are at cell faces.
With this we have the forward Euler (FE) scheme
(17) |
For the temperature at a face we can use the arithmetic average, . Similarly, the standard Predictor-Corrector (PC) scheme is
(18) |
and
(19) |
where , computed in the predictor step, is used in the corrector step.222Random numbers used in predictor and corrector steps may be the same or different; see [6].
The discretized noise has variance
(20) |
where is the volume of a grid point cell. Numerically this noise is generated as
(21) |
where are independent, normal (Gaussian) distributed psuedo-random numbers.
CFHD example in Python
The Python program, StochasticHeat, illustrates the numerical methods described in the previous section for the stochastic heat equation (SHE). The program is listed in the appendix and the most up-to-date version can be downloaded as a Jupyter Notebook from github.com/AlejGarcia/IntroFHD. The simulation computes trajectories for the one-dimensional SHE and analyzes their statistical properties (e.g., variance of temperature). The reader is encouraged to download and run the program since results are obtained in about 5 minutes on a laptop.
At the top of the program there are various global options and parameters:
-
•
Periodic or Dirichlet boundary conditions
-
•
Thermodynamic equilibrium or constant temperature gradient
-
•
Initialize with or without temperature perturbations
-
•
Run simulation with or without thermal fluctuations
-
•
Use Forward Euler (FE) or Predictor-Corrector (PC) scheme
-
•
Number of grid cells,
-
•
Number of time steps,
Other parameters (e.g., system length, ) can also be changed from their default values within the program. Simulation results in this section are from runs using grid cells, running for either (equilibrium cases) or (temperature gradient case) time steps. Default values were used for the other parameters (see program listing in Appendix).
The program computes time-averaged quantities, for example the average temperature in a cell is
(22) |
where is the number of statistical samples; the system “relaxes” for the first time steps before sampling begins. At thermodynamic equilibrium the variance and static correlation of temperature fluctuations () are predicted by statistical mechanics to be [7]
(23) |
with the average temperature, , equal to the equilibrium temperature, . Figures 1 and 2 show that the simulation results for Dirichlet boundaries (i.e., fixed temperature at the boundaries) are in good agreement with theory, especially for the PC scheme.






Figure 3 shows that temperature correlations are slightly different for periodic boundary conditions. This is because, due to conservation of energy, , the correlation is shifted by an additive constant such that . This is a common feature in systems with conserved variables, such as density fluctuations in closed systems.
The assessment of numerical schemes in CFHD is best done by measuring the static structure factor for fluctuations. For the SHE, we define the unnormalized structure factor, , where
(24) |
is the discrete Fourier transform with wavenumber index , and is its complex conjugate transpose.333In CFHD the structure factor is often normalized to unity using the equilibrium variance. At thermodynamic equilibrium the discretized structure factor is
(25) |
Figure 4 shows that the FE scheme has significant error for large while the PC scheme is accurate for all . An analysis of discretization errors for various numerical schemes is presented in [6]; for FE the error in is while for PC it is .


Finally we consider a non-equilibrium scenario, specifically a linear temperature gradient imposed by Dirichlet boundary conditions. In this case there is a weak, long-range correlation of temperature fluctuations [8]:
(26) |
Figure 5 shows that the simulation results are in good agreement with this theoretical result.


Stochastic Species Diffusion
In fluctuating hydrodynamics there are several stochastic diffusion equations that are closely related to the stochastic heat equation. For example, the diffusion of species mass is described by a similar stochastic PDE with the main difference being the functional form of the stochastic flux. As above we start with
(27) |
where is the species mass fraction and the species flux is
(28) |
Assuming that the system is isothermal (i.e., no Soret effect), irreversible thermodynamics tells us that the thermodynamic force is [4, 5]
(29) |
where is the chemical potential. For ideal solutions
(30) |
where is the particle mass. Since the phenomenological law for species flow is Fick’s law, , then the Onsager coefficient is
(31) |
The noise correlation is
(32) |
so the stochastic species diffusion equation is
(33) |
where is the number density of the pure state (). This may also be written in terms of species number density, , as
(34) |
This stochastic PDE is also known as the Dean-Kawasaki equation. Recall that the stochastic heat equation is
(35) |
Note that the deterministic parts of the two equations above are functionally similar while the stochastic parts are distinctly different.
The stochastic species diffusion equation can also be derived by coarse-graining the discrete random walk model for diffusion. Additional examples of discrete models that have associated stochastic diffusion equations are: the excluded random walk model; the “train model” for the diffusion of momentum [9, 10]; and the “Knudsen chain” model for gas effusion [11].
A Menagerie of Fluctuating Hydrodynamic Equations
The general form of the fluctuating hydrodynamic equations for a set of state variables is
(36) |
where and are the hyperbolic and diffusive fluxes with being the noise amplitude. For example, for the stochastic species diffusion equation , , , and . In general, the fluctuation-dissipation theorem relates to and tells us that the stochastic term is independent of the hyperbolic term.
This brief introduction to CFHD has focused on stochastic diffusion equations due to the pedagogical benefit of their simplicity. We close with an outline of other fluctuating hydrodynamic equations including references describing finite volume schemes for solving them.
-
•
Stochastic Burger’s equation [12]:
(37) Note that for this resembles the stochastic species diffusion equation with the addition of a hyperbolic flux, .
- •
-
•
Reaction-diffusion systems [13]:
The reaction-diffusion system has species diffusing and undergoing reactions. By denoting the number density of species by , the equations of fluctuating reaction-diffusion can be written formally as the stochastic PDEs(40) where is the diffusion coefficient of species , is the propensity function indicating the rate of reaction , and is the stoichiometric coefficient of species in reaction .
-
•
Compressible Navier-Stokes equations (single species fluid) [14, 15]:
(41) (42) (43) where , , and are fluid velocity, pressure, and stress tensor; total specific energy is . Note that (43) reduces to the stochastic heat equation when . See references for explicit expression of the deterministic and stochastic fluxes.
- •
- •
-
•
Incompressible / low Mach hydrodynamic equations [20, 21, 22, 23]:
The multi-species methodology can be extended to model isothermal mixtures of miscible incompressible liquids. Incompressibility of the fluids leads to a constrained evolution, similar to the incompressible Navier-Stokes equations, given by(45) (46) (47) Here, is a perturbational pressure and is the pure component density for species . The resulting system retains in influence of fluctuations on mixing but is considerable more computationally efficient, particularly for liquids with a high sound speed.
-
•
Stochastic Poisson-Nernst-Planck equations [24, 25]:
The incompressible version of CFHD for multi-species fluids can model electrolyte solutions by including charged species (ions). The chemical potential becomes the electrochemical potential with the electrical mobility given by the Nernst–Einstein relation and the diffusive flux by the Nernst-Planck equation. For scales comparable to the Debye length, the electric field is obtained by solving the Poisson equation. At scales larger than the Debye length, the fluid is electro-neutral. Electro-neutrality can be imposed as a constraint by solving a modified elliptic equation to compute the electric potential. -
•
Multi-phase fluids [26, 27, 28, 29]:
By adding non-local gradient terms to the free energy, one can incorporate interfacial tension in CFHD model to treat multiphase systems. This can be done for both single component systems (e.g., liquid/vapor) and for multicomponent systems (e.g., oil/water). For multicomponent systems, the low Mach number version of the methodology has also be derived. These types of systems introduce additional higher order operators into the momentum equations and, for multicomponent systems, the species transport equations. See the references for specific forms of these equations.
Finally, github.com/AMReX-FHD is a repository of CFHD codes written using the AMReX framework.
References
- [1] L. D. Landau and E. M. Lifshitz. Fluid Mechanics, Course of Theoretical Physics, Vol. 6. Pergamon Press, 1959.
- [2] J. M. Ortiz de Zarate and J. V. Sengers. Hydrodynamic Fluctuations in Fluids and Fluid Mixtures. Elsevier Science, 2007.
- [3] Crispin W. Gardiner. Handbook of Stochastic Methods. Springer, Berlin, 1985.
- [4] S. R. DeGroot and P. Mazur. Non-Equilibrium Thermodynamics. North-Holland Publishing Company, Amsterdam, 1963.
- [5] A. L. Garcia. Essentials of Modern Thermodynamics. Amazon, 2022.
- [6] Aleksandar Donev, Eric Vanden-Eijnden, Alejandro Garcia, and John Bell. On the accuracy of finite-volume schemes for fluctuating hydrodynamics. Communications in Applied Mathematics and Computational Science, 5(2):149–197, 2010.
- [7] Raj Kumar Pathria. Statistical Mechanics. Elsevier, 2016.
- [8] Alejandro L. Garcia, M. Malek Mansour, George C. Lie, and Enrico Cementi. Numerical integration of the fluctuating hydrodynamic equations. Journal of Statistical Physics, 47:209–228, 1987.
- [9] Alejandro Garcia, F. Baras, and M. Malek Mansour. A simple model for nonequilibrium fluctuations in a fluid. American Journal of Physics, 64:1488, 1996.
- [10] Francis J. Alexander, Alejandro L. Garcia, and Daniel M. Tartakovsky. Algorithm refinement for stochastic partial differential equations: II. Correlated systems. Journal of Computational Physics, 207(2):769–787, 2005.
- [11] Alejandro L. Garcia. Thermal fluctuations in a Knudsen flow system. Physics Letters A, 119(8):379–382, 1987.
- [12] John B. Bell, Jasmine Foo, and Alejandro L. Garcia. Algorithm refinement for the stochastic Burgers’ equation. Journal of Computational Physics, 223(1):451–468, 2007.
- [13] Changho Kim, Andy Nonaka, John B. Bell, Alejandro L. Garcia, and Aleksandar Donev. Stochastic simulation of reaction-diffusion systems: A fluctuating-hydrodynamics approach. The Journal of Chemical Physics, 146:124110, 2017.
- [14] John B. Bell, Alejandro L. Garcia, and Sarah A. Williams. Numerical methods for the stochastic Landau-Lifshitz Navier-Stokes equations. Physical Review E, 76:016708, 2007.
- [15] Ishan Srivastava, Daniel R. Ladiges, Andy J. Nonaka, Alejandro L. Garcia, and John B. Bell. Staggered scheme for the compressible fluctuating hydrodynamics of multispecies fluid mixtures. Physical Review E, 107:015305, 2023.
- [16] Kaushik Balakrishnan, Alejandro L. Garcia, Aleksandar Donev, and John B. Bell. Fluctuating hydrodynamics of multispecies nonreactive mixtures. Physical Review E, 89:013017, 2014.
- [17] Amit Kumar Bhattacharjee, Kaushik Balakrishnan, Alejandro L. Garcia, John B. Bell, and Aleksandar Donev. Fluctuating hydrodynamics of multi-species reactive mixtures. The Journal of Chemical Physics, 142:224107, 2015.
- [18] Changho Kim, Andy Nonaka, John B. Bell, Alejandro L. Garcia, and Aleksandar Donev. Fluctuating hydrodynamics of reactive liquid mixtures. The Journal of Chemical Physics, 149:084113, 2018.
- [19] Daniel T. Gillespie. The chemical Langevin equation. The Journal of Chemical Physics, 113(1):297–306, 2000.
- [20] Aleksandar Donev, Andy Nonaka, Yifei Sun, Thomas Fai, Alejandro Garcia, and John Bell. Low Mach number fluctuating hydrodynamics of diffusively mixing fluids. Communications in Applied Mathematics and Computational Science, 9(1):47–105, 2014.
- [21] Aleksandar Donev, Andy Nonaka, Amit Kumar Bhattacharjee, Alejandro L. Garcia, and John B. Bell. Low Mach number fluctuating hydrodynamics of multispecies liquid mixtures. Physics of Fluids, 27(3), 2015.
- [22] Andrew Nonaka, Yifei Sun, John Bell, and Aleksandar Donev. Low Mach number fluctuating hydrodynamics of binary liquid mixtures. Communications in Applied Mathematics and Computational Science, 10(2):163–204, 2015.
- [23] Florencio Balboa, John B. Bell, Rafael Delgado-Buscalioni, Aleksandar Donev, Thomas G. Fai, Boyce E. Griffith, and Charles S. Peskin. Staggered schemes for fluctuating hydrodynamics. Multiscale Modeling & Simulation, 10(4):1369–1408, 2012.
- [24] Jean-Philippe Péraud, Andy Nonaka, Anuj Chaudhri, John B. Bell, Aleksandar Donev, and Alejandro L. Garcia. Low Mach number fluctuating hydrodynamics for electrolytes. Physical Review Fluids, 1:074103, 2016.
- [25] Aleksandar Donev, Andrew J. Nonaka, Changho Kim, Alejandro L. Garcia, and John B. Bell. Fluctuating hydrodynamics of electrolytes at electroneutral scales. Physical Review Fluids, 4:043701, 2019.
- [26] Barry Z. Shang, Nikolaos K. Voulgarakis, and Jhih-Wei Chu. Fluctuating hydrodynamics for multiscale simulation of inhomogeneous fluids: Mapping all-atom molecular dynamics to capillary waves. The Journal of Chemical Physics, 135:044111, 2011.
- [27] Anuj Chaudhri, John B. Bell, Alejandro L. Garcia, and Aleksandar Donev. Modeling multiphase flow using fluctuating hydrodynamics. Physical Review E, 90:033014, 2014.
- [28] Katherine Klymko, Andrew Nonaka, John B. Bell, Sean P. Carney, and Alejandro L. Garcia. Low Mach number fluctuating hydrodynamics model for ionic liquids. Physical Review Fluids, 5:093701, 2020.
- [29] Bryn Barker, John B. Bell, and Alejandro L. Garcia. Fluctuating hydrodynamics and the Rayleigh-Plateau instability. Proceedings of the National Academy of Sciences, 120(30):e2306088120, 2023.
APPENDIX: Python program StochHeat
# StochasticHeat - Program to calculate trajectories for the stochastic heat equation # Set up configuration options and special features import numpy as np # Use numerical python library import matplotlib.pyplot as plt # Use plotting python library # Display plots in notebook window get_ipython().run_line_magic(’matplotlib’, ’inline’) # In[ ]: #* Set option flags and key parameters for the simulation BC_FLAG = 0 # Boundary condition flag (0: Periodic; 1: Dirichlet) NONEQ_FLAG = 0 # Non-equilibrium flag (0: Thermodynamic equilibrium; 1: Temperature gradient) if( BC_FLAG == 0 and NONEQ_FLAG == 1 ): print(’ERROR: Periodic boundary conditions are only for thermodynamic equilibrium’) NONEQ_FLAG = 0 # Reset the flag to equilibrium PERTURB_FLAG = 1 # Start from perturbed initial condition (0: No; 1: Yes) STOCH_FLAG = 1 # Thermal fluctuations? (0: No, deterministic; 1: Yes, stochastic) SCHEME_FLAG = 1 # Numerical scheme (0: Forward Euler; 1: Predictor-corrector) Ncells = 32 # Number of cells (including boundary cells ’0’ and ’Ncells-1’ ) MegaSteps = 2 # Number of simulation timesteps in millions # Recommend at least 2 million steps for equilibrium systems, 20 million for non-equilibrium systems # In[ ]: #* Set physical parameters for the system (iron bar) kB = 1.38e-23 # Boltzmann constant (J/K) mAtom = 9.27e-26 # Mass of iron atom (kg) rho = 7870. # Mass density of iron (kg/m^3) c_V = 450. # Specific heat capacity of iron (J/(kg K)) ThCond = 70. # Thermal conductivity of iron (W/(m K)) Length = 1.0e-8 # System length (m) Area = (5.0e-9)**2 # System cross-sectional area (m^2) # In[ ]: #* Set numerical parameters (time step, grid spacing, etc.). if( BC_FLAG == 0 ): cellLo = 0; cellHi = Ncells-1; # For periodic BC, range of cells = { 0, 1, ..., Ncells-2 } faceLo = 0; faceHi = Ncells-1; # Face ii is left side of cell ii else: cellLo = 1; cellHi = Ncells-1; # For Dirichlet BC, range of cells = { 1, 2, ..., Ncells-2 } faceLo = 1; faceHi = Ncells-1; # Face ii is left side of cell ii dx = Length/(Ncells-1) # Grid size (m) dV = Area*dx # Volume of grid cell (m^3) xx = np.zeros(Ncells) for ii in range(Ncells): xx[ii] = ii * dx # Cell center positions (m) kappa = ThCond / (rho * c_V ) # Coefficient in deterministic heat equation # Coefficient in stochastic heat equation if( STOCH_FLAG == 1 ): alpha = np.sqrt( 2 * kB * kappa / (rho * c_V) ) else: alpha = 0. # Set alpha = 0 to turn off thermal fluctuations stabilityFactor = 0.1 # Numerical stability if stabilityFactor < 1. dt = stabilityFactor * dx**2 /( 2. * kappa ) # Timestep (s) # In[ ]: #* Set initial conditions for temperature Tref = 300. # Reference temperature (K) if( NONEQ_FLAG == 0 ): T_Left = Tref; T_Right = Tref else: Tdiff = 400. # Temperature difference across the system T_Left = Tref - Tdiff/2.; T_Right = Tref + Tdiff/2. # Standard deviation of temperature in a cell at the reference temperature Tref_SD = np.sqrt(kB*Tref**2 / (rho * c_V * dV)) # Set initial temperature and its deterministic steady-state value T = np.zeros(Ncells); T0 = np.zeros(Ncells) for ii in range(cellLo,cellHi): T0[ii] = T_Left + (T_Right-T_Left) * ii/(Ncells-1) # Linear profile T[ii] = T0[ii] if( PERTURB_FLAG == 1 ): T[ii] += Tref_SD*np.random.randn() # Add random perturbation if( BC_FLAG == 0 ): T0[cellHi] = T0[0] # Copy first cell into last cell for periodic BCs T[cellHi] = T[0] else: T0[0] = T_Left; T[0] = T_Left # Set values in first and last cells T0[-1] = T_Right; T[-1] = T_Right # In[ ]: #* Summarize system parameters and initial state print( ’System is iron bar with about ’, int(rho*Length*Area/mAtom), ’ atoms’ ) print( ’System length = ’,Length*1.0e9,’ (nm); volume = ’, (Length*Area)*1.0e27,’ (nm**3)’ ) print( ’Number of timesteps = ’, MegaSteps,’ million’ ) print( ’Time step = ’, dt*1.e15, ’ (fs)’ ) print( ’Number of cells = ’, Ncells ) if( BC_FLAG == 0 ): print(’** PERIODIC boundary conditions **’) else: print(’++ DIRICHLET boundary conditions ++’) if( NONEQ_FLAG == 0 ): print(’Equilibrium temperature = ’,Tref,’ Kelvin’) else: print(’Fixed temperatures (K) = ’,T_Left,’ left; ’,T_Right,’ right’) print( ’At T = ’,Tref,’K, standard deviation sqrt(< dT^2 >) = ’, Tref_SD,’K’ ) if( SCHEME_FLAG == 0 ): print(’-- Forward Euler Scheme --’) else: print(’== Predictor-Corrector Scheme ==’) # Plot temperature versus position plt.plot(xx, T,’g*’,xx, T0,’b--’,xx[0],T[0],’sk’,xx[-1],T[-1],’sk’) plt.xlabel(’Position (m)’); plt.ylabel(’Temperature (K)’) plt.title(’Initial state (stars), steady state (dashed), boundary cells (squares)’) plt.show() # In[ ]: #* Initialize sampling plus misc. coefficients and arrays Nsamp = 0 # Count number of statistical samples sumT = np.zeros(Ncells) # Running sum of T_i ; used to compute mean sumT2 = np.zeros(Ncells) # Running sum of (T_i)**2 ; used to compute variance sumTT = np.zeros(Ncells) # Running sum for correlation T_i * T_iCorr sumSk = np.zeros(Ncells) # Running sum for structure factor S(k) iCorr = np.int_(Ncells/4) # Grid point used for correlation # Coefficients used in the main loop calculations coeffDetFE = kappa * dt / dx**2 coeffStoFE = alpha * dt / dx coeffZnoise = 1. / np.sqrt( dt * dV ) # Arrays used in the main loop calculations Determ = np.zeros(Ncells); Stoch = np.zeros(Ncells) Znoise = np.zeros(Ncells); Tface = np.zeros(Ncells) PreT = np.copy(T) # Used by Predictor-Corrector scheme Spectrum = np.zeros(Ncells) # Used to compute structure factor S(k) # In[ ]: #* Loop over the desired number of time steps. NstepInner = 10 # Number of time steps (inner loop) NstepOuter = np.int_(MegaSteps*1000000/NstepInner) # Number of time steps (outer loop) NskipOuter = NstepOuter/10 # Number of outer steps to skip before sampling begins NdiagOuter = NstepOuter/20 # Number of outer steps between diagnostic outputs for iOuter in range(NstepOuter): # Outer loop # Print diagnostics if (iOuter % NdiagOuter) == 0 : print( ’Finished ’,np.int_(100*iOuter/NstepOuter),’ percent of the time steps’) for iInner in range(NstepInner): # Inner loop # Deterministic update for temperature for ii in range(cellLo,cellHi): Determ[ii] = coeffDetFE * ( T[ ii+1 ] + T[ ii-1 ] - 2*T[ ii ] ) if( BC_FLAG == 0 ): Determ[0] = coeffDetFE * ( T[ 1 ] + T[ cellHi-1 ] - 2*T[ 0 ] ) # Periodic BC # Generate random noise Z Znoise = coeffZnoise * np.random.normal(size=Ncells) if( BC_FLAG == 0 ): Znoise[-1] = Znoise[0] # Periodic BC # Tface[ i ] is average between T of cells i-1 and i; value on the left face of cell i for ii in range(cellLo,cellHi): Tface[ii] = 0.5 * (T[ ii-1 ] + T[ ii ]) if( BC_FLAG == 0 ): Tface[cellHi] = Tface[0] # Periodic BC else: Tface[cellHi] = 0.5 * (T[ cellHi-1 ] + T[ cellHi ]) # Dirichlet BC # Stochastic update for temperature for ii in range(cellLo,cellHi): Stoch[ii] = coeffStoFE * ( Tface[ii+1]*Znoise[ii+1] - Tface[ii]*Znoise[ii] ) if( SCHEME_FLAG == 0 ): # Forward Euler scheme for ii in range(cellLo,cellHi): T[ii] += Determ[ii] + Stoch[ii] # Total update for temperature else: # Predictor-Corrector scheme for ii in range(cellLo,cellHi): PreT[ii] = T[ii] + Determ[ii] + Stoch[ii] # Predictor step if( BC_FLAG == 0 ): PreT[cellHi] = PreT[0] # Periodic BC # Corrector step for ii in range(cellLo,cellHi): Determ[ii] = coeffDetFE * ( PreT[ ii+1 ] + PreT[ ii-1 ] - 2*PreT[ ii ] ) if( BC_FLAG == 0 ): Determ[0] = coeffDetFE * ( PreT[ 1 ] + PreT[ cellHi-1 ] - 2*PreT[ 0 ] ) # Periodic BC for ii in range(cellLo,cellHi): Tface[ii] = 0.5 * (PreT[ ii-1 ] + PreT[ ii ]) if( BC_FLAG == 0 ): Tface[cellHi] = Tface[0] # Periodic BC else: Tface[cellHi] = 0.5 * (PreT[ cellHi-1 ] + PreT[ cellHi ]) for ii in range(cellLo,cellHi): Stoch[ii] = coeffStoFE * ( Tface[ii+1]*Znoise[ii+1] - Tface[ii]*Znoise[ii] ) for ii in range(cellLo,cellHi): T[ii] = 0.5*( T[ii] + PreT[ii] + Determ[ii] + Stoch[ii] ) if( BC_FLAG == 0 ): T[cellHi] = T[0] # Periodic BC # End of Inner loop # Take statistical sample if( iOuter > NskipOuter ): Nsamp += 1 for ii in range(cellLo,cellHi): sumT[ii] += T[ii] # Running sum for temperature average sumT2[ii] += T[ii]**2 # Running sum for temperature variance sumTT[ii] += T[ii]*T[iCorr] # Running sum for temperature correlation if( NONEQ_FLAG == 0 ): # Take Fourier transform and record sampled spectrum in running sum Spectrum[cellLo:cellHi] = np.abs( np.fft.fft( T[cellLo:cellHi] ) )**2 for ii in range(cellLo,cellHi): sumSk[ii] += Spectrum[ii] # End of Outer loop # In[ ]: #* Calculate average, variance, and correlation aveT = np.zeros(Ncells) # Average < T_i > varT = np.zeros(Ncells) # Variance < (T_i - <T_i>)**2 > corrT = np.zeros(Ncells) # Correlation < T_i T_iCorr > for ii in range(cellLo,cellHi): aveT[ii] = sumT[ii] / Nsamp varT[ii] = sumT2[ii]/Nsamp - aveT[ii]**2 for ii in range(cellLo,cellHi): corrT[ii] = sumTT[ii]/Nsamp - aveT[ii]*aveT[iCorr] # In[ ]: #* Plot temperature versus x plt.plot(xx[cellLo:cellHi], T[cellLo:cellHi],’g*’, xx[cellLo:cellHi],aveT[cellLo:cellHi],’ro’,xx[cellLo:cellHi],T0[cellLo:cellHi],’b--’) plt.xlabel(’Position (m)’); plt.ylabel(’Temperature (K)’) plt.title(’Final state (stars), Average (circles), Deterministic (line)’) plt.show() # In[ ]: #* Plot varicance of temperature versus x; compare with theory varT_Th = np.zeros(Ncells) # Theoretical value varT_Th[cellLo:cellHi] = kB*aveT[cellLo:cellHi]**2 / (rho * c_V * dV) # Conservation of energy correction for periodic boundary case if( BC_FLAG == 0 ): varT_Th *= (1 - 1/(Ncells-1)) plt.plot(xx[cellLo:cellHi], varT[cellLo:cellHi],’ro’, xx[cellLo:cellHi],varT_Th[cellLo:cellHi],’b--’) plt.xlabel(’Position (m)’); plt.ylabel(’Variance < dT**2 >’) plt.title(’Average (circles), Equilibrium theory (dashed)’) plt.show() # In[ ]: #* Plot temperature cell correlation versus x varTheory = kB*aveT[iCorr]**2 / (rho * c_V * dV) # Temperature variance in cell iCorr if( BC_FLAG == 0 ): corrT_Th = - varTheory * 1/(Ncells-1) * np.ones(Ncells) # Conservation of energy correction corrT_Th[iCorr] = varTheory * (1 - 1/(Ncells-1)) # for periodic boundary case else: corrT_Th = np.zeros(Ncells) # Kronecker delta correlation corrT_Th[iCorr] = varTheory # for Dirichlet boundary case plt.plot(xx[cellLo:cellHi], corrT[cellLo:cellHi],’ro’, xx[cellLo:cellHi],corrT_Th[cellLo:cellHi],’b--’) plt.xlabel(’Position (m)’); plt.ylabel(’Correlation < dT(x) dT(x*) >’) plt.title(’Average (circles), Theory (dashed)’) plt.show() print(’Correlation for x* = ’, xx[iCorr],’ (m)’) # In[ ]: #* Plot temperature cell correlation versus x WITHOUT the equilibrium delta function corrTd = np.array(corrT) corrTd[iCorr] = np.nan # Delete data point at iCorr using NaN # Calculate theoretical values for < dT(x) dT(x’) > where x’ = xx[iCorr] if( NONEQ_FLAG == 0 ): corrTd_Th = np.array(corrT_Th) corrTd_Th[iCorr] = np.nan # Delete data point at iCorr using NaN else: corrTd_Th = np.zeros(Ncells) for ii in range(Ncells): # Non-equilibrium correlation; see J. Stat. Phys. 47 209 (1987) corrTd_Th[ii] = kB*(T_Right-T_Left)**2 / (rho * c_V * Area * Length**3) if( ii < iCorr ): corrTd_Th[ii] *= xx[ii]*(Length - xx[iCorr]) else: corrTd_Th[ii] *= xx[iCorr]*(Length - xx[ii]) plt.plot(xx[cellLo:cellHi], corrTd[cellLo:cellHi],’ro’, xx[cellLo:cellHi],corrTd_Th[cellLo:cellHi],’b--’) plt.xlabel(’Position (m)’); plt.ylabel(’< dT(x) dT(x*) > [delta-function removed]’) plt.title(’Average (circles); Theory (dashed)’) plt.show() # In[ ]: #* Compute the measured structure factor and compare with linear theory if( NONEQ_FLAG == 0 ): # Only compute S(k) for equilibrium NN = len(range(cellLo,cellHi)) Sk = np.zeros(NN) # Power spectrum S(k), AKA the structure factor Sk[0:NN] = sumSk[cellLo:cellHi] / Nsamp # Average S(k) Nyq = np.int_(np.floor(NN/2)) # Nyquist frequency is kSpect[NNNy+1] ki = np.arange(1,Nyq) # Wavenumber index, skipping the zero index Sk_eq = varTheory*NN * np.ones(Nyq+1) # Equilibrium structure factor, which is constant # Plot structure factor, skipping the k=0 wavenumber index plt.plot( ki, Sk[1:Nyq],’ro’, ki, Sk_eq[1:Nyq],’b--’,) plt.xlabel(’Wavenumber index’); plt.ylabel(’Structure factor S(k)’) plt.title(’Average (circles); Theory (dashed)’) plt.show()