Binder

1. Basic usage

DustPy is using on the simframe framework for running scientific simulations. For a detailed description of the usage of simframe please have a look at the Simframe Documentation.

This notebook demonstrates how to run the most simple DustPy model, i.e., the model that is run by default, how to plot data, and how to resume simulations from dump files.

The Simulation Frame

To set up a model we have to import the Simulation class from the DustPy package.

[1]:
from dustpy import Simulation

We can now create an instance of this class.

[2]:
sim = Simulation()

At this stage sim is an empty simulation object that controls our simulation.

[3]:
sim
[3]:
DustPy
------
    dust         : Group (Dust quantities)
    gas          : Group (Gas quantities)
    grid         : Group (Grid quantities)
    star         : Group (Stellar quantities)
  -----
    t            : NoneType
  -----
    Integrator   : not specified
    Writer       : not specified

All the fields are initialized with None. All attributes can be easiliy addressed via e.g.

[4]:
sim.gas
[4]:
Group (Gas quantities)
----------------------
    boundary     : Group (Boundary conditions)
    S            : Group (Source terms)
    v            : Group (Velocities)
  -----
    alpha        : NoneType
    cs           : NoneType
    eta          : NoneType
    Fi           : NoneType
    gamma        : NoneType
    Hp           : NoneType
    mfp          : NoneType
    mu           : NoneType
    n            : NoneType
    nu           : NoneType
    P            : NoneType
    rho          : NoneType
    Sigma        : NoneType
    SigmaFloor   : NoneType
    T            : NoneType
  -----

Initializing

We can now initialize the sim object with Simulation.initialize(). DustPy will then fill all the fields with default values.

[5]:
sim.initialize()
As you can see, the sim object has now values assigned to its fields.
All quantities are in cgs units.
[6]:
sim.gas
[6]:
Group (Gas quantities)
----------------------
    boundary     : Group (Boundary conditions)
    S            : Group (Source terms)
    v            : Group (Velocities)
  -----
    alpha        : Field (Turbulent alpha parameter)
    cs           : Field (Sound speed [cm/s])
    eta          : Field (Pressure gradient parameter)
    Fi           : Field (Gas flux interfaces [g/cm/s])
    gamma        : Field (Adiabatic index)
    Hp           : Field (Pressure scale height [cm])
    mfp          : Field (Midplane mean free path [cm])
    mu           : Field (Mean molecular weight [g])
    n            : Field (Miplane number density [1/cm³])
    nu           : Field (Kinematic viscosity [cm²/s])
    P            : Field (Midplane pressure [g/cm/s²])
    rho          : Field (Miplane mass density [g/cm³])
    Sigma        : Field (Surface density [g/cm²])
    SigmaFloor   : Field (Floor value of surface density [g/cm²])
    T            : Field (Temperature [K])
  -----

You can also display the full table of contents of the sim object.

