Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add support for nd vectors on md field #251

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/gstools/field/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def pos(self, pos):
self._pos, self._field_shape = format_struct_pos_dim(pos, self.dim)
# prepend dimension if we have a vector field
if self.value_type == "vector":
self._field_shape = (self.dim,) + self._field_shape
self._field_shape = (self.generator.vec_dim,) + self._field_shape
if self.latlon:
raise ValueError("Field: Vector fields not allowed for latlon")

Expand Down
19 changes: 15 additions & 4 deletions src/gstools/field/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ class IncomprRandMeth(RandMeth):
the mean velocity in x-direction
mode_no : :class:`int`, optional
number of Fourier modes. Default: ``1000``
vec_dim : :class:`int`, optional
vector dimension, in case it mismatches the model dimension
seed : :class:`int` or :any:`None`, optional
the seed of the random number generator.
If "None", a random seed is used. Default: :any:`None`
Expand Down Expand Up @@ -465,18 +467,27 @@ def __init__(
model,
mean_velocity=1.0,
mode_no=1000,
vec_dim=None,
seed=None,
verbose=False,
sampling="auto",
**kwargs,
):
if model.dim < 2 or model.dim > 3:
if vec_dim is None and (model.dim < 2 or model.dim > 3):
raise ValueError(
"Only 2D and 3D incompressible fields can be generated."
"Only 2D and 3D incompressible vectors can be generated."
)
if vec_dim is not None and (vec_dim < 2 or vec_dim > 3):
raise ValueError(
"Only 2D and 3D incompressible vectors can be generated."
)
super().__init__(model, mode_no, seed, verbose, sampling, **kwargs)

self.mean_u = mean_velocity
if vec_dim is None:
self.vec_dim = model.dim
else:
self.vec_dim = vec_dim
self._value_type = "vector"

def __call__(self, pos, add_nugget=True):
Expand All @@ -501,7 +512,7 @@ def __call__(self, pos, add_nugget=True):
"""
pos = np.asarray(pos, dtype=np.double)
summed_modes = summate_incompr(
self._cov_sample, self._z_1, self._z_2, pos
self.vec_dim, self._cov_sample, self._z_1, self._z_2, pos
)
nugget = self.get_nugget(summed_modes.shape) if add_nugget else 0.0
e1 = self._create_unit_vector(summed_modes.shape)
Expand Down Expand Up @@ -532,7 +543,7 @@ def _create_unit_vector(self, broadcast_shape, axis=0):
the unit vector
"""
shape = np.ones(len(broadcast_shape), dtype=int)
shape[0] = self.model.dim
shape[0] = self.vec_dim

e1 = np.zeros(shape)
e1[axis] = 1.0
Expand Down
15 changes: 8 additions & 7 deletions src/gstools/field/summator.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ cdef (double) abs_square(const double[:] vec) nogil:


def summate_incompr(
const int vec_dim,
const double[:, :] cov_samples,
const double[:] z_1,
const double[:] z_2,
Expand All @@ -58,24 +59,24 @@ def summate_incompr(
cdef int i, j, d
cdef double phase
cdef double k_2
cdef int dim = pos.shape[0]
cdef int field_dim = pos.shape[0]

cdef double[:] e1 = np.zeros(dim, dtype=float)
cdef double[:] e1 = np.zeros(vec_dim, dtype=float)
e1[0] = 1.
cdef double[:] proj = np.empty(dim)
cdef double[:] proj = np.empty(vec_dim)

cdef int X_len = pos.shape[1]
cdef int N = cov_samples.shape[1]

cdef double[:, :] summed_modes = np.zeros((dim, X_len), dtype=float)
cdef double[:, :] summed_modes = np.zeros((vec_dim, X_len), dtype=float)

for i in range(X_len):
for j in range(N):
k_2 = abs_square(cov_samples[:, j])
k_2 = abs_square(cov_samples[:vec_dim, j])
phase = 0.
for d in range(dim):
for d in range(field_dim):
phase += cov_samples[d, j] * pos[d, i]
for d in range(dim):
for d in range(vec_dim):
proj[d] = e1[d] - cov_samples[d, j] * cov_samples[0, j] / k_2
summed_modes[d, i] += proj[d] * (z_1[j] * cos(phase) + z_2[j] * sin(phase))

Expand Down