Skip to content

Commit

Permalink
Add examples for cond. PGS & P-PGS
Browse files Browse the repository at this point in the history
  • Loading branch information
LSchueler committed Jan 10, 2025
1 parent 6c3eed3 commit 5d51a64
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
142 changes: 142 additions & 0 deletions examples/11_plurigaussian/05_conditioned.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"""
Creating conditioned PGS
------------------------
In case we have knowledge about values of the PGS in certain areas, we should
incorporate that knowledge. We can do this by using conditional fields, which
are created by combining kriged fields with SRFs. This can be done quite easily
with GSTools. For more details, have a look at the kriging and conditional
field examples.
In this example, we assume that we know the categorical values of the PGS field
to be 2 in the lower left 20 by 20 grid cells.
"""

import matplotlib.pyplot as plt
import numpy as np

import gstools as gs

dim = 2
# no. of cells in both dimensions
N = [100, 80]

# grid
x = np.arange(N[0])
y = np.arange(N[1])

###############################################################################
# Now we want to read the known data in order to condition the PGS on them.
# Normally, we would probably get the data in a different format, but in order
# to keep the dependencies for this example to a minimum, we will simpy use a
# numpy format. After reading in the data, we will have a quick look at how the
# data looks like.
# We'll see the first few values, which are all 1. This value is not very
# important. However, it should be in the range of SRF values, to not mess
# with the kriging. The known value of the PGS, namely 2, will be set for the
# L-field, which will map it the the conditioned SRF values of 1 at given
# positions.

cond_data = np.load("conditional_values.npz")
cond_pos = cond_data["cond_pos"]
cond_val = cond_data["cond_val"]
print(f"first 5 conditional positions:\n{cond_pos[:, :5]}")
print(f"first 5 conditional values:\n{cond_val[:5]}")

###############################################################################
# With the conditional values ready, we can now set up the covariance model
# for the kriging. This knowledge has to normally be inferred, but here we just
# assume that we know the convariance structure of the underlying field.
# For better visualization, we use `Simple` kriging with a mean value of 0.

model = gs.Gaussian(dim=dim, var=1, len_scale=[10, 5], angles=np.pi / 8)
krige = gs.krige.Simple(model, cond_pos=cond_pos, cond_val=cond_val, mean=0)
cond_srf = gs.CondSRF(krige)
cond_srf.set_pos([x, y], "structured")

###############################################################################
# Now that the conditioned field class is set up, we can generate SRFs
# conditioned on our previous knowledge. We'll do that for the two SRFs needed
# for the PGS, and then we will also set up the PGS generator. Next, we'll
# use a little helper method, which can transform the coordinates from the SRFs
# to the L field. This helps us set up the area around the conditioned value
# `cond_val`.

field1 = cond_srf(seed=484739)
field2 = cond_srf(seed=45755894)

pgs = gs.PGS(dim, [field1, field2])

M = [100, 80]

# size of the rectangle
R = [40, 32]

L = np.zeros(M)
# calculate grid axes of the L-field
pos_l = pgs.calc_L_axes(L.shape)
# transform conditioned SRF value to L-field index
pos_l_i = pgs.transform_coords(L.shape, [cond_val[0], cond_val[0]])

# conditioned category of 2 around the conditioned values' positions
L[
pos_l_i[0] - 5 : pos_l_i[0] + 5,
pos_l_i[1] - 5 : pos_l_i[1] + 5,
] = 2

###############################################################################
# With the two SRFs and `L` ready, we can create the actual PGS.

P = pgs(L)

###############################################################################
# Finally, we can plot the PGS, but we will also show the L-field and the two
# original Gaussian SRFs. We will set the colours of the SRF correlation
# scatter plot to be the sum of their respective position tuples (x+y), to get a
# feeling for which point corresponds to which position. The more blue the
# points, the smaller the sum is. We can nicely see that many blue points
# gather in the highlighted rectangle of the L-field where the categorical
# value of 2 is set.

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(field1, cmap="copper", vmin=-3, vmax=2, origin="lower")
axs[0, 1].imshow(field2, cmap="copper", vmin=-3, vmax=2, origin="lower")
axs[1, 0].scatter(
field1.flatten(),
field2.flatten(),
s=0.1,
c=(x.reshape((len(x), 1)) + y.reshape((1, len(y))).flatten()),
)
axs[1, 0].pcolormesh(pos_l[0], pos_l[1], L.T, alpha=0.3, cmap="copper")
axs[1, 1].imshow(P, cmap="copper", origin="lower")

