diff --git a/docs/user/localization/index.rst b/docs/user/localization/index.rst index 47ad720563..81be998cea 100644 --- a/docs/user/localization/index.rst +++ b/docs/user/localization/index.rst @@ -1,4 +1,3 @@ - Keywords for the local configuration file ========================================= @@ -7,8 +6,8 @@ Keywords for the local configuration file General overview ---------------- -To create a configuration for localization you must "program" your own -local config commands by writing a Python script, and invoking it from a workflow. +To create a configuration for localization you must *"program"* your own local +config commands by writing a Python script, and invoking it from a workflow. **Local config python script example:** @@ -16,587 +15,765 @@ local config commands by writing a Python script, and invoking it from a workflo :: from ert.enkf import ErtScript - from ert.enkf import LocalConfig, LocalObsdata, LocalObsdataNode, LocalMinistep, LocalUpdateStep, LocalDataset, ActiveList + from ert.enkf import (LocalConfig, LocalObsdata, LocalObsdataNode, + LocalMinistep, LocalUpdateStep, LocalDataset, ActiveList) from ert.ecl import EclGrid, EclRegion, Ecl3DKW, EclFile, EclInitFile, EclKW, EclTypeEnum class LocalConfigJob(ErtScript): - - + def run(self): - + # This example can be used with the REEK data set from the ERT tutorial - + # Get the ert object ert = self.ert() - + # Get local config object local_config = ert.getLocalConfig() - - # Reset internal local config structure. From now you need to specify what to localize + + # Reset internal local config structure. From now you need to + # specify what to localize local_config.clear() - + # There is only one update step updatestep = local_config.getUpdatestep() - + # A ministep - ministep = local_config.createMinistep("MINISTEP" ) - + ministep = local_config.createMinistep("MINISTEP" ) + # Add some dataset you want to localize here. dataset_multflt = local_config.createDataset("DATASET_MULTFLT") - + # Add some field and localize inside a box data_poro = local_config.createDataset("DATA_PORO") ecl_grid = local_config.getGrid() ecl_region = EclRegion(ecl_grid, False) - ecl_region.select_box((0,0,0),(3,3,3)) + ecl_region.select_box((0,0,0), (3,3,3)) data_poro.addField("PORO", ecl_region) - - + + # Add some index from MULTFLT to the dataset dataset_multflt.addNode("MULTFLT") active_list = dataset_multflt.getActiveList("MULTFLT") active_list.addActiveIndex(0) - - # Add existing observations from WOPR:OP_1. Alternatively, use getObservations and filter the observations you want to use for this ministep. + + # Add existing observations from WOPR:OP_1. Alternatively, use + # getObservations and filter the observations you want to use + # for this ministep. obsdata_wopr = local_config.createObsdata("WOPR:OP_1_10") - for i in range(1,10): - obsdata_wopr.addNode("OBS"+str(i)) - + for i in range(1, 10): + obsdata_wopr.addNode("OBS" + str(i)) + # Attach the created dataset and obsset to the ministep ministep.attachDataset(dataset_multflt) ministep.attachObsset(obsdata_wopr) - + # Then attach the ministep to the update step updatestep.attachMinistep(ministep) - - # Write a .csv file for debugging. The generated file can be imported into Excel for better tabulation of the setup - local_config.writeSummaryFile("tmp/summary_local_config.csv") -=========================================================================================== ============================================================================================================================================== -ERT script function Purpose -=========================================================================================== ============================================================================================================================================== -:ref:`getObservations ` Get the observations currently imported, use to filter the observations to localize -:ref:`getGrid ` Get the underlying grid use to define active cells in a field -:ref:`getUpdatestep ` Creates and gets default updatestep -:ref:`createMinistep ` Creates ministep -:ref:`createDataset ` Creates dataset -:ref:`copyDataset ` Deep copy of dataset -:ref:`createObsdata ` Creates observation set -:ref:`copyObsdata ` Deep copy of observation set -:ref:`attachMinistep ` Attaches ministep to update step -:ref:`attachDataset ` Attaches dataset to mini step -:ref:`attachObsset ` Attaches observation set to mini step -:ref:`addNode ` Adds data node to dataset -:ref:`del (data) ` Deletes observation node from dataset -:ref:`addNode, addNodeAndRange ` Adds observation node to observation set for all times or in a given time range -:ref:`del (obs) ` Deletes observation node from observation set -:ref:`clear ` Delete all the data keys from a dataset -:ref:`addActiveIndex (data) ` Adds several data indices to the list of active indices -:ref:`addActiveIndex (obs) ` Adds several observation indices to the list of active indices -:ref:`addField ` Adds field node to dataset -:ref:`EclGrid, EclInitFile ` Loads eclipse file in restart format -:ref:`EclRegion ` Creates a new region for use when defining active regions for fields -:ref:`select_active ` Selects or deselects cells in a region -:ref:`select_equal ` Selects or deselects cells in a region equal to given value -:ref:`select_less ` Selects or deselects cells in a region equal less than a given value -:ref:`select_more ` Selects or deselects cells in a region equal greater than a given value -:ref:`select_box ` Selects or deselects cells in a box -:ref:`select_islice, _jslice,_kslice ` Selects or deselects cells in a slice -:ref:`select_below_plane ` Selects or deselects cells in a half space defined by a plane -:ref:`select_inside_polygon ` Selects or deselects cells in region inside polygon -:ref:`Example create polygon ` Creates a geo-polygon based on coordinate list -:ref:`Example load polygon ` Loads polygon in Irap RMS format from file - -=========================================================================================== ============================================================================================================================================== - - -.. ########################################################################################################### + # Write a .csv file for debugging. The generated file can be imported + # into Excel for better tabulation of the setup + local_config.writeSummaryFile("tmp/summary_local_config.csv") +========================================================================= =================================================================================== +ERT script function Purpose +========================================================================= =================================================================================== +:ref:`getObservations ` Get the observations currently imported, use to filter the observations to localize +:ref:`getGrid ` Get the underlying grid use to define active cells in a field +:ref:`getUpdatestep ` Creates and gets default updatestep +:ref:`createMinistep ` Creates ministep +:ref:`createDataset ` Creates dataset +:ref:`copyDataset ` Deep copy of dataset +:ref:`createObsdata ` Creates observation set +:ref:`copyObsdata ` Deep copy of observation set +:ref:`attachMinistep ` Attaches ministep to update step +:ref:`attachDataset ` Attaches dataset to mini step +:ref:`attachObsset ` Attaches observation set to mini step +:ref:`addNode ` Adds data node to dataset +:ref:`del (data) ` Deletes observation node from dataset +:ref:`addNode, addNodeAndRange ` Adds observation node to observation set for all times or in a given time range +:ref:`del (obs) ` Deletes observation node from observation set +:ref:`clear ` Delete all the data keys from a dataset +:ref:`addActiveIndex (data) ` Adds several data indices to the list of active indices +:ref:`addActiveIndex (obs) ` Adds several observation indices to the list of active indices +:ref:`addField ` Adds field node to dataset +:ref:`EclGrid, EclInitFile ` Loads eclipse file in restart format +:ref:`EclRegion ` Creates a new region for use when defining active regions for fields +:ref:`select_active ` Selects or deselects cells in a region +:ref:`select_equal ` Selects or deselects cells in a region equal to given value +:ref:`select_less ` Selects or deselects cells in a region equal less than a given value +:ref:`select_more ` Selects or deselects cells in a region equal greater than a given value +:ref:`select_box ` Selects or deselects cells in a box +:ref:`select_islice, _jslice,_kslice ` Selects or deselects cells in a slice +:ref:`select_below_plane ` Selects or deselects cells in a half space defined by a plane +:ref:`select_inside_polygon ` Selects or deselects cells in region inside polygon +:ref:`Example create polygon ` Creates a geo-polygon based on coordinate list +:ref:`Example load polygon ` Loads polygon in Irap RMS format from file +:ref:`Load surface from IRAP file ` Create a polygon from IRAP file +:ref:`Select polygon from surface ` Selects the inside of a polygon from a surface +:ref:`Select halfspace from surface ` Selects above or below a line from a surface +:ref:`Add a surface to dataset ` Add a surface node to a dataset +========================================================================= =================================================================================== + + +.. ##################################################################### .. _create_updatestep: .. topic:: getUpdatestep - | This function will create the default updatestep. - | Observe that you must get, otherwise it will not be able to do anything. - - *Example:* + This function will create the default ``updatestep``. + + Observe that you must get, otherwise it will not be able to do anything. + + *Example:* - :: - - updatestep = local_config.getUpdatestep() + :: -.. ########################################################################################################### + updatestep = local_config.getUpdatestep() + +.. ##################################################################### .. _all_obs: .. topic:: getObservations - | This function will retrieve ERT's observations - - *Example:* + This function will retrieve ERT's observations + + *Example:* - :: - - all_obs = local_config.getObservations() + :: -.. ########################################################################################################### + all_obs = local_config.getObservations() + +.. ##################################################################### .. _ert_grid: .. topic:: getGrid - | This function will retrieve ERT's grid - - *Example:* + This function will retrieve ERT's grid + + *Example:* - :: - - grid = local_config.getGrid() + :: -.. ########################################################################################################### + grid = local_config.getGrid() +.. ##################################################################### .. _create_ministep: -.. topic:: createMinistep +.. topic:: createMinistep - | This function will create a new ministep with a given name and an optional analysis module. The default analysis module for this ministep is ERT's current analysis module. - | A given observation set can be attached to a given ministep with attachObsset.The ministep is then ready for adding data. Before the ministep can be used you must attach it to an updatestep with the attachMinistep command - - *Example:* + This function will create a new ``ministep`` with a given name and an + optional analysis module. The default analysis module for this ``ministep`` + is ERT's current analysis module. - :: - - ministep = local_config.createMinistep("MINISTEP") + A given observation set can be attached to a given ``ministep`` with + ``attachObsset``. The ``ministep`` is then ready for adding data. Before + the ``ministep`` can be used you must attach it to an ``updatestep`` with the + ``attachMinistep`` command - *Example:* + *Example:* - :: + :: - analysis_config = ert.analysisConfig() - std_enkf_analysis_module = analysis_config.getModule("STD_ENKF") - ministep_using_std_enkf = local_config.createMinistep("MINISTEP", std_enkf_analysis_module) + ministep = local_config.createMinistep("MINISTEP") + *Example:* -.. ########################################################################################################### + :: + analysis_config = ert.analysisConfig() + std_enkf_analysis_module = analysis_config.getModule("STD_ENKF") + ministep_using_std_enkf = local_config.createMinistep("MINISTEP", std_enkf_analysis_module) + + +.. ##################################################################### .. _create_dataset: .. topic:: createDataset - | This function will create a new dataset with a given name, i.e. a collection of enkf_nodes which should be updated together. Before you can actually use a dataset you must attach it to a ministep with the attachDataset command. - + This function will create a new ``dataset`` with a given name, i.e., a + collection of ``enkf_nodes`` which should be updated together. Before you + can actually use a ``dataset`` you must attach it to a ``ministep`` with the + ``attachDataset`` command. - *Example:* - :: + *Example:* - dataset_multflt = local_config.createDataset("DATASET_MULTFLT") + :: -.. ########################################################################################################### + dataset_multflt = local_config.createDataset("DATASET_MULTFLT") + +.. ##################################################################### .. _copy_dataset: .. topic:: copyDataset - | Will create a new local_obsset instance which is a copy of the - source dataset; this is a deep copy where also the lowest level active_list instances are copied, and can then subsequently be updated independently of each other. + Will create a new ``local_obsset`` instance which is a copy of the source + ``dataset``; this is a deep copy where also the lowest level active_list + instances are copied, and can then subsequently be updated independently of + each other. - *Example:* + *Example:* - :: + :: - dataset_multflt_copy = local_config.copyDataset("DATASET_MULTFLT","DATASET_MULTFLT_COPY") + dataset_multflt_copy = local_config.copyDataset("DATASET_MULTFLT", + "DATASET_MULTFLT_COPY") -.. ########################################################################################################### +.. ##################################################################### .. _create_obsset: .. topic:: createObsdata - | This function will create an observation set, i.e. a collection of observation keys which will be used as the observations in one ministep. Before the obsset can be used it must be attached to a ministep with the attachDataset command. - - - *Example:* + This function will create an observation set, i.e., a collection of + observation keys which will be used as the observations in one ``ministep``. + Before the ``obsset`` can be used it must be attached to a ``ministep`` with + the ``attachDataset`` command. + - :: + *Example:* - obsset_obs_well = local_config.createObsdata("OBS_WELL") + :: + obsset_obs_well = local_config.createObsdata("OBS_WELL") -.. ########################################################################################################### +.. ##################################################################### .. _copy_obsset: .. topic:: copyObsdata - | Will create a new local_obsset instance which is a copy of the - source dataset; this is a deep copy where also the lowest level active_list instances are copied, and can then subsequently be updated independently of each other. - + Will create a new ``local_obsset`` instance which is a copy of the source + ``dataset``; this is a deep copy where also the lowest level ``active_list`` + instances are copied, and can then subsequently be updated independently of + each other. - *Example:* - :: + *Example:* - obsset_obs_well_copy = local_config.copyObsdata("OBS_WELL", "OBS_WELL_COPY") + :: -.. ########################################################################################################### + obsset_obs_well_copy = local_config.copyObsdata("OBS_WELL", "OBS_WELL_COPY") + +.. ##################################################################### .. _attach_ministep: .. topic:: attachMinistep - | This function will attach the ministep to the default updatestep. - - *Example:* + This function will attach the ``ministep`` to the default ``updatestep``. - :: + *Example:* - update_step.attachMinistep(ministep) + :: + update_step.attachMinistep(ministep) -.. ########################################################################################################### +.. ##################################################################### .. _attach_dataset: .. topic:: attachDataset - | Will attach the given dataset to the ministep. - + Will attach the given ``dataset`` to the ``ministep``. - *Example:* - :: + *Example:* - ministep.attachDataset(dataset_multflt) + :: + ministep.attachDataset(dataset_multflt) -.. ########################################################################################################### +.. ##################################################################### .. _attach_obsset: .. topic:: attachObsset - | Will attach the given obsset to the ministep. - - *Example:* + Will attach the given ``obsset`` to the ``ministep``. - :: + *Example:* - ministep.attachObsset(obsset_obs_well) + :: + ministep.attachObsset(obsset_obs_well) -.. ########################################################################################################### +.. ##################################################################### .. _add_data: .. topic:: addNode - | This function will add the data KEY as one enkf node which should be updated in this dataset. If you do not manipulate the KEY further with addActiveIndex, the KEY will be added as 'ALL_ACTIVE', i.e. all elements will be updated. - - - *Example:* + This function will add the data ``KEY`` as one *enkf* node which should be + updated in this dataset. If you do not manipulate the ``KEY`` further with + ``addActiveIndex``, the ``KEY`` will be added as ``ALL_ACTIVE``, i.e., all + elements will be updated. - :: - dataset_multflt.addNode("MULTFLT") + *Example:* -.. ########################################################################################################### + :: + dataset_multflt.addNode("MULTFLT") + + +.. ##################################################################### .. _del_data: .. topic:: del (data) - | This function will delete the data 'KEY' from the dataset. - - - *Example:* + This function will delete the data ``KEY`` from the dataset. - :: - del dataset_multflt["MULTFLT"] + *Example:* + :: -.. ########################################################################################################### + del dataset_multflt["MULTFLT"] + +.. ##################################################################### .. _add_obs: .. topic:: addNode - | This function will install the observation 'OBS_KEY' as an observation for this obsset - similarly to the addNode function. - - *Example:* + This function will install the observation ``OBS_KEY`` as an observation for + this ``obsset`` --- similarly to the ``addNode`` function. + + *Example:* - :: - - -- The obsset has a time range - obsset_obs_well.addNodeAndRange("WOPR:OBS_WELL", 0, 1) - - -- All times are active - obsset_obs_well.addNode("WOPR:OBS_WELL") + :: + # The obsset has a time range + obsset_obs_well.addNodeAndRange("WOPR:OBS_WELL", 0, 1) -.. ########################################################################################################### + # All times are active + obsset_obs_well.addNode("WOPR:OBS_WELL") + +.. ##################################################################### .. _del_obs: .. topic:: del (obs) - | This function will delete the obs 'OBS_KEY' from the obsset 'NAME_OF_OBSSET'. - - - *Example:* + This function will delete the obs ``OBS_KEY`` from the ``obsset`` + ``NAME_OF_OBSSET``. + - :: + *Example:* - del obsset_obs_well["WOPR:OBS_WELL"] + :: + del obsset_obs_well["WOPR:OBS_WELL"] -.. ########################################################################################################### +.. ##################################################################### .. _dataset_del_all_data: .. topic:: clear - | This function will delete all the data keys from the dataset. - - *Example:* + This function will delete all the data keys from the ``dataset``. + + *Example:* + + :: - :: + dataset_multflt.clear() - dataset_multflt.clear() - -.. ########################################################################################################### +.. ##################################################################### .. _active_list_add_data_index: .. topic:: addActiveIndex (data) - | This function will say that the data with name 'DATA_KEY' in dataset with name 'DATASTEP_NAME' should have the index 'INDEX' active. - - - *Example:* + This function will say that the data with name ``DATA_KEY`` in ``dataset`` + with name ``DATASTEP_NAME`` should have the index ``INDEX`` active. - :: - active_list = dataset_multflt.getActiveList("MULTFLT") - active_list.addActiveIndex(0); + *Example:* -.. ########################################################################################################### + :: + + active_list = dataset_multflt.getActiveList("MULTFLT") + active_list.addActiveIndex(0); + +.. ##################################################################### .. _active_list_add_obs_index: .. topic:: addActiveIndex (obs) - | This function will say that the observation with name 'OBS_KEY' in obsset with name 'OBSSET_NAME' should have the index 'INDEX' active. - - *Example:* + This function will say that the observation with name ``OBS_KEY`` in + ``obsset`` with name ``OBSSET_NAME`` should have the index ``INDEX`` active. - :: + *Example:* - active_list = obsset_obs_well.getActiveList("WOPR:OBS_WELL") - active_list.addActiveIndex(0); + :: + active_list = obsset_obs_well.getActiveList("WOPR:OBS_WELL") + active_list.addActiveIndex(0); -.. ########################################################################################################### + +.. ##################################################################### .. _add_field: .. topic:: addField - | This function will install the node with name 'FIELD_NAME' in the dataset 'DATASET_NAME'. It will in addition select all the (currently) active cells in the region 'ECLREGION_NAME' as active for this field/ministep combination. The ADD_FIELD command is actually a shortcut of: ADD_DATA DATASET FIELD_NAME; followed by: ACTIVE_LIST_ADD_MANY_DATA_INDEX - - *Example:* - - :: - - # Load Eclipse grid - ecl_grid = EclGrid("path/to/LOCAL.GRDECL") - - with open("path/to/LOCAL.GRDECL","r") as fileH: - local_kw = Ecl3DKW.read_grdecl(ecl_grid, fileH, "LOCAL") - - # Define Eclipse region - eclreg_poro = EclRegion(ecl_grid, False) - eclreg_poro.select_more(local_kw, 1) - - # Create dataset and add field to dataset - data_poro = local_config.createDataset("DATA_PORO") - data_poro.addField("PORO", eclreg_poro) - - -.. ########################################################################################################### + This function will install the node with name ``FIELD_NAME`` in the + ``dataset`` ``DATASET_NAME``. It will in addition select all the (currently) + active cells in the region ``ECLREGION_NAME`` as active for this + ``field``/``ministep`` combination. The ``ADD_FIELD`` command is actually a + shortcut of: + + ``ADD_DATA DATASET FIELD_NAME``; + + followed by: + + ``ACTIVE_LIST_ADD_MANY_DATA_INDEX `` + + *Example:* + :: + + # Load Eclipse grid + ecl_grid = EclGrid("path/to/LOCAL.GRDECL") + + with open("path/to/LOCAL.GRDECL","r") as grdecl_file: + local_kw = Ecl3DKW.read_grdecl(ecl_grid, grdecl_file, "LOCAL") + + # Define Eclipse region + eclreg_poro = EclRegion(ecl_grid, False) + eclreg_poro.select_more(local_kw, 1) + + # Create dataset and add field to dataset + data_poro = local_config.createDataset("DATA_PORO") + data_poro.addField("PORO", eclreg_poro) + + +.. ##################################################################### .. _load_file: .. topic:: EclGrid, EclInitFile - | This function will load an ECLIPSE file in restart format (i.e. restart file or INIT file), the keywords in this file can then subsequently be used in ECLREGION_SELECT_VALUE_XXX commands below. The 'KEY' argument is a string which will be used later when we refer to the content of this file. - - *Example:* + This function will load an ECLIPSE file in restart format (i.e., *restart + file* or *INIT file*), the keywords in this file can then subsequently be + used in ``ECLREGION_SELECT_VALUE_XXX`` commands below. The ``KEY`` argument + is a string which will be used later when we refer to the content of this + file. + + *Example:* - :: - - # Load Eclipse grid and init file - ecl_grid = EclGrid("path/to/FULLMODEL.GRDECL") - refinit_file = EclInitFile(grid , "path/to/somefile.init") + :: -.. ########################################################################################################### + # Load Eclipse grid and init file + ecl_grid = EclGrid("path/to/FULLMODEL.GRDECL") + refinit_file = EclInitFile(grid , "path/to/somefile.init") + +.. ##################################################################### .. _create_eclregion: .. topic:: EclRegion - | This function will create a new region 'ECLREGION_NAME', which can subsequently be used when defining active regions for fields. The second argument, SELECT_ALL, is a boolean value. If this value is set to true the region will start with all cells selected, if set to false the region will start with no cells selected. - - *Example:* + This function will create a new region ``ECLREGION_NAME``, which can + subsequently be used when defining active regions for fields. The second + argument, ``SELECT_ALL``, is a *boolean* value. If this value is set to true + the region will start with all cells selected, if set to false the region + will start with no cells selected. + + *Example:* - :: - - # Define Eclipse region - eclreg_poro = EclRegion(ecl_grid, False) + :: -.. ########################################################################################################### + # Define Eclipse region + eclreg_poro = EclRegion(ecl_grid, False) + +.. ##################################################################### .. _eclregion_select_all: .. topic:: select_active - | Will select all the cells in the region (or deselect if SELECT == FALSE). - + Will select (or deselect) all the cells in the region. + - *Example:* + *Example:* - :: - - eclreg_poro.select_active() + :: + eclreg_poro.select_active() + eclreg_poro.deselect_active() -.. ########################################################################################################### +.. ##################################################################### .. _eclregion_select_value_equal: .. topic:: select_equal - | This function will compare an ecl_kw instance loaded from file with a user supplied value, and select (or deselect) all cells which match this value. It is assumed that the ECLIPSE keyword is an INTEGER keyword, for float comparisons use the ECLREGION_SELECT_VALUE_LESS and ECLREGION_SELECT_VALUE_MORE functions. - - *Example:* - - :: - - # Load Eclipse grid - ecl_grid = EclGrid("path/to/LOCAL.GRDECL") - - with open("path/to/LOCAL.GRDECL","r") as fileH: - local_kw = Ecl3DKW.read_grdecl(ecl_grid, fileH, "LOCAL", ecl_type= EclTypeEnum.ECL_INT_TYPE) - - # Define Eclipse region - eclreg_poro = EclRegion(ecl_grid, False) - eclreg_poro.select_equal(local_kw, 1) - print 'GRID LOADED%s' % ecl_grid - print ecl_grid.getDims() - print local_kw.header - - - -.. ########################################################################################################### + This function will compare an ``ecl_kw`` instance loaded from file with a + user supplied value, and select (or deselect) all cells which match this + value. It is assumed that the ECLIPSE keyword is an INTEGER keyword, for + float comparisons use the ``ECLREGION_SELECT_VALUE_LESS`` and + ``ECLREGION_SELECT_VALUE_MORE`` functions. + + *Example:* + + :: + + # Load Eclipse grid + ecl_grid = EclGrid("path/to/LOCAL.GRDECL") + with open("path/to/LOCAL.GRDECL","r") as grdecl_file: + local_kw = Ecl3DKW.read_grdecl(ecl_grid, grdecl_file, "LOCAL", + ecl_type=EclTypeEnum.ECL_INT_TYPE) + + # Define Eclipse region + eclreg_poro = EclRegion(ecl_grid, False) + eclreg_poro.select_equal(local_kw, 1) + print('GRID LOADED: %s' % ecl_grid) + print(ecl_grid.getDims()) + print(local_kw.header) + + +.. ##################################################################### .. _eclregion_select_value_less: .. topic:: select_less - | This function will compare an ecl_kw instance loaded from disc with a numerical value, and select all cells which have numerical below the limiting value. The ecl_kw value should be a floating point value like e.g. PRESSURE or PORO. The arguments are just as for ECLREGION_SELECT_VALUE_EQUAL. + This function will compare an ``ecl_kw`` instance loaded from disc with a + numerical value, and select all cells which have numerical below the limiting + value. The ``ecl_kw`` value should be a floating point value like e.g., + ``PRESSURE`` or ``PORO``. The arguments are just as for + ``ECLREGION_SELECT_VALUE_EQUAL``. + + *Example:* - *Example:* + :: - :: - - eclreg_poro.select_less(local_kw, 1) - - -.. ########################################################################################################### + eclreg_poro.select_less(local_kw, 1) + +.. ##################################################################### .. _eclregion_select_value_more: .. topic:: select_more - | This function will compare an ecl_kw instance loaded from disc with a numerical value, and select all cells which have numerical above the limiting value. The ecl_kw value should be a floating point value like e.g. PRESSURE or PORO. The arguments are just as for ECLREGION_SELECT_VALUE_EQUAL. - + This function will compare an ``ecl_kw`` instance loaded from disc with a + numerical value, and select all cells which have numerical above the limiting + value. The ``ecl_kw`` value should be a floating point value like e.g., + ``PRESSURE`` or ``PORO``. The arguments are just as for + ``ECLREGION_SELECT_VALUE_EQUAL``. + + + *Example:* + + :: - *Example:* + eclreg_poro.select_more(local_kw, 1) - :: - - eclreg_poro.select_more(local_kw, 1) - -.. ########################################################################################################### +.. ##################################################################### .. _eclregion_select_box: .. topic:: select_box - | This function will select (or deselect) all the cells in the box defined by the six coordinates i1 i2 j1 j2 k1 k2. The coordinates are inclusive, and the counting starts at 1. - + This function will select (or deselect) all the cells in the box defined by + the six coordinates ``i1 i2 j1 j2 k1 k2``. The coordinates are inclusive, + and the counting starts at 1. - *Example:* - :: - - eclreg_poro.select_box((0,2,4),(1,3,5)) - + *Example:* + :: -.. ########################################################################################################### + eclreg_poro.select_box((0,2,4),(1,3,5)) + +.. ##################################################################### .. _eclregion_select_slice: .. topic:: select_islice, _jslice,_kslice - | This function will select a slice in the direction given by 'dir', which can 'x', 'y' or 'z'. Depending on the value of 'dir' the numbers n1 and n2 are interpreted as (i1 i2), (j1 j2) or (k1 k2) respectively. The numbers n1 and n2 are inclusice and the counting starts at 1. It is OK to use very high/low values to imply "the rest of the cells" in one direction. - - - *Example:* + This function will select a slice in the direction given by ``dir``', which + can ``x``, ``y``, or ``z``. Depending on the value of ``dir`` the numbers + ``n1`` and ``n2`` are interpreted as ``(i1 i2)``, ``(j1 j2)``, or ``(k1 + k2)``, respectively. + + The numbers ``n1`` and ``n2`` are inclusive and the counting starts at 1. It + is OK to use very high/low values to imply *"the rest of the cells"* in one + direction. + + + *Example:* - :: - - eclreg_poro.select_kslice(2,3) + :: + eclreg_poro.select_kslice(2,3) -.. ########################################################################################################### + +.. ##################################################################### .. _eclregion_select_plane: .. topic:: select_below_plane - | Will select all points which have positive (sign > 0) distance to the plane defined by normal vector n = (nx,ny,nz) and point p = (px,py,pz). If sign < 0 all cells with negative distance to plane will be selected. - - *Example:* + Will select all points which have positive (sign > 0) distance to the plane + defined by normal vector ``n = (nx,ny,nz)`` and point ``p = (px,py,pz)``. If + sign < 0 all cells with negative distance to plane will be selected. + + *Example:* - :: - - eclreg_poro.select_below_plane((1,1,1),(0,0,0)) + :: + eclreg_poro.select_below_plane((1,1,1), (0,0,0)) -.. ########################################################################################################### +.. ##################################################################### .. _eclregion_select_in_polygon: .. topic:: select_inside_polygon - | Well select all the points which are inside the polygon with name 'POLYGON_NAME'. The polygon should have been created with command CREATE_POLYGON or loaded with command 'LOAD_POLYGON' first. - - - - *Example:* + Well select all the points which are inside the polygon with name + ``POLYGON_NAME``. The polygon should have been created with command + ``CREATE_POLYGON`` or loaded with command ``LOAD_POLYGON`` first. + - :: - - polygon = [(0,0) , (0,1) , (1,0)] - eclreg_poro.select_inside_polygon(polygon) - -.. ########################################################################################################### + *Example:* + :: + + polygon = [(0,0), (0,1), (1,0)] + eclreg_poro.select_inside_polygon(polygon) + + +.. ##################################################################### .. _create_polygon: .. topic:: Example create polygon - | Will create a geo_polygon instance based on the coordinate list: (x1,y1), (x2,y2), (x3,y3), ... The polygon should not be explicitly closed - i.e. you should in general have (x1,y1) != (xn,yn). The polygon will be stored under the name 'POLYGON_NAME' - which should later be used when referring to the polygon in region select operations. - + Will create a ``geo_polygon`` instance based on the coordinate list: + + ``[(x1,y1), (x2,y2), (x3,y3), ..., (xn,yn)]`` + + The polygon should not be explicitly closed --- i.e., you should in general + have + + ``(x1,y1) != (xn,yn).`` + + The polygon will be stored under the name ``POLYGON_NAME`` --- which should + later be used when referring to the polygon in region select operations. - *Example:* + *Example:* - :: - - polygon = [(0,0) , (0,1) , (1,0)] + :: -.. ########################################################################################################### + polygon = [(0,0), (0,1), (1,0)] + +.. ##################################################################### .. _load_polygon: .. topic:: Example load polygon - | Will load a polygon instance from the file 'FILENAME' - the file should be in irap RMS format. The polygon will be stored under the name 'POLYGON_NAME' which can then later be used to refer to the polygon for e.g. select operations. + Will load a polygon instance from the file ``FILENAME`` --- the file should + be in *irap RMS* format. The polygon will be stored under the name + ``POLYGON_NAME`` which can then later be used to refer to the polygon for + e.g., select operations. + + + *Example:* + + :: + + polygon = [] + with open("polygon.ply", "r") as ply_file: + for line in ply_file: + xs, ys = map(float, line.split()) + polygon.append(xs, ys) + + +.. ##################################################################### +.. _surface__init: +.. topic:: Load surface from IRAP file + + Will load a surface from an *IRAP file*. We can also create a surface + programmatically. It is also possible to obtain the underlying pointset. + + + *Example for creating programmatically:* + + :: + + # values copied from irap surface_small + nx, ny = 30,20 + xinc, yinc = 50.0, 50.0 + xstart, ystart = 463325.5625, 7336963.5 + angle = -65.0 + s_args = (None, nx, ny, xinc, yinc, xstart, ystart, angle) + s = Surface(*s_args) + + *Example loading from file:* + + :: + + surface = Surface('path/to/surface.irap') + # we can also obtain the underlying pointset + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + + +.. ##################################################################### +.. _geo_region__select_polygon: +.. topic:: Select polygon from surface + + Will select or deselect all points from a surface contained inside a given + polygon. + + + *Example:* + + :: + + nx,ny = 12, 12 + xinc,yinc = 1, 1 + xstart,ystart = -1, -1 + angle = 0.0 + s_args = (None, nx, ny, xinc, yinc, xstart, ystart, angle) + surface = Surface(*s_args) # an irap surface + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + points = [(-0.1,2.0), (1.9,8.1), (6.1,8.1), (9.1,5), (7.1,0.9)] + polygon = CPolyline(name='test_polygon', init_points=points) + + georegion.select_inside(polygon) + georegion.select_outside(polygon) + georegion.deselect_inside(polygon) + georegion.select_polygon(polygon, inside=False, select=False) # deselect outside + + +.. ##################################################################### +.. _geo_region__select_halfspace: +.. topic:: Select halfspace from surface + + Will select or deselect all points from a surface above or below a line. + + + *Example:* + + :: + + surface = Surface(...) # an irap surface, see above + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + line = [(-0.1,2.0), (1.9,8.1)] + + georegion.select_above(line) + georegion.deselect_above(line) + georegion.select_below(line) + georegion.select_halfspace(line, above=False, select=False) # deselect below + + +.. ##################################################################### +.. _local_dataset__add_surface: +.. topic:: Add a surface to dataset + + Adds a surface to a local dataset just as one can add a field node to a + dataset (see add_field_). + + + *Example:* - - *Example:* + :: - :: - - polygon = [] - with open("polygon.ply","r") as fileH: - for line in fileH.readlines(): - tmp = line.split() - polygon.append( (float(tmp[0]) , float(tmp[1]))) + main = test_context.getErt() + local_config = main.getLocalConfig() + # Creating dataset + data_scale = local_config.createDataset('DATA_SCALE') + surface = Surface(...) # an irap surface, see above + pointset = surface.getPointset() + georegion = GeoRegion(pointset) + data_scale.addSurface('TOP', georegion) + # similar use to + grid = local_config.getGrid() + eclregion = EclRegion(grid, False) + eclregion.select_islice(10, 20) + data_scale.addField('PERMX', eclregion) diff --git a/python/python/ert/geo/geo_region.py b/python/python/ert/geo/geo_region.py index 05f0a20071..648a0dabc7 100644 --- a/python/python/ert/geo/geo_region.py +++ b/python/python/ert/geo/geo_region.py @@ -16,6 +16,10 @@ from cwrap import BaseCClass from ert.util import IntVector from ert.geo import GeoPrototype +from .cpolyline import CPolyline +from ctypes import c_double + +cpair = c_double * 2 # this is a function that maps two doubles to a double* class GeoRegion(BaseCClass): TYPE_NAME = "geo_region" @@ -23,15 +27,15 @@ class GeoRegion(BaseCClass): _alloc = GeoPrototype("void* geo_region_alloc(geo_pointset, bool)", bind=False) _free = GeoPrototype("void geo_region_free(geo_region)") _reset = GeoPrototype("void geo_region_reset(geo_region)") - #_select_inside_polygon = GeoPrototype("void geo_region_select_inside_polygon(geo_region, geo_polygon)") - #_select_outside_polygon = GeoPrototype("void geo_region_select_outside_polygon(geo_region, geo_polygon)") - #_deselect_inside_polygon = GeoPrototype("void geo_region_deselect_inside_polygon(geo_region, geo_polygon)") - #_deselect_outside_polygon = GeoPrototype("void geo_region_deselect_outside_polygon(geo_region, geo_polygon)") - #_select_above_line = GeoPrototype("void geo_region_select_above_line(geo_region, const double xcoords[2], const double ycoords[2])") - #_select_below_line = GeoPrototype("void geo_region_select_below_line(geo_region, const double xcoords[2], const double ycoords[2])") - #_deselect_above_line = GeoPrototype("void geo_region_deselect_above_line(geo_region, const double xcoords[2], const double ycoords[2])") - #_deselect_below_line = GeoPrototype("void geo_region_deselect_below_line(geo_region, const double xcoords[2], const double ycoords[2])") - _get_index_list = GeoPrototype("int_vector_ref geo_region_get_index_list(geo_region)") + _get_index_list = GeoPrototype("int_vector_ref geo_region_get_index_list(geo_region)") + _select_inside_polygon = GeoPrototype("void geo_region_select_inside_polygon(geo_region, geo_polygon)") + _select_outside_polygon = GeoPrototype("void geo_region_select_outside_polygon(geo_region, geo_polygon)") + _deselect_inside_polygon = GeoPrototype("void geo_region_deselect_inside_polygon(geo_region, geo_polygon)") + _deselect_outside_polygon = GeoPrototype("void geo_region_deselect_outside_polygon(geo_region, geo_polygon)") + _select_above_line = GeoPrototype("void geo_region_select_above_line(geo_region, double*, double*)") + _select_below_line = GeoPrototype("void geo_region_select_below_line(geo_region, double*, double*)") + _deselect_above_line = GeoPrototype("void geo_region_deselect_above_line(geo_region, double*, double*)") + _deselect_below_line = GeoPrototype("void geo_region_deselect_below_line(geo_region, double*, double*)") def __init__(self, pointset, preselect=False): @@ -42,9 +46,65 @@ def __init__(self, pointset, preselect=False): else: raise ValueError('Could not construct GeoRegion from pointset %s.' % pointset) + def getActiveList(self): return self._get_index_list() + def _assert_polygon(self, polygon): + if not isinstance(polygon, CPolyline): + raise ValueError('Need to select with a CPolyline, not %s.' + % type(polygon)) + + + def _construct_cline(self, line): + """Takes a line ((x1,y1), (x2,y2)) and returns two double[2]* but + reordered to (x1x2, y1y2). + """ + try: + p1, p2 = line + x1, y1 = map(float, p1) + x2, y2 = map(float, p2) + except Exception as err: + err_msg = 'Select with pair ((x1,y1), (x2,y2)), not %s (%s).' + raise ValueError(err_msg % (line, err)) + x1x2_ptr = cpair(x1, x2) + y1y2_ptr = cpair(y1, y2) + return x1x2_ptr, y1y2_ptr + + + def select_inside(self, polygon): + self._assert_polygon(polygon) + self._select_inside_polygon(polygon) + + def select_outside(self, polygon): + self._assert_polygon(polygon) + self._select_outside_polygon(polygon) + + def deselect_inside(self, polygon): + self._assert_polygon(polygon) + self._deselect_inside_polygon(polygon) + + def deselect_outside(self, polygon): + self._assert_polygon(polygon) + self._deselect_outside_polygon(polygon) + + + def select_above(self, line): + x_ptr, y_ptr = self._construct_cline(line) + self._select_above_line(x_ptr, y_ptr) + + def select_below(self, line): + x_ptr, y_ptr = self._construct_cline(line) + self._select_below_line(x_ptr, y_ptr) + + def deselect_above(self, line): + x_ptr, y_ptr = self._construct_cline(line) + self._deselect_above_line(x_ptr, y_ptr) + + def deselect_below(self, line): + x_ptr, y_ptr = self._construct_cline(line) + self._deselect_below_line(x_ptr, y_ptr) + def __len__(self): """Returns the size of the active list, not the size of the diff --git a/python/tests/core/geometry/test_geo_region.py b/python/tests/core/geometry/test_geo_region.py index df6df24170..771a2af59e 100644 --- a/python/tests/core/geometry/test_geo_region.py +++ b/python/tests/core/geometry/test_geo_region.py @@ -1,15 +1,88 @@ -from ert.geo import GeoRegion, GeoPointset +from ert.geo import GeoRegion, GeoPointset, CPolyline, Surface from ert.test import ExtendedTestCase, TestAreaContext class GeoRegionTest(ExtendedTestCase): def test_init(self): - ps = GeoPointset() - gp = GeoRegion(ps) - self.assertEqual(0, len(gp)) + pointset = GeoPointset() + georegion = GeoRegion(pointset) + self.assertEqual(0, len(georegion)) def test_repr(self): - ps = GeoPointset() - gp = GeoRegion(ps) - self.assertTrue(repr(gp).startswith('GeoRegion')) + pointset = GeoPointset() + georegion = GeoRegion(pointset) + self.assertTrue(repr(georegion).startswith('GeoRegion')) + + @staticmethod + def small_surface(): + ny,nx = 12,12 + xinc,yinc = 1, 1 + xstart,ystart = -1, -1 + angle = 0.0 + s_args = (None, nx, ny, xinc, yinc, xstart, ystart, angle) + return Surface(*s_args) + + def test_select_polygon(self): + surface = self.small_surface() + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + self.assertEqual(0, len(georegion)) + points = [(-0.1,2.0), (1.9,8.1), (6.1,8.1), (9.1,5), (7.1,0.9)] + polygon = CPolyline(name='test_polygon', init_points=points) + picked = 52 # https://www.futilitycloset.com/2013/04/24/picks-theorem/ + georegion.select_inside(polygon) + self.assertEqual(picked, len(georegion)) + georegion.deselect_inside(polygon) + self.assertEqual(0, len(georegion)) + georegion.select_outside(polygon) + self.assertEqual(len(surface) - picked, len(georegion)) + georegion.deselect_outside(polygon) + self.assertEqual(0, len(georegion)) + + georegion.select_inside(polygon) + georegion.select_outside(polygon) + self.assertEqual(len(surface), len(georegion)) + georegion.deselect_inside(polygon) + georegion.deselect_outside(polygon) + self.assertEqual(0, len(georegion)) + + georegion.select_inside(polygon) + self.assertEqual(picked, len(georegion)) + internal_square = [(2.5,2.5), (2.5,6.5), (6.5,6.5), (6.5,2.5)] + georegion.deselect_inside(CPolyline(init_points=internal_square)) + self.assertEqual(picked - 4*4, len(georegion)) # internal square is 4x4 + + + def test_select_halfspace(self): + surface = self.small_surface() + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + self.assertEqual(0, len(georegion)) + line = [(-0.1,2.0), (1.9,8.1)] + picked = 118 + georegion.select_above(line) + self.assertEqual(picked, len(georegion)) + georegion.deselect_above(line) + self.assertEqual(0, len(georegion)) + georegion.select_below(line) + self.assertEqual(len(surface) - picked, len(georegion)) + georegion.deselect_below(line) + self.assertEqual(0, len(georegion)) + + georegion.select_above(line) + georegion.select_below(line) + self.assertEqual(len(surface), len(georegion)) + georegion.deselect_above(line) + georegion.deselect_below(line) + self.assertEqual(0, len(georegion)) + + + def test_raises(self): + surface = self.small_surface() + pointset = GeoPointset.fromSurface(surface) + georegion = GeoRegion(pointset) + with self.assertRaises(ValueError): + georegion.select_above(((2,), (1, 3))) + with self.assertRaises(ValueError): + georegion.select_above((('not-a-number', 2), (1, 3)))