-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.