Commit 227cfeae authored by theos's avatar theos
Browse files

Finished first implementation of Field.power_synthesize.

parent 7041c114
...@@ -314,17 +314,115 @@ class Field(object): ...@@ -314,17 +314,115 @@ class Field(object):
return result_obj return result_obj
def power_synthesize(self, spaces=None, real_signal=True): def power_synthesize(self, spaces=None, real_signal=True):
# assert that all spaces in `self.domain` are eiher of signal-type or # assert that all spaces in `self.domain` are either of signal-type or
# power_space instances # power_space instances
for sp in self.domain: for sp in self.domain:
if sp.harmonic and not isinstance(sp, PowerSpace): if not sp.harmonic and not isinstance(sp, PowerSpace):
raise AttributeError( raise AttributeError(
"ERROR: Field has a space in `domain` which is neither " "ERROR: Field has a space in `domain` which is neither "
"harmonic nor a PowerSpace.") "harmonic nor a PowerSpace.")
# synthesize random fields in harmonic domain using # check if the `spaces` input is valid
# np.random.multivariate_normal(mean=[0,0], cov=[[0.5,0],[0,0.5]], size=shape) spaces = utilities.cast_axis_to_tuple(spaces, len(self.domain))
if spaces is None:
if len(self.domain) == 1:
spaces = (0,)
raise ValueError(about._errors.cstring(
"ERROR: Field has multiple spaces as domain "
"but `spaces` is None."))
if len(spaces) == 0:
raise ValueError(about._errors.cstring(
"ERROR: No space for synthesis specified."))
elif len(spaces) > 1:
raise ValueError(about._errors.cstring(
"ERROR: Conversion of only one space at a time is allowed."))
power_space_index = spaces[0]
power_domain = self.domain[power_space_index]
if not isinstance(power_domain, PowerSpace):
raise ValueError(about._errors.cstring(
"ERROR: A PowerSpace is needed for field synthetization."))
# create the result domain
result_domain = list(self.domain)
harmonic_domain = power_domain.harmonic_domain
result_domain[power_space_index] = harmonic_domain
# create random samples: one or two, depending on whether the
# power spectrum is real or complex
if issubclass(power_domain.dtype.type, np.complexfloating):
result_list = [None, None]
result_list = [None]
result_list = [self.__class__.from_random('normal',
for x in result_list]
# from now on extract the values from the random fields for further
# processing without killing the fields.
# if the signal-space field should be real, hermitianize the field
# components
if real_signal:
result_val_list = [harmonic_domain.hermitian_decomposition(
for x in result_list]
result_val_list = [x.val for x in result_list]
# weight the random fields with the power spectrum
# therefore get the pindex from the power space
pindex = power_domain.pindex
# take the local data from pindex. This data must be compatible to the
# local data of the field given the slice of the PowerSpace
local_distribution_strategy = \
if pindex.distribution_strategy is not local_distribution_strategy:
"WARNING: The distribution_stragey of pindex does not fit the "
"slice_local distribution strategy of the synthesized field.")
# Now use numpy advanced indexing in order to put the entries of the
# power spectrum into the appropriate places of the pindex array.
# Do this for every 'pindex-slice' in parallel using the 'slice(None)'s
local_pindex = pindex.get_local_data(copy=False)
local_spec = self.val.get_local_data(copy=False)
local_blow_up = [slice(None)]*len(self.shape)
local_blow_up[self.domain_axes[power_space_index][0]] = local_pindex
# here, the power_spectrum is distributed into the new shape
local_rescaler = local_spec[local_blow_up]
# apply the rescaler to the random fields
lambda x: x * local_rescaler.real,
if issubclass(power_domain.dtype.type, np.complexfloating):
lambda x: x * local_rescaler.imag,
# store the result into the fields
[x.set_val(new_val=y, copy=False) for x, y in
zip(result_list, result_val_list)]
if issubclass(power_domain.dtype.type, np.complexfloating):
result = result_list[0] + 1j*result_list[1]
result = result_list[0]
return result
# ---Properties--- # ---Properties---
...@@ -413,9 +511,10 @@ class Field(object): ...@@ -413,9 +511,10 @@ class Field(object):
if dtype is None: if dtype is None:
dtype = self.dtype dtype = self.dtype
return_x = distributed_data_object(global_shape=self.shape, return_x = distributed_data_object(
dtype=dtype, global_shape=self.shape,
distribution_strategy=self.datamodel) dtype=dtype,
return_x.set_full_data(x, copy=False) return_x.set_full_data(x, copy=False)
return return_x return return_x
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment