Loop3D / LoopStructural

LoopStructural is an open-source 3D structural geological modelling library.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] unstable model evaluation error

gpirot opened this issue · comments

Describe your issue

When adding a slippling fault perturbation to a dataset it creates some instabilities when evaluating the the model for its stratigraphy on a regular grid. When the fault slip is set to 0, the evaluation runs without problem. When the faultslip is set to 1500, then have a value error as described below.
The data perturbation basically moves all data points on on side of the fault by the faultslip along the slip vector.

stability-test.zip

Minimal reproducing code example

A notebook example.ipynb is provided in the zip file.

To check for the change of behavior,  update the following parameter in the first code cell
# PARAM FAULT 12627 DISPLACEMENT
dispF12627=1500 # 0 or 1500

The third code cell is the one with an unstable behavior

Error message

data.loc[groupSix,"scalar_field"] = model.evaluate_feature_value('stratigraphy',xyzS,scale=True)#,scale=True)

data.loc[groupSix,"scalar_field"] = model.evaluate_feature_value('stratigraphy',xyzS,scale=True)#,scale=True)
​
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-874a38232180> in <module>
----> 1 data.loc[groupSix,"scalar_field"] = model.evaluate_feature_value('stratigraphy',xyzS,scale=True)#,scale=True)

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\core\geological_model.py in evaluate_feature_value(self, feature_name, xyz, scale)
   1470             if scale:
   1471                 scaled_xyz = self.scale(xyz,inplace=False)
-> 1472             return feature.evaluate_value(scaled_xyz)
   1473         else:
   1474             return np.zeros(xyz.shape[0])

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature.py in evaluate_value(self, evaluation_points)
    124         #if evaluation_points is not a numpy array try and convert
    125         #otherwise error
--> 126         self.builder.up_to_date()
    127         # check if the points are within the display region
    128         v = np.zeros(evaluation_points.shape[0])

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in up_to_date(self)
     88         #has anything changed in the builder since we built the feature? if so update
     89         if self._up_to_date == False:
---> 90             self.update()
     91         #check if the interpolator is up to date, if not solve
     92         if self._interpolator.up_to_date == False:

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in update(self)
     77 
     78     def update(self):
---> 79         self.build(**self.build_arguments)
     80     @property
     81     def name(self):

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in build(self, fold, fold_weights, data_region, **kwargs)
    405 
    406 
--> 407         self.add_data_to_interpolator(**kwargs)
    408         if data_region is not None:
    409             xyz = self.interpolator.get_data_locations()

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in add_data_to_interpolator(self, constrained, force_constrained, **kwargs)
    172         for f in self.faults:
    173             data.loc[:,xyz_names()] = f.apply_to_points(
--> 174                 self.get_data_locations())
    175         # Now check whether there are enough constraints for the
    176         # interpolator to be able to solve

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\fault\fault_segment.py in apply_to_points(self, points)
    275                 gz_future = executor.submit(self.faultframe.features[2].evaluate_value, newp)
    276                 gx = gx_future.result()
--> 277                 gy = gy_future.result()
    278                 gz = gz_future.result()
    279         else:

C:\ProgramData\Anaconda3\lib\concurrent\futures\_base.py in result(self, timeout)
    426                 raise CancelledError()
    427             elif self._state == FINISHED:
--> 428                 return self.__get_result()
    429 
    430             self._condition.wait(timeout)

C:\ProgramData\Anaconda3\lib\concurrent\futures\_base.py in __get_result(self)
    382     def __get_result(self):
    383         if self._exception:
--> 384             raise self._exception
    385         else:
    386             return self._result

C:\ProgramData\Anaconda3\lib\concurrent\futures\thread.py in run(self)
     55 
     56         try:
---> 57             result = self.fn(*self.args, **self.kwargs)
     58         except BaseException as exc:
     59             self.future.set_exception(exc)

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature.py in evaluate_value(self, evaluation_points)
    124         #if evaluation_points is not a numpy array try and convert
    125         #otherwise error
--> 126         self.builder.up_to_date()
    127         # check if the points are within the display region
    128         v = np.zeros(evaluation_points.shape[0])

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in up_to_date(self)
     88         #has anything changed in the builder since we built the feature? if so update
     89         if self._up_to_date == False:
---> 90             self.update()
     91         #check if the interpolator is up to date, if not solve
     92         if self._interpolator.up_to_date == False:

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in update(self)
     77 
     78     def update(self):
