random-fields 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- random_fields/__init__.py +1 -0
- random_fields/__version__.py +3 -0
- random_fields/generate_field.py +96 -0
- random_fields/utils.py +97 -0
- random_fields-1.0.1.dist-info/LICENSE +28 -0
- random_fields-1.0.1.dist-info/METADATA +153 -0
- random_fields-1.0.1.dist-info/RECORD +9 -0
- random_fields-1.0.1.dist-info/WHEEL +5 -0
- random_fields-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .__version__ import __version__
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import List
|
|
3
|
+
import numpy as np
|
|
4
|
+
import gstools as gs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ModelName(Enum):
|
|
8
|
+
"""
|
|
9
|
+
Name of the model to be used. Options are: "Gaussian", "Exponential", "Matern", "Linear"
|
|
10
|
+
"""
|
|
11
|
+
Gaussian = gs.Gaussian
|
|
12
|
+
Exponential = gs.Exponential
|
|
13
|
+
Matern = gs.Matern
|
|
14
|
+
Linear = gs.Linear
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RandomFields:
|
|
18
|
+
"""
|
|
19
|
+
Generate random fields
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, model_name: ModelName, n_dim: int,
|
|
23
|
+
mean: float, variance: float,
|
|
24
|
+
v_scale_fluctuation: float, anisotropy: List[float], angle: List[float],
|
|
25
|
+
seed: int = 14, v_dim: int = 1) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Initialise generation of random fields
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
-----------
|
|
31
|
+
model_name: str
|
|
32
|
+
Name of the model to be used. Options are: "Gaussian", "Exponential", "Matern", "Linear"
|
|
33
|
+
n_dim: int
|
|
34
|
+
The dimension of the random field
|
|
35
|
+
mean: float
|
|
36
|
+
The mean of the random field
|
|
37
|
+
variance: float
|
|
38
|
+
The variance of the random field
|
|
39
|
+
v_scale_fluctuation: float
|
|
40
|
+
The vertical scale of fluctuation of the random field
|
|
41
|
+
anisotropy: list
|
|
42
|
+
The anisotropy of the random field (per dimension)
|
|
43
|
+
angle: list
|
|
44
|
+
The angle of the random field (per dimension)
|
|
45
|
+
seed: int
|
|
46
|
+
The seed number for the random number generator
|
|
47
|
+
v_dim: int
|
|
48
|
+
The dimension of the vertical scale of fluctuation
|
|
49
|
+
"""
|
|
50
|
+
# initialise model
|
|
51
|
+
if model_name.name not in ModelName.__members__:
|
|
52
|
+
raise ValueError(f'Model name: {model_name} is not supported')
|
|
53
|
+
|
|
54
|
+
if n_dim not in [1, 2, 3]:
|
|
55
|
+
raise ValueError('Only 1, 2, 3 dimensions are supported')
|
|
56
|
+
|
|
57
|
+
aux_keys = [anisotropy, angle]
|
|
58
|
+
for key in aux_keys:
|
|
59
|
+
if len(key) != n_dim - 1:
|
|
60
|
+
raise ValueError(f'Number of dimensions: {n_dim} does not match number of\
|
|
61
|
+
random field properties: {len(variance)}. It should be {n_dim - 1}.')
|
|
62
|
+
|
|
63
|
+
self.random_field_model = model_name.value
|
|
64
|
+
self.n_dim = n_dim
|
|
65
|
+
self.seed = seed
|
|
66
|
+
self.mean = mean
|
|
67
|
+
self.variance = variance
|
|
68
|
+
self.vertical_scale_fluctuation = v_scale_fluctuation
|
|
69
|
+
self.anisotropy = anisotropy
|
|
70
|
+
self.angle = angle
|
|
71
|
+
self.v_dim = v_dim
|
|
72
|
+
self.random_field = None
|
|
73
|
+
|
|
74
|
+
def generate(self, nodes: np.ndarray) -> None:
|
|
75
|
+
"""
|
|
76
|
+
Generate random field
|
|
77
|
+
|
|
78
|
+
Parameters:
|
|
79
|
+
------------
|
|
80
|
+
nodes: list
|
|
81
|
+
The nodes of the random field
|
|
82
|
+
"""
|
|
83
|
+
# check dimensions of nodes agrees with dimensions of model
|
|
84
|
+
if nodes.shape[1] != self.n_dim:
|
|
85
|
+
raise ValueError(f'Dimensions of nodes: {nodes.shape[1]} do not match dimensions of model: {self.n_dim}')
|
|
86
|
+
|
|
87
|
+
# scale of fluctuation
|
|
88
|
+
scale_fluctuation = np.ones(self.n_dim) * self.vertical_scale_fluctuation
|
|
89
|
+
|
|
90
|
+
# apply the anisotropy to the other dimensions
|
|
91
|
+
mask = np.arange(len(scale_fluctuation)) != self.v_dim
|
|
92
|
+
scale_fluctuation[mask] = scale_fluctuation[mask] * self.anisotropy
|
|
93
|
+
|
|
94
|
+
model = self.random_field_model(dim=self.n_dim, var=self.variance, len_scale=scale_fluctuation, angles=self.angle)
|
|
95
|
+
self.random_field = gs.SRF(model, mean=self.mean, seed=self.seed)
|
|
96
|
+
self.random_field(nodes.T)
|
random_fields/utils.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib.pylab as plt
|
|
4
|
+
import matplotlib as mpl
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def plot3D(coordinates: list, random_field: list, title: str = "Random Field",
|
|
8
|
+
output_folder = "./", output_name: str = "random_field.png"):
|
|
9
|
+
"""
|
|
10
|
+
Plot 3D random field
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
coordinates : list
|
|
15
|
+
List of coordinates of the random field
|
|
16
|
+
random_field : list
|
|
17
|
+
List of random field values
|
|
18
|
+
title : str
|
|
19
|
+
Title of the plot
|
|
20
|
+
output_folder : str
|
|
21
|
+
Output folder
|
|
22
|
+
output_name : str
|
|
23
|
+
Output fine name
|
|
24
|
+
"""
|
|
25
|
+
# create output folder
|
|
26
|
+
if not os.path.exists(output_folder):
|
|
27
|
+
os.makedirs(output_folder)
|
|
28
|
+
|
|
29
|
+
# make plot
|
|
30
|
+
fig = plt.figure(1, figsize=(6, 5))
|
|
31
|
+
ax = fig.add_subplot(projection='3d')
|
|
32
|
+
ax.set_position([0.1, 0.1, 0.8, 0.8])
|
|
33
|
+
# rotate the axes so that y is vertical
|
|
34
|
+
ax.view_init(125, -90, 0)
|
|
35
|
+
|
|
36
|
+
vmin = np.min([np.min(aux) for aux in random_field])
|
|
37
|
+
vmax = np.max([np.max(aux) for aux in random_field])
|
|
38
|
+
|
|
39
|
+
for i, coord in enumerate(coordinates):
|
|
40
|
+
x, y, z = coord[:, 0], coord[:, 1], coord[:, 2]
|
|
41
|
+
ax.scatter(x, y, z, c=random_field[i], vmin=vmin, vmax=vmax, cmap="viridis", edgecolors=None, marker="s")
|
|
42
|
+
|
|
43
|
+
ax.set_xlabel('x coordinate')
|
|
44
|
+
ax.set_ylabel('y coordinate')
|
|
45
|
+
ax.set_zlabel('z coordinate')
|
|
46
|
+
|
|
47
|
+
cax = ax.inset_axes([1.1, 0., 0.05, 1])
|
|
48
|
+
norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
|
|
49
|
+
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap="viridis"), ax=ax, cax=cax)
|
|
50
|
+
fig.suptitle(title)
|
|
51
|
+
plt.savefig(os.path.join(output_folder, output_name))
|
|
52
|
+
plt.close()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def plot2D(coordinates: list, random_field: list, title: str = "Random Field",
|
|
56
|
+
output_folder = "./", output_name: str = "random_field.png"):
|
|
57
|
+
"""
|
|
58
|
+
Plot 2D random field
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
coordinates : list
|
|
63
|
+
List of coordinates of the random field
|
|
64
|
+
random_field : list
|
|
65
|
+
List of random field values
|
|
66
|
+
title : str
|
|
67
|
+
Title of the plot
|
|
68
|
+
output_folder : str
|
|
69
|
+
Output folder
|
|
70
|
+
output_name : str
|
|
71
|
+
Output fine name
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
# create output folder
|
|
75
|
+
if not os.path.exists(output_folder):
|
|
76
|
+
os.makedirs(output_folder)
|
|
77
|
+
|
|
78
|
+
# make plot
|
|
79
|
+
fig, ax = plt.subplots(figsize=(6, 5))
|
|
80
|
+
ax.set_position([0.1, 0.1, 0.7, 0.8])
|
|
81
|
+
|
|
82
|
+
vmin = np.min([np.min(aux) for aux in random_field])
|
|
83
|
+
vmax = np.max([np.max(aux) for aux in random_field])
|
|
84
|
+
|
|
85
|
+
for i, coord in enumerate(coordinates):
|
|
86
|
+
x, y = coord[:, 0], coord[:, 1]
|
|
87
|
+
ax.scatter(x, y, c=random_field[i], vmin=vmin, vmax=vmax, cmap="viridis", edgecolors=None, marker="s")
|
|
88
|
+
|
|
89
|
+
ax.set_xlabel('x coordinate')
|
|
90
|
+
ax.set_ylabel('y coordinate')
|
|
91
|
+
|
|
92
|
+
cax = ax.inset_axes([1.1, 0., 0.05, 1])
|
|
93
|
+
norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
|
|
94
|
+
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap="viridis"), ax=ax, cax=cax)
|
|
95
|
+
fig.suptitle(title)
|
|
96
|
+
plt.savefig(os.path.join(output_folder, output_name))
|
|
97
|
+
plt.close()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2025, StemVibrations
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: random_fields
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Random fields on unstructured grids
|
|
5
|
+
Author: attr: random_fields.__author__
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
8
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
9
|
+
Classifier: Operating System :: Unix
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: numpy>=2.0.2
|
|
14
|
+
Requires-Dist: matplotlib>=3.9.3
|
|
15
|
+
Requires-Dist: gstools>=1.6.0
|
|
16
|
+
Provides-Extra: testing
|
|
17
|
+
Requires-Dist: pytest>=7.4.2; extra == "testing"
|
|
18
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "testing"
|
|
19
|
+
Requires-Dist: tox>=4.4; extra == "testing"
|
|
20
|
+
Provides-Extra: docs
|
|
21
|
+
Requires-Dist: Sphinx==6.2.1; extra == "docs"
|
|
22
|
+
Requires-Dist: sphinx-rtd-theme==1.2.2; extra == "docs"
|
|
23
|
+
|
|
24
|
+
# RandomFields
|
|
25
|
+

|
|
26
|
+
[](https://codecov.io/gh/StemVibrations/RandomFields)
|
|
27
|
+
|
|
28
|
+
# Random Fields
|
|
29
|
+
|
|
30
|
+
Python package to generate random fields in 2D or 3D on unstructured grids.
|
|
31
|
+
|
|
32
|
+
## Background information
|
|
33
|
+
The random fields are generated using [gstools](https://geostat-framework.readthedocs.io/en/latest/).
|
|
34
|
+
|
|
35
|
+
Currently, the following covariance models are available:
|
|
36
|
+
- Gaussian
|
|
37
|
+
- Exponential
|
|
38
|
+
- Matern
|
|
39
|
+
- Linear
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
To install the package, run the following command in the terminal:
|
|
44
|
+
```bash
|
|
45
|
+
pip install git+https://github.com/StemVibrations/RandomFields
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
# Tutorial
|
|
49
|
+
## Example in 2D
|
|
50
|
+
|
|
51
|
+
In this example we generate a random field on a 2D regular grid.
|
|
52
|
+
|
|
53
|
+
First you need to import the packages:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import numpy as np
|
|
57
|
+
from random_fields.generate_field import RandomFields, ModelName
|
|
58
|
+
from random_fields.utils import plot2D
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then you need to define the grid:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
x = np.linspace(0, 100, 50)
|
|
65
|
+
y = np.linspace(0, 50, 50)
|
|
66
|
+
|
|
67
|
+
x, y = np.meshgrid(x, y)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
In this example we create a mesh of 50x50 points between 0 and 100 in x and 0 and 50 in y direction.
|
|
71
|
+
|
|
72
|
+
Then we define the random field properties:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
nb_dimensions = 2
|
|
76
|
+
mean = 10
|
|
77
|
+
variance = 2
|
|
78
|
+
vertical_scale_fluctuation = 10
|
|
79
|
+
anisotropy = [1]
|
|
80
|
+
angle = [0]
|
|
81
|
+
model_rf = ModelName.Gaussian
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
In this example we use a Gaussian covariance model.
|
|
85
|
+
|
|
86
|
+
Then we create the random field:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
rf = RandomFields(model_rf, nb_dimensions, mean, variance, vertical_scale_fluctuation, anisotropy, angle, seed=14)
|
|
90
|
+
rf.generate(np.array([x.ravel(), y.ravel()]).T)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To visualise the results you can run:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
plot2D([np.array([x.ravel(), y.ravel()]).T], [rf.random_field], title="Random Field", output_folder="./", output_name="random_field.png")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The result is the following random field:
|
|
100
|
+
|
|
101
|
+

|
|
102
|
+
|
|
103
|
+
## Example in 3D
|
|
104
|
+
|
|
105
|
+
In this example we generate a random field on a 3D regular grid.
|
|
106
|
+
|
|
107
|
+
First you need to import the packages:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import numpy as np
|
|
111
|
+
from random_fields.generate_field import RandomFields, ModelName
|
|
112
|
+
from random_fields.utils import plot3D
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Then you need to define the grid:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
x = np.linspace(0, 100, 50)
|
|
119
|
+
y = np.linspace(0, 50, 50)
|
|
120
|
+
z = np.linspace(0, 25, 25)
|
|
121
|
+
|
|
122
|
+
x, y, z = np.meshgrid(x, y, z)
|
|
123
|
+
```
|
|
124
|
+
In this example we create a mesh of 50x50x25 points between 0 and 100 in x, 0 and 50 in y direction and 0 and 25 in z direction.
|
|
125
|
+
|
|
126
|
+
Then we define the random field properties:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
nb_dimensions = 3
|
|
130
|
+
mean = 10
|
|
131
|
+
variance = 2
|
|
132
|
+
vertical_scale_fluctuation = 10
|
|
133
|
+
anisotropy = [5, 5]
|
|
134
|
+
angle = [0, 0]
|
|
135
|
+
model_rf = ModelName.Gaussian
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Then we create the random field:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
rf = RandomFields(model_rf, nb_dimensions, mean, variance, vertical_scale_fluctuation, anisotropy, angle, seed=14)
|
|
142
|
+
rf.generate(np.array([x.ravel(), y.ravel(), z.ravel()]).T)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
To visualise the results you can run:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
plot3D([np.array([x.ravel(), y.ravel(), z.ravel()]).T], [rf.random_field], title="Random Field", output_folder="./", output_name="random_field_3D.png")
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
The result is the following random field:
|
|
152
|
+
|
|
153
|
+

|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
random_fields/__init__.py,sha256=e3S0EcDGJlWIp2hddSFjvt633jfeZ4W7VyAeLpfTWVM,37
|
|
2
|
+
random_fields/__version__.py,sha256=DLIwjEWAWM3KBFCJ_Q00fL6GY1GlsiYH0pveSBIDxww,85
|
|
3
|
+
random_fields/generate_field.py,sha256=0C4h9viPoj7o4szOBzI7WGzmPb2SC-YH5_C72JJ2w94,3397
|
|
4
|
+
random_fields/utils.py,sha256=dBMqWMe0knF-Leb0aCXCqztGeOYx5FnukOQyPWIbfPo,2967
|
|
5
|
+
random_fields-1.0.1.dist-info/LICENSE,sha256=WbcTzZtVX4H8BLF_mD2BtvCL8oh43TQtyugBiPKVDwo,1506
|
|
6
|
+
random_fields-1.0.1.dist-info/METADATA,sha256=PXgQ1zIBAgF9v57W4g6csZ9kyN0R30wdHM8i8rk3RL8,4073
|
|
7
|
+
random_fields-1.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
8
|
+
random_fields-1.0.1.dist-info/top_level.txt,sha256=yFqhrKXL6hMrmI_OAUg9EBy5DvJsOQYBpLqqGdqL2zE,14
|
|
9
|
+
random_fields-1.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
random_fields
|