docs: def select(self, key=None, val=None, touch=None, log='any', out=int):
          """ Return the indices of the rays matching selection criteria
  
          The criterion can be of two types:
              - a key found in self.dchans, with a matching value
              - a touch tuple (indicating which element in self.config is touched
                  by the desired rays)
  
          Parameters
          ----------
          key :    None / str
              A key to be found in self.dchans
          val :   int / str / float / list of such
              The value to be matched
              If a list of values is provided, the behaviour depends on log
          log :   str
              A flag indicating which behaviour to use when val is a list
                  - any : Returns indices of rays matching any value in val
                  - all : Returns indices of rays matching all values in val
                  - not : Returns indices of rays matching None of the val
          touch:  None / str / int / tuple
              Used if key is None
              Tuple that can be of len()=1, 2 or 3
              Tuple indicating you want the rays that are touching some specific elements of self.config:
                  - touch[0] : str / int or list of such
                      str : a 'Cls_Name' string indicating the element
                      int : the index of the element in self.lStruct_computeInOut
                  - touch[1] : int / list of int
                      Indices of the desired segments on the polygon
                      (i.e.: of the cross-section polygon of the above element)
                  - touch[2] : int / list of int
                      Indices, if relevant, of the toroidal / linear unit
                      Only relevant when the element has noccur>1
              In this case only log='not' has an effect
          out :   str
              Flag indicating whether to return:
                  - bool : a (nRays,) boolean array of indices
                  - int :  a (N,) array of int indices (N=number of matching rays)
  
          Returns
          -------
          ind :   np.ndarray
              The array of matching rays
  
          """
          assert out in [int,bool]
          assert log in ['any','all','not']
          C = [key is None,touch is None]
          assert np.sum(C)>=1
          if np.sum(C)==2:
              ind = np.ones((self.nRays,),dtype=bool)
          else:
              if key is not None:
                  assert type(key) is str and key in self._dchans.keys()
                  ltypes = [str,int,float,np.int64,np.float64]
                  C0 = type(val) in ltypes
                  C1 = type(val) in [list,tuple,np.ndarray]
                  assert C0 or C1
                  if C0:
                      val = [val]
                  else:
                      assert all([type(vv) in ltypes for vv in val])
                  ind = np.vstack([self._dchans[key]==ii for ii in val])
                  if log=='any':
                      ind = np.any(ind,axis=0)
                  elif log=='all':
                      ind = np.all(ind,axis=0)
                  else:
                      ind = ~np.any(ind,axis=0)
  
              elif touch is not None:
                  lint = [int,np.int64]
                  larr = [list,tuple,np.ndarray]
                  touch = [touch] if not type(touch) is list else touch
                  assert len(touch) in [1,2,3]
  
                  def _check_touch(tt):
                      cS = type(tt) is str and len(tt.split('_'))==2
                      c0 = type(tt) in lint
                      c1 = type(tt) in larr and len(tt)>=0
                      c1 = c1 and all([type(t) in lint for t in tt])
                      return cS, c0, c1
                  for ii in range(0,3-len(touch)):
                      touch.append([])
  
                  ntouch = len(touch)
                  assert ntouch == 3
  
                  for ii in range(0,ntouch):
                      cS, c0, c1 = _check_touch(touch[ii])
  
                      if not (cS or c0 or c1):
                          msg = "Provided touch is not valid:\n"%touch
                          msg += "    - Provided: %s\n"%str(touch)
                          msg += "Please provide either:\n"
                          msg += "    - str in the form 'Cls_Name'\n"
                          msg += "    - int (index)\n"
                          msg += "    - array of int indices"
                          raise Exception(msg)
  
                      if cS:
                          lS = self.lStruct_computeInOut
                          k0, k1 = touch[ii].split('_')
                          ind = [jj for jj in range(0,len(lS))
                                 if lS[jj].Id.Cls==k0 and lS[jj].Id.Name==k1]
                          assert len(ind)==1
                          touch[ii] = [ind[0]]
                      elif c0:
                          touch[ii] = [touch[ii]]
  
                  # Common part
                  ind = np.zeros((ntouch,self.nRays),dtype=bool)
                  for i in range(0,ntouch):
                      if len(touch[i])==0:
                          ind[i,:] = True
                      else:
                          for n in range(0,len(touch[i])):
                              ind[i,:] = np.logical_or(ind[i,:],
                                                       self._dgeom['indout'][i,:]==touch[i][n])
                  ind = np.all(ind,axis=0)
                  if log=='not':
                      ind[:] = ~ind
          if out is int:
              ind = ind.nonzero()[0]
          return ind