docs: def addRandomEffect(self, K=None, is_noise=False, normalize=False, Kcross=None, trait_covar_type='freeform', rank=1, fixed_trait_covar=None, jitter=1e-4):
          """
          Add random effects term.
  
          Args:
              K:      Sample Covariance Matrix [N, N]
              is_noise:   Boolean indicator specifying if the matrix is homoscedastic noise (weighted identity covariance) (default False)
              normalize:  Boolean indicator specifying if K has to be normalized such that K.trace()=N.
              Kcross:            NxNtest cross covariance for predictions
              trait_covar_type: type of covaraince to use. Default 'freeform'. possible values are
                              'freeform':  general semi-definite positive matrix,
                              'fixed': fixed matrix specified in fixed_trait_covar,
                              'diag': diagonal matrix,
                              'lowrank': low rank matrix. The rank of the lowrank part is specified in the variable rank,
                              'lowrank_id': sum of a lowrank matrix and a multiple of the identity. The rank of the lowrank part is specified in the variable rank,
                              'lowrank_diag': sum of a lowrank and a diagonal matrix. The rank of the lowrank part is specified in the variable rank,
                              'block': multiple of a matrix of ones,
                              'block_id': sum of a multiple of a matrix of ones and a multiple of the idenity,
                              'block_diag': sum of a multiple of a matrix of ones and a diagonal matrix,
              rank:       rank of a possible lowrank component (default 1)
              fixed_trait_covar:   PxP matrix for the (predefined) trait-to-trait covariance matrix if fixed type is used
              jitter:        diagonal contribution added to trait-to-trait covariance matrices for regularization
          """
          assert K is not None or is_noise, 'VarianceDecomposition:: Specify covariance structure'
  
          if is_noise:
              assert self.noisPos is None, 'VarianceDecomposition:: Noise term already exists'
              K  = sp.eye(self.N)
              Kcross = None
              self.noisPos = self.n_randEffs
          else:
              assert K.shape[0]==self.N, 'VarianceDecomposition:: Incompatible shape for K'
              assert K.shape[1]==self.N, 'VarianceDecomposition:: Incompatible shape for K'
          if Kcross is not None:
              assert self.Ntest is not None, 'VarianceDecomposition:: specify Ntest for predictions (method VarianceDecomposition::setTestSampleSize)'
              assert Kcross.shape[0]==self.N, 'VarianceDecomposition:: Incompatible shape for Kcross'
              assert Kcross.shape[1]==self.Ntest, 'VarianceDecomposition:: Incompatible shape for Kcross'
  
          if normalize:
              cc = covar_rescaling_factor(K) 
              K *= cc
              if Kcross is not None: Kcross *= cc 
  
          # add random effect
          self.sample_covars.append(K)
          self.sample_cross_covars.append(Kcross)
          _cov = self._buildTraitCovar(trait_covar_type=trait_covar_type, rank=rank, fixed_trait_covar=fixed_trait_covar, jitter=jitter)
          self.trait_covars.append(_cov)
          self.n_randEffs+=1
  
          #TODO: define _sync function
          self._desync()