message: added derivatives interface to soap
diff: @@ -166,6 +166,83 @@ class SOAP(Descriptor):
  self._average = average
  self.crossover = crossover
  + def derivatives_single(self, system, positions=None, include=None, exclude=None, method="numerical"):
  + """Return the SOAP output for the given systems and given positions.
  +
  + Args:
  + system (:class:`ase.Atoms` or list of :class:`ase.Atoms`): One or
  + many atomic structures.
  + positions (list): Positions where to calculate SOAP. Can be
  + provided as cartesian positions or atomic indices. If no
  + positions are defined, the SOAP output will be created for all
  + atoms in the system. When calculating SOAP for multiple
  + systems, provide the positions as a list for each system.
  + include (list): indices of atoms to compute the derivatives on.
  + Cannot be provided with argument exclude.
  + exclude (list): indices of atoms not to compute the derivatives on.
  + Cannot be provided with argument include.
  + method (str): 'numerical' or 'analytical' derivatives
  + """
  + # Determine the atom indices that are displaced
  + if include is None and exclude is None:
  + displacedIndices = np.arange(len(system))
  + elif include is not None:
  + displacedIndices = np.asarray(include)
  + elif exclude is not None:
  + displacedIndices = np.arange(len(system))
  + displacedIndices = numpy.delete(displacedIndices, exclude)
  + else:
  + raise ValueError("Provide either 'include' or 'exclude', not both.")
  +
  + system, positions, cutoff_padding = self.prepare(system, positions)
  + n_atoms = len(system)
  + positions, Z_sorted = self.flatten_positions(system, None)
  + sorted_species = self._atomic_numbers
  + n_species = len(sorted_species)
  + centers = np.array(positions)
  + n_centers = centers.shape[0]
  + centers = centers.flatten()
  + alphas = self._alphas.flatten()
  + betas = self._betas.flatten()
  +
  + # Determine shape
  + n_features = self.get_number_of_features()
  + if self._average == "inner" or self._average == "outer":
  + d = np.zeros((1, n_atoms, n_features, 3), dtype=np.float64)
  + else:
  + d = np.zeros((n_centers, n_atoms, n_features, 3), dtype=np.float64)
  +
  + # Calculate numerically with extension
  + if method == "numerical":
  + if self._rbf == "gto":
  + dscribe.ext.derivatives_soap_gto(
  + d,
  + positions,
  + centers,
  + alphas,
  + betas,
  + Z_sorted,
  + sorted_species,
  + displacedIndices,
  + self._rcut,
  + cutoff_padding,
  + n_atoms,
  + n_species,
  + self._nmax,
  + self._lmax,
  + n_centers,
  + self._eta,
  + self.crossover,
  + self._average,
  + )
  + elif method == "analytical":
  + d = np.zeros((n_atoms, n_centers, n_features), dtype=np.float64)
  + dscribe.ext.soap_gto_devX(d, positions, centers, alphas, betas, Z_sorted, rcut, cutoff_padding, n_atoms, n_species, nmax, lmax, n_centers, eta, crossover)
  + else:
  + raise ValueError("Please choose method 'numerical' or 'analytical'")
  + return d
  +
  +
  def create(self, system, positions=None, n_jobs=1, verbose=False):
  """Return the SOAP output for the given systems and given positions.
  