plt.tight_layout()
plt.show()

###############################################################################
# With all this set up, we can easily create an ensemble of PGS, which conform
# to the conditional values

seed = gs.random.MasterRNG(20170519)

ens_no = 9
fields1 = []
fields2 = []
Ps = []
for i in range(ens_no):
fields1.append(cond_srf(seed=seed()))
fields2.append(cond_srf(seed=seed()))
pgs = gs.PGS(dim, [fields1[-1], fields2[-1]])
Ps.append(pgs(L))

fig, axs = plt.subplots(3, 3)
cnt = 0
for i in range(int(np.sqrt(ens_no))):
for j in range(int(np.sqrt(ens_no))):
axs[i, j].imshow(Ps[cnt], cmap="copper", origin="lower")

cnt += 1

plt.tight_layout()
plt.show()
76 changes: 76 additions & 0 deletions examples/11_plurigaussian/06_periodic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Creating PGS with periodic boundaries
-------------------------------------
Plurigaussian fields with periodic boundaries (P-PGS) are used in various
applications, including the simulation of interactions between the landsurface
and the atmosphere, as well as the application of homogenisation theory to
porous media, e.g. [Ricketts 2024](https://doi.org/10.1007/s11242-024-02074-z).
In this example we will use GSTools's Fourier generator to create periodic
random fields, which can in turn be used to generate P-PGS.
"""

import matplotlib.pyplot as plt
import numpy as np

import gstools as gs

dim = 2
# define the spatial grid, see the periodic random field [examples](https://geostat-framework.readthedocs.io/projects/gstools/en/latest/examples/01_random_field/08_fourier.html)
# for details.

# domain size and periodicity
L = 200
# no. of cells in both dimensions
N = [170, 153]

x = np.linspace(0, L, N[0], endpoint=False)
y = np.linspace(0, L, N[1], endpoint=False)

###############################################################################
# The parameters of the covariance model are very similar to previous examples.
# The interesting part is the SRF class. We set the `generator` to `"Fourier"`,
# which inherently generates periodic SRFs. The Fourier generator needs an
# extra parameter `period` which defines the periodicity.

model = gs.Gaussian(dim=dim, var=0.8, len_scale=40)
srf = gs.SRF(model, generator="Fourier", period=L)
field1 = srf.structured([x, y], seed=19770319)
field2 = srf.structured([x, y], seed=19860912)

###############################################################################
# Very similar to previous examples, we create a simple L-field.

M = [200, 160]

# size of the rectangle
R = [40, 32]

L = np.zeros(M)
L[
M[0] // 2 - R[0] // 2 : M[0] // 2 + R[0] // 2,
M[1] // 2 - R[1] // 2 : M[1] // 2 + R[1] // 2,
] = 1

###############################################################################
# With the two SRFs and the L-ield ready, we can create our first P-PGS.

pgs = gs.PGS(dim, [field1, field2])
P = pgs(L)

###############################################################################
# Finally, we can plot the PGS, but we will also show the L-field and the two
# original periodic Gaussian fields.
# Especially with `field1` you can nicely see the periodic structures in the
# black structure in the upper right corner. This transfers to the P-PGS, where
# you can see that the structures seemlessly match the opposite boundaries.

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(field1, cmap="copper", origin="lower")
axs[0, 1].imshow(field2, cmap="copper", origin="lower")
axs[1, 0].imshow(L, cmap="copper", origin="lower")
axs[1, 1].imshow(P, cmap="copper", origin="lower")

plt.show()
Binary file added examples/11_plurigaussian/conditional_values.npz
Binary file not shown.

0 comments on commit 5d51a64

Please sign in to comment.