code: def likelihood(self, outcomes, modelparams, expparams):
          
          # By calling the superclass implementation, we can consolidate
          # call counting there.
          super(DirectViewParallelizedModel, self).likelihood(outcomes, modelparams, expparams)
  
          # If there's less models than some threshold, just use the serial model.
          # By default, we'll set that threshold to be the number of engines * 10.
          if modelparams.shape[0] <= self._serial_threshold:
              return self.underlying_model.likelihood(outcomes, modelparams, expparams)
          
          if self._dv is None:
              raise RuntimeError(
                  "No direct view provided; this may be because the instance was "
                  "loaded from a pickle or NumPy saved array without providing a "
                  "new direct view."
              )
  
          # Need to decorate with interactive to overcome namespace issues with
          # remote engines.
          @interactive
          def serial_likelihood(mps, sm, os, eps):
              return sm.likelihood(os, mps, eps)
  
          # TODO: check whether there's a better way to pass the extra parameters
          # that doesn't use so much memory.
          # The trick is that serial_likelihood will be pickled, so we need to be
          # careful about closures.
          L = self._dv.map_sync(
              serial_likelihood,
              np.array_split(modelparams, self.n_engines, axis=0),
              [self.underlying_model] * self.n_engines,
              [outcomes] * self.n_engines,
              [expparams] * self.n_engines
          )
  
          return np.concatenate(L, axis=1)
docs: Returns the likelihood for the underlying (serial) model, distributing
          the model parameter array across the engines controlled by this
          parallelized model. Returns what the serial model would return, see
          :attr:`~Model.likelihood`