[7]:
sim.toc
DustPy
    - dust: Group (Dust quantities)
        - a: Field (Particle size [cm])
        - backreaction: Group (Backreaction coefficients)
            - A: Field (Pull factor)
            - B: Field (Push factor)
        - boundary: Group (Boundary conditions)
            - inner: Constant gradient
            - outer: Value
        - coagulation: Group (Coagulation quantities)
            - A: Field (Fragment normalization factors), constant
            - eps: Field (Remnant mass distribution), constant
            - lf_ind: Field (Index of largest fragment), constant
            - phi: Field (Fragment distribution), constant
            - rm_ind: Field (Smaller index of remnant), constant
            - stick: Field (Sticking matrix), constant
            - stick_ind: Field (Non-zero elements of sticking matrix), constant
        - D: Field (Diffusivity [cm²/s])
        - delta: Group (Mixing parameters)
            - rad: Field (Radial mixing parameter)
            - turb: Field (Turbulent mixing parameter)
            - vert: Field (Vertical mixing parameter)
        - eps: Field (Dust-to-gas ratio)
        - Fi: Group (Fluxes)
            - adv: Field (Advective flux [g/cm/s])
            - diff: Field (Diffusive flux [g/cm/s])
            - tot: Field (Total flux [g/cm/s])
        - fill: Field (Filling factor)
        - H: Field (Scale heights [cm])
        - kernel: Field (Collision kernel [cm²/s])
        - p: Group (Probabilities)
            - frag: Field (Fragmentation probability)
            - stick: Field (Sticking probability)
        - rho: Field (Midplane mass density per mass bin [g/cm³])
        - rhos: Field (Solid state density [g/cm³])
        - S: Group (Sources)
            - coag: Field (Coagulation sources [g/cm²/s])
            - ext: Field (External sources [g/cm²/s])
            - hyd: Field (Hydrodynamic sources [g/cm²/s])
            - tot: Field (Tot sources [g/cm²/s])
        - Sigma: Field (Surface density per mass bin [g/cm²])
        - SigmaFloor: Field (Floor value of surface density [g/cm²])
        - St: Field (Stokes number)
        - v: Group (Velocities)
            - driftmax: Field (Maximum drift velocity [cm/s])
            - frag: Field (Fragmentation velocity [cm/s])
            - rad: Field (Radial velocity [cm/s])
            - rel: Group (Relative velocities)
                - azi: Field (Relative azimuthal velocity [cm/s])
                - brown: Field (Relative Brownian motion velocity [cm/s])
                - rad: Field (Relative radial velocity [cm/s])
                - tot: Field (Total relative velocity [cm/s])
                - turb: Field (Relative turbulent velocity [cm/s])
                - vert: Field (Relative vertical settling velocity [cm/s])
    - gas: Group (Gas quantities)
        - alpha: Field (Turbulent alpha parameter)
        - boundary: Group (Boundary conditions)
            - inner: Constant gradient
            - outer: Value
        - cs: Field (Sound speed [cm/s])
        - eta: Field (Pressure gradient parameter)
        - Fi: Field (Gas flux interfaces [g/cm/s])
        - gamma: Field (Adiabatic index)
        - Hp: Field (Pressure scale height [cm])
        - mfp: Field (Midplane mean free path [cm])
        - mu: Field (Mean molecular weight [g])
        - n: Field (Miplane number density [1/cm³])
        - nu: Field (Kinematic viscosity [cm²/s])
        - P: Field (Midplane pressure [g/cm/s²])
        - rho: Field (Miplane mass density [g/cm³])
        - S: Group (Source terms)
            - ext: Field (External sources [g/cm²/s])
            - hyd: Field (Hydrodynamic sources [g/cm²/s])
            - tot: Field (Total sources [g/cm²/s])
        - Sigma: Field (Surface density [g/cm²])
        - SigmaFloor: Field (Floor value of surface density [g/cm²])
        - T: Field (Temperature [K])
        - v: Group (Velocities)
            - rad: Field (Radial velocity [cm/s])
            - visc: Field (Viscous accretion velocity [cm/s])
    - grid: Group (Grid quantities)
        - A: Field (Radial grid annulus area [cm²]), constant
        - m: Field (Mass grid [g]), constant
        - Nm: Field (# of mass bins), constant
        - Nr: Field (# of radial grid cells), constant
        - OmegaK: Field (Keplerian frequency [1/s])
        - r: Field (Radial grid cell centers [cm]), constant
        - ri: Field (Radial grid cell interfaces [cm]), constant
    - star: Group (Stellar quantities)
        - L: Field (Luminosity [erg/s])
        - M: Field (Mass [g])
        - R: Field (Radius [cm])
        - T: Field (Effective temperature [K])
    - t: IntVar (Time [s]), Integration variable

Running a Simulation

The simulation is now ready to go. This will take a few minutes. The default simulation is running for 100,000 years.

[8]:
sim.run()

DustPy v1.0.5

Documentation: https://stammler.github.io/dustpy/
PyPI:          https://pypi.org/project/dustpy/
GitHub:        https://github.com/stammler/dustpy/

Please cite Stammler & Birnstiel (2022).

Checking for mass conservation...

    - Sticking:
        max. rel. error:  2.75e-14
        for particle collision
            m[114] =  1.93e+04 g    with
            m[116] =  3.73e+04 g
    - Full fragmentation:
        max. rel. error:  5.55e-16
        for particle collision
            m[55] =  7.20e-05 g    with
            m[55] =  7.20e-05 g
    - Erosion:
        max. rel. error:  1.78e-15
        for particle collision
            m[110] =  5.18e+03 g    with
            m[118] =  7.20e+04 g

Creating data directory 'data'.
Writing file data/data0000.hdf5
Writing dump file data/frame.dmp
Writing file data/data0001.hdf5
Writing dump file data/frame.dmp
Writing file data/data0002.hdf5
Writing dump file data/frame.dmp
Writing file data/data0003.hdf5
Writing dump file data/frame.dmp
Writing file data/data0004.hdf5
Writing dump file data/frame.dmp
Writing file data/data0005.hdf5
Writing dump file data/frame.dmp
Writing file data/data0006.hdf5
Writing dump file data/frame.dmp
Writing file data/data0007.hdf5
Writing dump file data/frame.dmp
Writing file data/data0008.hdf5
Writing dump file data/frame.dmp
Writing file data/data0009.hdf5
Writing dump file data/frame.dmp
Writing file data/data0010.hdf5
Writing dump file data/frame.dmp
Writing file data/data0011.hdf5
Writing dump file data/frame.dmp
Writing file data/data0012.hdf5
Writing dump file data/frame.dmp
Writing file data/data0013.hdf5
Writing dump file data/frame.dmp
Writing file data/data0014.hdf5
Writing dump file data/frame.dmp
Writing file data/data0015.hdf5
Writing dump file data/frame.dmp
Writing file data/data0016.hdf5
Writing dump file data/frame.dmp
Writing file data/data0017.hdf5
Writing dump file data/frame.dmp
Writing file data/data0018.hdf5
Writing dump file data/frame.dmp
Writing file data/data0019.hdf5
Writing dump file data/frame.dmp
Writing file data/data0020.hdf5
Writing dump file data/frame.dmp
Writing file data/data0021.hdf5
Writing dump file data/frame.dmp
Execution time: 0:25:21

By default DustPy has written output files into the data/ directory.

Plotting

DustPy is coming with a simple plotting script that can be used to check the status of a simulation.

[9]:
from dustpy import plot

The plotting script does either take the simulation object as argument or a data directory.

If the argument is a simulation object the script is only plotting the current state.

[10]:
plot.panel(sim)
_images/1_basics_22_0.png

The blue and the green lines in the top left panel are analytical estimates for the fragmentation and drift barrier taken from Birnstiel et al. (2012).

If you pass the data directory as argument, you also have access to the time evolution.
Furthermore, some plots can be addressed by specifying the time it, radial ir, or mass im index.
[11]:
plot.panel("data", it=10, ir=10, im=5)
_images/1_basics_24_0.png

The top middle and bottom left panels show the dust density distribution along the gray dashed lines in the top left panel.

It’s furthermore possible to use an interactive plotting script.

[12]:
plot.ipanel("data")
_images/1_basics_27_0.png

Code Units

The dust density distribution plotted here is given by

\(\Sigma_\mathrm{d} \left( r \right) = \int\limits_0^\infty \sigma \left(r, m \right) \mathrm{d} \log m\).

In this way the distribution is independent of the mass grid.

The code units DustPy uses are \(\Sigma_{\mathrm{d},\,i} \left( r \right) \equiv \Sigma_\mathrm{d} \left(r, m_i \right)\) with

\(\Sigma_\mathrm{d} \left( r \right) = \sum\limits_i \Sigma_{\mathrm{d},\,i} \left( r \right)\),

meaning the numerical sum over the mass dimension is the dust surface density.

[13]:
sim.dust.Sigma.sum(-1)
[13]:
[1.10558450e+01 1.02993178e+01 9.59195549e+00 8.93896250e+00
 8.32864174e+00 7.75848590e+00 7.22598369e+00 6.72858592e+00
 6.26421498e+00 5.83081686e+00 5.42620155e+00 5.04864366e+00
 4.69645621e+00 4.36777353e+00 4.06118666e+00 3.77532356e+00
 3.50860884e+00 3.25989679e+00 3.02807142e+00 2.81181881e+00
 2.61021238e+00 2.42234104e+00 2.24712484e+00 2.08381550e+00
 1.93166208e+00 1.78979299e+00 1.65760302e+00 1.53446451e+00
 1.41968942e+00 1.31278633e+00 1.21322188e+00 1.12046727e+00
 1.03412179e+00 9.53725668e-01 8.78889287e-01 8.09295487e-01
 7.44492670e-01 6.84225840e-01 6.28197359e-01 5.76099776e-01
 5.27718147e-01 4.82764881e-01 4.41043793e-01 4.02342272e-01
 3.66453458e-01 3.33227994e-01 3.02446805e-01 2.73990240e-01
 2.47688216e-01 2.23422420e-01 2.01049388e-01 1.80460725e-01
 1.61534454e-01 1.44173668e-01 1.28272126e-01 1.13746515e-01
 1.00500117e-01 8.84600676e-02 7.75352688e-02 6.76579619e-02
 5.87666240e-02 5.07930091e-02 4.36881105e-02 3.74080407e-02
 3.18793025e-02 2.70181020e-02 2.27460221e-02 1.90019344e-02
 1.57365503e-02 1.29008272e-02 1.04285647e-02 8.21052034e-03
 6.08307277e-03 3.92338320e-03 1.93621450e-03 6.99128440e-04
 1.85480259e-04 3.65581248e-05 5.35346523e-06 5.68845727e-07
 4.38908175e-08 2.70624483e-09 1.34691188e-10 5.43173421e-12
 1.76930567e-13 4.59995512e-15 9.32088975e-17 1.41486135e-18
 1.51708088e-20 1.06317740e-22 4.45397680e-25 1.14219956e-27
 1.04642867e-28 9.00834622e-29 7.84588136e-29 6.83347698e-29
 5.95170965e-29 5.18372240e-29 4.51483347e-29 3.93225557e-29]

To convert this into \(\sigma\) we have to divide the code density distribution by \(B = \frac{\Delta m}{m}\), where \(\Delta m\) is the width of the mass bin centered on \(m\).

Since the mass grid is strictly logarithmic the following relation holds

\(m_{i+1} = A \cdot m_i\).

The grid constant \(A\) can be easily calculated.

[14]:
import numpy as np
A = np.mean(sim.grid.m[1:]/sim.grid.m[:-1])
A
[14]:
1.3894954943731377

We further assume that the mass bin center is exactly in the middle between the mass bin interfaces

\(m_i = \frac{1}{2} \left( m_{i-\frac{1}{2}} + m_{i+\frac{1}{2}} \right)\).

Solving for the interfaces yields

\(\begin{split} m_{i-\frac{1}{2}} &= \frac{2}{A+1} m_i \\ m_{i+\frac{1}{2}} &= \frac{2}{A+1} A\cdot m_i. \end{split}\)

We therefore have

\(\Delta m_i = m_{i+\frac{1}{2}} - m_{i-\frac{1}{2}} = 2\frac{A-1}{A+1}m_i\)

and

\(B = \frac{\Delta m_i}{m_i} = 2\frac{A-1}{A+1}\).

[15]:
B = 2 * (A-1) / (A+1)
[16]:
sim.dust.Sigma / B
[16]:
[[1.35750251e-01 1.11450049e-01 1.16073436e-01 ... 1.52526930e-23
  2.11935481e-23 2.94483396e-23]
 [1.29655487e-01 1.06116482e-01 1.10245276e-01 ... 1.32845402e-23
  1.84588088e-23 2.56484316e-23]
 [1.24179647e-01 1.01289473e-01 1.04943384e-01 ... 1.15703508e-23
  1.60769503e-23 2.23388501e-23]
 ...
 [4.45718657e-46 6.19324066e-46 8.60547999e-46 ... 2.30858850e-29
  3.20777332e-29 4.45718657e-29]
 [3.88204722e-46 5.39408712e-46 7.49505975e-46 ... 2.01069653e-29
  2.79385376e-29 3.88204722e-29]
 [3.38112178e-46 4.69805348e-46 6.52792414e-46 ... 1.75124347e-29
  2.43334490e-29 3.38112178e-29]]

Reading data files

If you want to read data files you can use the read/writer module provided by simframe, that is used to write the data.

[17]:
from dustpy import hdf5writer

wrtr = hdf5writer()

Make sure that the correct data directory is assigned to the writer.

[18]:
wrtr
[18]:
Writer (HDF5 file format using h5py)
------------------------------------
    Data directory : data
    File names     : data/data0000.hdf5
    Overwrite      : False
    Dumping        : True
    Options        : {'com': 'lzf', 'comopts': None}
    Verbosity      : 1

You can now read a single data file with

[19]:
data0003 = wrtr.read.output(3)

This function returns a namespace and the data can simply be accessed in the same way as for the Simulation object.

[20]:
data0003.gas.Sigma
[20]:
array([1.11442758e+003, 1.03950016e+003, 9.69534899e+002, 9.03996575e+002,
       8.42652573e+002, 7.85281679e+002, 7.31666653e+002, 6.81591015e+002,
       6.34839857e+002, 5.91202935e+002, 5.50478001e+002, 5.12473131e+002,
       4.77007790e+002, 4.43912953e+002, 4.13030706e+002, 3.84213637e+002,
       3.57324174e+002, 3.32233942e+002, 3.08823154e+002, 2.86980035e+002,
       2.66600291e+002, 2.47586611e+002, 2.29848199e+002, 2.13300346e+002,
       1.97864019e+002, 1.83465484e+002, 1.70035958e+002, 1.57511273e+002,
       1.45831575e+002, 1.34941033e+002, 1.24787571e+002, 1.15322622e+002,
       1.06500891e+002, 9.82801375e+001, 9.06209726e+001, 8.34866689e+001,
       7.68429821e+001, 7.06579849e+001, 6.49019115e+001, 5.95470123e+001,
       5.45674173e+001, 4.99390088e+001, 4.56393015e+001, 4.16473303e+001,
       3.79435448e+001, 3.45097100e+001, 3.13288134e+001, 2.83849764e+001,
       2.56633720e+001, 2.31501460e+001, 2.08323432e+001, 1.86978378e+001,
       1.67352666e+001, 1.49339667e+001, 1.32839164e+001, 1.17756796e+001,
       1.04003528e+001, 9.14951632e+000, 8.01518836e+000, 6.98978248e+000,
       6.06606887e+000, 5.23713926e+000, 4.49637584e+000, 3.83742439e+000,
       3.25417178e+000, 2.74072812e+000, 2.29141364e+000, 1.90075039e+000,
       1.56345878e+000, 1.27445866e+000, 1.02887484e+000, 8.22046251e-001,
       6.49538378e-001, 5.07157848e-001, 3.90968245e-001, 2.97305957e-001,
       2.22794764e-001, 1.64357939e-001, 1.19226636e-001, 8.49435663e-002,
       5.93611962e-002, 4.06340475e-002, 2.72050959e-002, 1.77866714e-002,
       1.13366732e-002, 7.03125139e-003, 4.23534403e-003, 2.47255688e-003,
       1.39583152e-003, 7.60163304e-004, 3.98337858e-004, 2.00295348e-004,
       9.63569541e-005, 4.42094325e-005, 1.92794721e-005, 7.96245913e-006,
       3.10228830e-006, 1.13550420e-006, 3.87735143e-007, 1.00000000e-100])

You can also read the full data directory with

[21]:
data = wrtr.read.all()

The data has now an additional dimension for time.

[22]:
data.gas.Sigma.shape
[22]:
(22, 100)

Data files can be quite large and reading the entire data set can take some time. Is is also possible to only read a single field from the data files instead of the entire data set.

[23]:
SigmaGas = wrtr.read.sequence("gas.Sigma")
[24]:
SigmaGas.shape
[24]:
(22, 100)

It is also possible to exclude certain fields from being written into the data files to save memory by setting their save attribute to False.

[25]:
sim.dust.kernel.save = False

Reading Dump Files

The data files are only containing the pure data, but no information about the operations DustPy has to perform, like customized functions. Therefore, it’s not possible to directly restart a simulation from data files.

simframe is saving by default the most recent dump file, from which a simulation can be restarted.

Attention: Malware can be injected with dump files, which are pickled objects. Only read dump files that you have created yourself or from sources that you trust! Dump files have to be read with the same version of DustPy as they were written. Otherwise, it is not guaranteed to work.

[26]:
from dustpy import readdump
[27]:
sim_restart = readdump("data/frame.dmp")

This is now a simulation frame that should be identical to our previous object.

[28]:
sim.gas.Sigma == sim_restart.gas.Sigma
[28]:
[ True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True]

We can now, for example, add more snapshots and restart the simulation. Here we just want to extend the run by one year.

[29]:
from dustpy import constants as c

sim_restart.t.snapshots = np.concatenate((sim_restart.t.snapshots, [100001.*c.year]))

The current time is

[30]:
sim_restart.t / c.year
[30]:
100000.0

We can now restart the simulation for another year.

[31]:
sim_restart.run()

DustPy v1.0.5

Documentation: https://stammler.github.io/dustpy/
PyPI:          https://pypi.org/project/dustpy/
GitHub:        https://github.com/stammler/dustpy/

Please cite Stammler & Birnstiel (2022).

Checking for mass conservation...

    - Sticking:
        max. rel. error:  2.75e-14
        for particle collision
            m[114] =  1.93e+04 g    with
            m[116] =  3.73e+04 g
    - Full fragmentation:
        max. rel. error:  5.55e-16
        for particle collision
            m[55] =  7.20e-05 g    with
            m[55] =  7.20e-05 g
    - Erosion:
        max. rel. error:  1.78e-15
        for particle collision
            m[110] =  5.18e+03 g    with
            m[118] =  7.20e+04 g

Writing file data/data0022.hdf5
Writing dump file data/frame.dmp
Execution time: 0:00:01

Another file was written and the current time is now

[32]:
sim_restart.t / c.year
[32]:
100001.0