---> 79         self.build(**self.build_arguments)
     80     @property
     81     def name(self):

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in build(self, fold, fold_weights, data_region, **kwargs)
    436                 # try adding very small cg
    437                 kwargs['cgw'] = 0.0
--> 438         self.install_gradient_constraint()
    439         self.install_equality_constraints()
    440         self.interpolator.setup_interpolator(**kwargs)

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in install_gradient_constraint(self)
    249         for g in self._orthogonal_features.values():
    250             feature,w,region,step,B = g
--> 251             vector = feature.evaluate_gradient(self.interpolator.support.barycentre())
    252             vector /= np.linalg.norm(vector,axis=1)[:,None]
    253             element_idx = np.arange(self.interpolator.support.n_elements)

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature.py in evaluate_gradient(self, evaluation_points)
    158 
    159         """
--> 160         self.builder.up_to_date()
    161         v = np.zeros(evaluation_points.shape)
    162         v[:] = np.nan

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in up_to_date(self)
     88         #has anything changed in the builder since we built the feature? if so update
     89         if self._up_to_date == False:
---> 90             self.update()
     91         #check if the interpolator is up to date, if not solve
     92         if self._interpolator.up_to_date == False:

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in update(self)
     77 
     78     def update(self):
---> 79         self.build(**self.build_arguments)
     80     @property
     81     def name(self):

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\modelling\features\geological_feature_builder.py in build(self, fold, fold_weights, data_region, **kwargs)
    438         self.install_gradient_constraint()
    439         self.install_equality_constraints()
--> 440         self.interpolator.setup_interpolator(**kwargs)
    441         self.interpolator.solve_system(**kwargs)
    442         self._up_to_date = True

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\geological_interpolator.py in setup_interpolator(self, **kwargs)
    171         Runs all of the required setting up stuff
    172         """
--> 173         self._setup_interpolator(**kwargs)
    174 
    175     def solve_system(self, **kwargs):

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\piecewiselinear_interpolator.py in _setup_interpolator(self, **kwargs)
     85                                self.n_t, self.n_i, self.propertyname))
     86         self.add_gradient_ctr_pts(self.interpolation_weights['gpw'])
---> 87         self.add_norm_ctr_pts(self.interpolation_weights['npw'])
     88         self.add_ctr_pts(self.interpolation_weights['cpw'])
     89         self.add_tangent_ctr_pts(self.interpolation_weights['tpw'])

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\piecewiselinear_interpolator.py in add_norm_ctr_pts(self, w)
    312                                                   vol[outside, None],
    313                                                   idc[outside],
--> 314                                                   name='norm')
    315 
    316     def add_ctr_pts(self, w=1.0):  # for now weight all value points the same

C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\discrete_interpolator.py in add_constraints_to_least_squares(self, A, B, idc, name)
    181 
    182             self.constraints[name]['A'] =  np.vstack([self.constraints[name]['A'],A])
--> 183             self.constraints[name]['B'] =  np.hstack([self.constraints[name]['B'], B])
    184             self.constraints[name]['idc'] = np.vstack([self.constraints[name]['idc'],
    185                                                 idc])

<__array_function__ internals> in hstack(*args, **kwargs)

C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\shape_base.py in hstack(tup)
    341     # As a special case, dimension 0 of 1-dimensional arrays is "horizontal"
    342     if arrs and arrs[0].ndim == 1:
--> 343         return _nx.concatenate(arrs, 0)
    344     else:
    345         return _nx.concatenate(arrs, 1)

<__array_function__ internals> in concatenate(*args, **kwargs)

ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 1 dimension(s) and the array at index 1 has 2 dimension(s)

Hi Guillaume,

Can you please upload a working example for me?

I get this error when trying to run your notebook.

`---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
113 base_elevation = (np.asarray(stratigraphy.loc[ixunit,'cumulativeThickness'])).flatten() # 'base_elevation' 'cumulativeThickness'
114 ixctc = np.asarray(np.where(contacts["formation"]==unit)).flatten()
--> 115 contacts.loc[ixctc,"val"]=base_elevation
116 contacts.loc[ixctc,"feature_name"]=stratigraphy.loc[ixunit[0],'group']
117 ixori = np.asarray(np.where(orientations["formation"]==unit)).flatten()

/opt/conda/lib/python3.7/site-packages/pandas/core/indexing.py in setitem(self, key, value)
721
722 iloc = self if self.name == "iloc" else self.obj.iloc
--> 723 iloc._setitem_with_indexer(indexer, value, self.name)
724
725 def _validate_key(self, key, axis: int):

/opt/conda/lib/python3.7/site-packages/pandas/core/indexing.py in _setitem_with_indexer(self, indexer, value, name)
1728 if take_split_path:
1729 # We have to operate column-wise
-> 1730 self._setitem_with_indexer_split_path(indexer, value, name)
1731 else:
1732 self._setitem_single_block(indexer, value, name)

/opt/conda/lib/python3.7/site-packages/pandas/core/indexing.py in _setitem_with_indexer_split_path(self, indexer, value, name)
1784
1785 raise ValueError(
-> 1786 "Must have equal len keys and value "
1787 "when setting with an iterable"
1788 )

ValueError: Must have equal len keys and value when setting with an iterable`

