Your first simulation
PyLogGrid is designed with ease-of-use in mind, so that users spend less time coding and more time thinking about the physics.
Unlike other big frameworks, users don’t provide a “simulation file” composed only of parameters, but instead provide a python script, which offers much more flexibility.
What we’re simulating
Log-lattices operate in an exponentially decimated grid in Fourier space. By design, the current version is therefore limited to periodic boundary/initial conditions, although there are ongoing efforts to alleviate this constraint.
Due to their sparsity, Log-lattices can simulate very wide range of scales, spanning lots of orders of magnitude, down to the Kolmogorov scale. This enables us to perform geophysical simulations without parameterizing the dissipation.
Log-lattices are intrinsically limited to equations that write (in Fourier space) as linear terms and convolutions (i.e. it can’t handle third order nonlinear terms). Fortunately, that already covers a very vast array of equations. Pyloggrid is a general-purpose academic equation solver, not an industry CFD solver like OpenFOAM.
In the example below, we simulate 3D Navier-Stokes with given initial conditions and forcing.
To get started, let’s look at the examples in the Simulations folder of the source (available on Github ). Copy it and navigate inside:
cd Simulations
In this folder, you will find a simple script called NS3D.py which simulates the 3D Navier-Stokes equations.
Let’s look at what’s inside.
Simulation functions
At the top of the NS3D.py file, you will find several functions that define the equation being simulated:
get_forcingreturns the forcing field for a given simulation grid. This function is optional, but it’s good practice to define the forcing field separately from the equation itself.equation_nonlinearreturns the nonlinear part of the equation. If your equation is \(\partial_t u=A(u)−b\cdot u\), then this corresponds to \(A(u)\).equation_linearreturns the linear factor of the equation \(−b\).initial_conditionsdefines the initial conditions for the simulation.update_gridsizespecifies when to update the size of the simulation grid.
For an in-depth explanation on how to use those, read pyloggrid.LogGrid.Framework.Solver.
Parameters
After defining the simulation functions, we set the parameters for the simulation. First, we define the physical parameters of the equation:
fields = ["ux", "uy", "uz"] # the scalar fields to simulate
D = 3 # the dimension of the space
l_params = {"plastic": False, "a": 1, "b": 2} # the grid spacing's parameters
Re_F = 1e3
simu_params = {"Re_F": Re_F} # scalar parameter of the simulation, passed to the equation
Next, we define the numerical parameters:
rtol = 1e-4 # relative tolerance of the solver
n_threads_convolution = 4 # parallelization
N_points = 6 # initial size of the grid
Finally, we define the output parameters:
save_path = f"results/save_3D_f0{f0:.2e}_ReF{Re_F:.2e}" # save path
end_simulation = {"t": 2000, "ode_step": 1e10} # when to end the simulation
save_one_in = 50 # save one step every N real steps
Running the simulation
The simulation can be run as-is, but since we set end_simulation = {"t": 2000, "ode_step": 1e10}} it will run for a very long time [1].
If you want to end the simulation after a specified amount of time, you can change this parameter to:
end_simulation = {"elapsed_time": 120}
This will automatically end the simulation after 120 seconds (i.e., 2 minutes).
To run the simulation, simply execute the NS3D.py script:
python NS3D.py
Once the simulation is complete, you can analyze the output data.
Tips
By default,
numpyis multithreaded. If you want to disable this feature (typically because you want control over how many CPUs your simulation take, and because numpy operations take up a negligible time in the simulation), simply import it asfrom Libs.singlethread_numpy import npat the top of your simulation file (before it’s imported by any other library).If your simulation includes a forcing term, it’s a good practice to put it in a separate function, as done in the example. That way, you can reuse it in the initialization or in the treatment.
There are a number of functions in
pyloggrid.Libs.datascito help manipulating arrays, in particular complex random arrays, which is very useful for creating peusorandom forcings consistent across grid size changes.