Skip to content

Commit

Permalink
Updates after review of localisation script
Browse files Browse the repository at this point in the history
  • Loading branch information
oddvarlia authored and oyvindeide committed Apr 20, 2022
1 parent 08ba4e8 commit 2d486df
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 124 deletions.
81 changes: 50 additions & 31 deletions semeio/workflows/localisation/local_config_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,12 @@ def run(self, *args):
or **surface_scale** keyword.
For **field_scale** the available methods are **gaussian_decay**,
**exponential_decay**, **from_file** and **segment**.
For **surface_scale** the available methods are **gaussian_decay** and
**exponential_decay**.
**exponential_decay**, **const_gaussian_decay**, **const_exponential_decay**,
**from_file** and **segment**.
For **surface_scale** the available methods are **gaussian_decay**,
**exponential_decay**, **const_gaussian_decay**,
**const_exponential_decay**
:exponential_decay:
Name of a method or scaling function having default expression defined by
Expand All @@ -323,25 +326,43 @@ def run(self, *args):
and *perp_range* range parameters. A rotation of the ellipse defined by *d=1*
is also possible by specifying azimuth direction different from 0.
There are options to modify the default definition of this function.
If cutoff is specified using **set_to_zero_outside_range**, the function
If cutoff is specified using **cutoff**, the function
returns 0 if the normalised distance *d > 1*.
The user can choose an alternative version of this function by using
**normalised_tapering_range** (called *dT* below) with value *dT > 1*.
Then the function is defined by:
*f(d) = 1* for *d <= 1*,
*f(d) = exp(-3(d-1)/(dT-1))* for *d > 1*,
with the option that
*f(d) = 0* for *d > dT* if cutoff is activated by **set_to_zero_outside_range**.
This method requires specification of keywords **main_range**, **perp_range**,
**azimuth** and **ref_point**.
Optional specification of keywords **set_to_zero_outside_range**,
**normalised_tapering_range**.
Optional specification of keywords **cutoff**.
:gaussian_decay:
Scaling function with default expression defined by
*f(d) = exp(-3 d^2)* where *d* is normalised distance.
Name of a method or scaling function defined by *f(d) = exp(-3 d^2)* where *d* is
normalised distance.
For more details see **exponential_decay** above.
:const_exponential_decay:
Name of a method or scaling function defined by
*f(d) = 1* for *d <= 1*,
*f(d) = exp(-3(d-1)/(D-1))* for *d > 1* where D is **normalised_tapering_range**.
and *d* is the normalised distance.
See description above for **exponential_decay**.
There are options to modify the default definition of this function.
If cutoff is specified using **cutoff**, then
*f(d) = 0* for *d > D*.
This method requires specification of keywords **main_range**, **perp_range**,
**azimuth**, **ref_point** and **normalised_tapering_range**.
Optional specification of keywords **cutoff**.
:const_gaussian_decay:
Name of a method or scaling function having default expression defined by
*f(d) = 1* for *d <= 1*,
*f(d) = exp(-3 [ (d-1)/(D-1)]^2 )* for *d > 1* where D
is **normalised_tapering_range**. and *d* is the normalised distance.
See description above for **exponential_decay**.
There are options to modify the default definition of this function.
If cutoff is specified using **cutoff**, then
*f(d) = 0* for *d > D*.
This method requires specification of keywords **main_range**, **perp_range**,
**azimuth**, **ref_point** and **normalised_tapering_range**.
Optional specification of keywords **cutoff**.
:main_range:
Sub keyword under **field_scale** or **surface_scale**. Is only used for
method **exponential_decay** and **gaussian_decay**.
Expand Down Expand Up @@ -369,24 +390,23 @@ def run(self, *args):
1.0 for correlations between observations and the field parameter in that
location.
:set_to_zero_outside_range:
:cutoff:
Optional sub keyword under **field_scale** or **surface_scale**.
Is only used for method **exponential_decay** and **gaussian_decay**.
Is only used for method **exponential_decay**, **gaussian_decay**,
**const_exponential_decay** and **const_gaussian_decay**.
Takes True/False as values. Default is False. If a distance from reference
point to a grid cell is larger than the specified range, the scaling
function is set to 0 if this keyword is set to True.
If the keyword is used together with **normalised_tapering_range**,
the scaling function is set to 0 for distances outside the
normalised tapering range. See keyword **normalised_tapering_range**.
:normalised_tapering_range:
Optional sub keyword under **field_scale** or **surface_scale**.
Is only used for method **exponential_decay** and **gaussian_decay**.
Has only an effect if the value > 1. If value is less than or equal
to 1, it is ignored. Default is to not use this option.
When using this option with value > 1, the scaling function is set
to 1.0 for all grid cells with normalised distance <= 1.
For normalised distance > 1 the function decays from 1 and approach 0
Is only used for method **const_exponential_decay** and
**const_gaussian_decay**.
Legal values for normalised_tapering range *D* are *D > 1*.
Default value is D=1.5.
When using this option, the scaling function is set
to 1.0 for all grid cells with normalised distance *d <= 1*.
For normalised distance *d > 1* the function decays from 1 and approach 0
with increasing distance. The normalised distance is defined to be
the distance measured in number of ranges. Normalised distance equal to 1
corresponds to all points on the ellipse with half axes equal to the
Expand All @@ -396,9 +416,8 @@ def run(self, *args):
value for this keyword. At this distance the scaling factor has decreased
to around 0.05.Typical values for **normalised_tapering_range** are
between 1 and 3.
If **set_to_zero_outside_range** is True, the scaling function is
set to 0 for normalised distance larger than the specified value
for the keyword **normalised_tapering_range**.
If **cutoff** is True, the scaling function is
set to 0 for normalised distance *d > D*.
:surface_file:
Sub keyword under **surface_scale**. Is required and specify filename for
Expand All @@ -422,12 +441,12 @@ def run(self, *args):
for keyword **segment_file**.
:active_segments:
Sub keyword under **field_scale**. Is only used if method is ``segment``.
Sub keyword under **field_scale**. Is only used if method is **segment**.
A list of integer numbers for the segments to use to define active field
parameter values.
:scalingfactors:
Sub keyword under **field_scale**. Is only used if method is ``segment``.
Sub keyword under **field_scale**. Is only used if method is **segment**.
A list of float values between 0 and 1 is specified. The values are
scaling factors to be used in the active segments specified.
The list in **active_segments** and **scalingfactors** must of same
Expand Down
152 changes: 102 additions & 50 deletions semeio/workflows/localisation/local_script_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,33 +228,51 @@ def apply_decay(
and returns a full sized grid parameter with scaling factors for active
grid cells and 0 elsewhere to be used for QC purpose.
"""
use_one_in_range = False
if tapering_range is not None:
use_one_in_range = tapering_range > 1
if method == "gaussian_decay":
decay_obj = GaussianDecay(
ref_pos,
main_range,
perp_range,
azimuth,
use_one_in_range,
tapering_range,
use_cutoff,
grid,
use_cutoff,
)
elif method == "exponential_decay":
decay_obj = ExponentialDecay(
ref_pos,
main_range,
perp_range,
azimuth,
use_one_in_range,
grid,
use_cutoff,
)
elif method == "const_gaussian_decay":
decay_obj = ConstGaussianDecay(
ref_pos,
main_range,
perp_range,
azimuth,
grid,
tapering_range,
use_cutoff,
)
elif method == "const_exponential_decay":
decay_obj = ConstExponentialDecay(
ref_pos,
main_range,
perp_range,
azimuth,
grid,
tapering_range,
use_cutoff,
)
else:
_valid_methods = ["gaussian_decay", "exponential_decay"]
_valid_methods = [
"gaussian_decay",
"exponential_decay",
"const_gaussian_decay",
"const_exponential_decay",
]
raise NotImplementedError(
f"The only allowed methods for function 'apply_decay' are: {_valid_methods}"
)
Expand Down Expand Up @@ -550,7 +568,7 @@ def add_ministeps(
):
# pylint: disable-msg=too-many-branches
# pylint: disable-msg=R0915

# pylint: disable-msg=R1702
debug_print("Add all ministeps:", LogLevel.LEVEL1, user_config.log_level)
ScalingValues.initialize()
# Read all region files used in correlation groups,
Expand Down Expand Up @@ -595,7 +613,12 @@ def add_ministeps(
)
elif impl_type == ErtImplType.FIELD:
assert grid_for_field is not None
_decay_methods_fields = ["gaussian_decay", "exponential_decay"]
_decay_methods_group1 = ["gaussian_decay", "exponential_decay"]
_decay_methods_group2 = [
"const_gaussian_decay",
"const_exponential_decay",
]
_decay_methods_all = _decay_methods_group1 + _decay_methods_group2
if corr_spec.field_scale is not None:
debug_print(
"Scale field parameter correlations using method: "
Expand All @@ -609,13 +632,17 @@ def add_ministeps(
data_size2 = field_config.get_data_size()
assert data_size == data_size2
param_for_field = None
if corr_spec.field_scale.method in _decay_methods_fields:
if corr_spec.field_scale.method in _decay_methods_all:
ref_pos = corr_spec.field_scale.ref_point
main_range = corr_spec.field_scale.main_range
perp_range = corr_spec.field_scale.perp_range
azimuth = corr_spec.field_scale.azimuth
use_cutoff = corr_spec.field_scale.set_to_zero_outside_range
tapering_range = corr_spec.field_scale.normalised_tapering_range
use_cutoff = corr_spec.field_scale.cutoff
tapering_range = None
if corr_spec.field_scale.method in _decay_methods_group2:
tapering_range = (
corr_spec.field_scale.normalised_tapering_range
)
check_if_ref_point_in_grid(ref_pos, grid_for_field)
param_for_field = apply_decay(
corr_spec.field_scale.method,
Expand Down Expand Up @@ -697,7 +724,14 @@ def add_ministeps(
user_config.log_level,
)
elif impl_type == ErtImplType.SURFACE:
_decay_methods_surf = ["gaussian_decay", "exponential_decay"]
_decay_methods_surf_group1 = ["gaussian_decay", "exponential_decay"]
_decay_methods_surf_group2 = [
"const_gaussian_decay",
"const_exponential_decay",
]
_decay_methods_surf_all = (
_decay_methods_surf_group1 + _decay_methods_surf_group2
)
if corr_spec.surface_scale is not None:
surface_file = corr_spec.surface_scale.surface_file
debug_print(
Expand All @@ -715,15 +749,17 @@ def add_ministeps(
surface = Surface(surface_file)
data_size = surface.getNX() * surface.getNY()
row_scaling = ministep.row_scaling(node_name)
if corr_spec.surface_scale.method in _decay_methods_surf:
if corr_spec.surface_scale.method in _decay_methods_surf_all:
ref_pos = corr_spec.surface_scale.ref_point
main_range = corr_spec.surface_scale.main_range
perp_range = corr_spec.surface_scale.perp_range
azimuth = corr_spec.surface_scale.azimuth
use_cutoff = corr_spec.surface_scale.set_to_zero_outside_range
tapering_range = (
corr_spec.surface_scale.normalised_tapering_range
)
use_cutoff = corr_spec.surface_scale.cutoff
tapering_range = None
if corr_spec.surface_scale.method in _decay_methods_surf_group2:
tapering_range = (
corr_spec.surface_scale.normalised_tapering_range
)
apply_decay(
corr_spec.surface_scale.method,
row_scaling,
Expand Down Expand Up @@ -795,9 +831,6 @@ class Decay:
main_range: float
perp_range: float
azimuth: float
use_one_in_range: bool
normalised_tapering_range: float
use_cutoff: bool
grid: object

def __post_init__(self):
Expand Down Expand Up @@ -825,50 +858,69 @@ def get_dx_dy(self, data_index):

def norm_dist_square(self, data_index):
dx, dy = self.get_dx_dy(data_index)
d2 = dx * dx + dy * dy
d2 = dx**2 + dy**2
return d2


@dataclass
class GaussianDecay(Decay):
cutoff: bool

def __call__(self, data_index):
d2 = super().norm_dist_square(data_index)
if self.use_one_in_range:
d = math.sqrt(d2)
if d <= 1.0:
return 1.0
if self.use_cutoff and d > self.normalised_tapering_range:
return 0.0
if self.cutoff and d2 > 1.0:
return 0.0
exp_arg = -3.0 * d2
return math.exp(exp_arg)

distance_from_inner_ellipse = (d - 1) / (self.normalised_tapering_range - 1)
exp_arg = -3 * distance_from_inner_ellipse * distance_from_inner_ellipse
return math.exp(exp_arg)

else:
if self.use_cutoff and d2 > 1.0:
return 0.0
exp_arg = -3.0 * d2
return math.exp(exp_arg)
@dataclass
class ConstGaussianDecay(Decay):
normalised_tapering_range: float
cutoff: bool

def __call__(self, data_index):
d2 = super().norm_dist_square(data_index)
d = math.sqrt(d2)
if d <= 1.0:
return 1.0
if self.cutoff and d > self.normalised_tapering_range:
return 0.0

distance_from_inner_ellipse = (d - 1) / (self.normalised_tapering_range - 1)
exp_arg = -3 * distance_from_inner_ellipse**2
return math.exp(exp_arg)


@dataclass
class ExponentialDecay(Decay):
cutoff: bool

def __call__(self, data_index):
d2 = super().norm_dist_square(data_index)
d = math.sqrt(d2)
if self.use_one_in_range:
if d <= 1.0:
return 1.0
if self.use_cutoff and d > self.normalised_tapering_range:
return 0.0
if self.cutoff and d > 1.0:
return 0.0
exp_arg = -3.0 * d
return math.exp(exp_arg)

distance_from_inner_ellipse = (d - 1) / (self.normalised_tapering_range - 1)
exp_arg = -3 * distance_from_inner_ellipse
return math.exp(exp_arg)

else:
if self.use_cutoff and d > 1.0:
return 0.0
exp_arg = -3.0 * d
return math.exp(exp_arg)
@dataclass
class ConstExponentialDecay(Decay):
normalised_tapering_range: float
cutoff: bool

def __call__(self, data_index):
d2 = super().norm_dist_square(data_index)
d = math.sqrt(d2)
if d <= 1.0:
return 1.0
if self.cutoff and d > self.normalised_tapering_range:
return 0.0

distance_from_inner_ellipse = (d - 1) / (self.normalised_tapering_range - 1)
exp_arg = -3 * distance_from_inner_ellipse
return math.exp(exp_arg)


class ScalingValues:
Expand Down
Loading

0 comments on commit 2d486df

Please sign in to comment.