Page MenuHomec4science

rough_surfaces.rst
No OneTemporary

File Metadata

Created
Fri, Apr 19, 09:24

rough_surfaces.rst

Random rough surfaces
=====================
The generation of stochatsticly rough surfaces is controlled in Tamaas by two abstract classes: :cpp:class:`tamaas::SurfaceGenerator` and :cpp:class:`tamaas::Filter`. The former provides access lets the user set the surface sizes and random seed, while the latter encodes the information of the spectrum of the surface. Two surface generation methods are provided:
- :cpp:class:`tamaas::SurfaceGeneratorFilter` implements a Fourier filtering algorithm (see `Hu & Tonder <https://doi.org/10.1016/0890-6955(92)90064-N>`_),
- :cpp:class:`tamaas::SurfaceGeneratorRandomPhase` implements a random phase filter.
Both of these rely on a :cpp:class:`tamaas::Filter` object to provided the filtering information (usually power spectrum density coefficients). Tamaas provides two such classes and allows for Python subclassing:
- :cpp:class:`tamaas::Isopowerlaw` provides a roll-off powerlaw,
- :cpp:class:`tamaas::RegularizedPowerlaw` provides a powerlaw with a regularized rolloff.
Tamaas also provided routines for surface statistics.
Generating a surface
--------------------
Let us now see how to generate a surface. Frist create a filter object and set the surface sizes::
import tamaas as tm
# Create spectrum object
spectrum = tm.Isopowerlaw2D()
# Set spectrum parameters
spectrum.q0 = 4
spectrum.q1 = 4
spectrum.q2 = 32
spectrum.hurst = 0.8
The ``spectrum`` object can be queried for information, such as the root-mean-square of heights, the various statistical moments, the spectrum bandwidth, etc. Then we create a generator object and build the random surface::
generator = tm.SurfaceGeneratorFilter2D()
generator.setSpectrum(spectrum)
generator.random_seed = 0
surface = generator.buildSurface()
The ``surface`` object is a :py:class:`numpy.ndarray` wrapped around internal memory in the ``generator`` object, so a subsequent call to :py:func:`buildSurface <tamaas._tamaas.SurfaceGenerator2D.buildSurface>` may change its content. Note that if ``generator`` goes out of scope its memory will not be freed if there is still a live reference to the surface data.
Custom filter
-------------
Tamaas provides several classes that can be derived directly with Python classes, and :cpp:class:`tamaas::Filter` is one of them. Since it provides a single pure virtual method :cpp:func:`computeFilter <tamaas::Filter::computeFilter>`, it is easy to write a sub-class. Here we implement a class that takes a user-defined auto-correlation function and implements the :cpp:func:`computeFilter <tamaas::Filter::computeFilter>` virtual function::
class AutocorrelationFilter(tm.Filter2D):
def __init__(self, autocorrelation):
super().__init__(self)
self.autocorrelation = autocorrelation.copy()
def computeFilter(self, filter_coefficients):
shifted_ac = np.fft.ifftshift(self.autocorrelation)
filter_coefficients[...] = np.sqrt(np.fft.rfft2(shifted_ac))
Here ``filter_coefficients`` is also a :py:class:`numpy.ndarray` and is therefore easily manipulated. The creation of the surface then follows the same pattern as previously::
# Create spectrum object
autocorrelation = ... # set your desired autocorrelation
spectrum = AutocorrelationFilter(autocorrelation)
generator = tm.SurfaceGenerator2D()
generator.setSpectrum(spectrum)
surface = generator.buildSurface()
The lifetime of the ``spectrum`` object is associated to the ``generator`` when :py:func:`setSpectrum <tamaas._tamaas.SurfaceGeneratorFilter2D.setSpectrum>` is called.
Surface Satistics
-----------------
Tamaas provides the C++ class :cpp:class:`tamaas::Statistics` and its wrapper :py:class:`Statistics2D <tamaas._tamaas.Statistics2D>` to compute statistics on surfaces, including:
- power spectrum density
- autocorrelation
- spectrum moments
- root-mean-square of heigts :math:`\sqrt{\langle h^2 \rangle}`
- root-mean-square of slopes (computed in Fourier domain) :math:`\sqrt{\langle |\nabla h|^2\rangle}`
All these quantities are computed in a discretization-independent manner: increasing the number of points in the surface should not drastically change the computed values (for a given spectrum). This allows to refine the discretization as much as possible to approximate a continuum. Note that the autocorrelation and PSD are fft-shifted. Here is a sample code plotting the PSD and autocorrelation::
psd = tm.Statistics2D.computePowerSpectrum(surface)
psd = np.fft.fftshift(psd, axes=0) # Shifting only once axis because of R2C transform
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
plt.imshow(psd.real, norm=LogNorm())
acf = tm.Statistics2D.computeAutocorrelation(surface)
acf = np.fft.fftshift(acf)
plt.figure()
plt.imshow(acf)
plt.show()
See ``examples/statistics.py`` for more usage examples of statistics.

Event Timeline