Hi Lachie,
Here is an updated notebook. Sorry about that, I do not have this error on my end, so if it persists, let me know and I will provide directly my processed data.
Cheers

stability-test.zip

Which version of loopstructural are you using? This bug was fixed in 63ea5ec but I have also made another change in 009d2b8 that fix another bug you may have experienced because you don't provide the dimensions of the fault ellipsoid. Can you try updating to the latest commit on master and see if the bug is gone.

Hi Lachie,
I am using version 1.1.0.
I will update my version and check ho it goes.
Cheers

Hi Lachie,
I upgraded to version 1.4.1 and I do not observe these errors anymore, so I will close this issue.
But a set of understandable warnings:

2021-12-09 11:26:17,043 ~ LoopStructural.modelling.core.geological_model ~ WARNING ~ Depreciated method. Model data can now be set using the data attribute
2021-12-09 11:26:17,149 ~ LoopStructural.modelling.core.geological_model ~ WARNING ~ Fault slip vector is nan, estimating from fault normal
2021-12-09 11:26:17,155 ~ LoopStructural.modelling.fault.fault_builder ~ WARNING ~ Fault major axis using map length: 65783.89284117577
2021-12-09 11:26:17,229 ~ LoopStructural.modelling.core.geological_model ~ WARNING ~ Fault slip vector is nan, estimating from fault normal
2021-12-09 11:26:17,235 ~ LoopStructural.modelling.fault.fault_builder ~ WARNING ~ Fault major axis using map length: 97248.09034725242
2021-12-09 11:26:17,305 ~ LoopStructural.modelling.core.geological_model ~ WARNING ~ Fault slip vector is nan, estimating from fault normal
2021-12-09 11:26:17,311 ~ LoopStructural.modelling.fault.fault_builder ~ WARNING ~ Fault major axis using map length: 31228.97524244915

AND a few runtime warnings when my fault slip value is not 0:
WOULD YOU LIKE ME TO OPEN A NEW ISSUE FOR THESE
C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\structured_tetra.py:121: RuntimeWarning: invalid value encountered in greater
inside *= pos[:, i] > self.origin[None, i]
C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\structured_tetra.py:125: RuntimeWarning: invalid value encountered in less

  • self.step_vector[None, i] * self.nsteps_cells[None, i]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\base_structured_3d_support.py:176: RuntimeWarning: invalid value encountered in floor_divide
    ix = ix // self.step_vector[None, 0]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\base_structured_3d_support.py:177: RuntimeWarning: invalid value encountered in floor_divide
    iy = iy // self.step_vector[None, 1]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\base_structured_3d_support.py:178: RuntimeWarning: invalid value encountered in floor_divide
    iz = iz // self.step_vector[None, 2]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\structured_tetra.py:190: RuntimeWarning: invalid value encountered in greater
    mask = np.all(c > 0, axis=2)
    2021-12-09 11:30:04,900 ~ LoopStructural.interpolators.discrete_interpolator ~ WARNING ~ No solution, Fault_12627_2 scalar field 0. Add more data.
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\piecewiselinear_interpolator.py:438: RuntimeWarning: invalid value encountered in true_divide
    vector /= norm[:, None]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\piecewiselinear_interpolator.py:441: RuntimeWarning: divide by zero encountered in true_divide
    element_gradients /= norm[:, None, None]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\piecewiselinear_interpolator.py:441: RuntimeWarning: invalid value encountered in true_divide
    element_gradients /= norm[:, None, None]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\discrete_interpolator.py:183: RuntimeWarning: invalid value encountered in greater
    B[length > 0] /= length[length > 0]
    C:\ProgramData\Anaconda3\lib\site-packages\LoopStructural\interpolators\discrete_interpolator.py:187: RuntimeWarning: invalid value encountered in greater
    A[length > 0, :] /= length[length > 0, None]