The Fingerprint base class

The fingerprint object provides a base class for the generation of material fingerprints.

It can use Material objects as input.

Usage

All built-in fingerprints can be generated from the base class:

from madas import Fingerprint

dos_fingerprint = Fingerprint("DOS", **<dos_fingerprint_kwargs>).from_material(<material>, **dos_fingerprint_calculate_kwargs)

This is equivalent to calling:

dos_fingerprint = Fingerprint("DOS", **<dos_fingerprint_kwargs>).calculate(<material>.data["dos_energies"], <material>.data["dos_values"], **dos_fingerprint_calculate_kwargs)

The fingerprints can be customized by passing (expected) keyword arguments to the initialization and to the calculate method.

The similarity to other materials can be calculated for single or many fingerprints:

single_similarity = dos_fingerprint.get_similarity(<other_dos_fingerprint>)

many_similarities = dos_fingerprint.get_similarities(<list_of_other_fingerprints>)

Custom fingerprint generation

New types of fingerprints can be defined as child classes of Fingerprint. Say, you want to generate a fingerprint that compares the highest atomic number of the elements of a material. The corresponding code would look like this:

from ase import Atoms

from madas import Material, Fingerprint

def MAN_similarity(fingerprint1, fingerprint2):
   """
   Calculate similarity between two MANFingerprint objects.
   """
   # extract data from fingerprint objects
   man1 = fingerprint1.data["maximum_atomic_number"]
   man2 = fingerprint2.data["maximum_atomic_number"]
   # calculate absolute distance
   atomic_number_differences = abs(man1 - man2)
   # convert distance to similarity
   similarity = 1/(1 + atomic_number_differences)
   # return value
   return similarity

class MANFingerprint(Fingerprint):
   """
   (M)aximum (A)tomic (N)umber fingerprint.

   Example fingerprint that compares the highest atomic number of the elements of a material.
   """

   # This declaration can be skipped.
   # However, it is advised to explicitly write the `__init__` function.
   def __init__(self,
               name = "MAN",
               similarity_function=MAN_similarity,
               pass_on_exceptions=True) -> None:
      # set the fingerprint type name
      self.set_fp_type("MAN")
      # set a name of the specific fingerprint
      self.set_name(name)
      # set if the fingerprint shall raise an exeption if anything fails
      self.set_pass_on_exceptions(pass_on_exceptions)
      # set the similarity function used to calculate similarity values
      self.set_similarity_function(similarity_function)

   def calculate(self, atoms: Atoms):
      # get the maximal atomic number from ASE Atoms object
      atomic_numbers = atoms.get_atomic_numbers()
      max_atomic_number = max(atomic_numbers)
      # REQUIRED: set the fingerprint data
      self.set_data("maximum_atomic_number", max_atomic_number)
      # REQUIRED: return self
      return self

   def from_material(self, material: Material):
      # REQUIRED: set the material identifier for this fingerprint
      self.set_mid(material)
      # use obtain properties from the material object
      atoms = material.atoms
      # calculate the fingerprint
      self.calculate(atoms)
      # REQUIRED: return self
      return self

Note that two methods are required: a calculate method to compute the fingerprint directly from data, and a from_material method that collects the required data from a Material object and calls the calculate method internally.

Documentation

The documentation of all methods and parameters can be found below:

class madas.fingerprint.Fingerprint(fp_type: str | type | None = None, name: str | None = None, similarity_function: ~typing.Callable | None = None, pass_on_exceptions: bool = False, importfunction: ~typing.Callable = <function import_builtin_module>, **kwargs)

Generic description of a fingerprint.

Intended use case is subclassing to integrate with the madas framework.

Arbitrary data can be passed to the Fingerprint object by using Fingerprint().set_data(<key>: str, <data>: Any). It can be retrieved either through the property Fingerprint().data as a dictionary, or directly via Fingerprint()[<key>].

Parameters:

fp_type: str, type, or None

Type of fingerprint. The behavior changes based on the type of the argument:

  • None: Don’t intialize the fingerprint type. The object will be a generic Fingerprint

  • type: Intialize as a fingerprint of the given type. All keyword arguments will be passed to the child class.

  • str: Initialize as a built-in fingerprint type using the importfunction. All keyword arguments will be passed to the child class.

default: None

name: str

Name of the fingerprint. Can be used to distinguish between fingerprints of the same type with different parameters.

similarity_function: Callable or None

Function used to evaluate the similarity to other fingerprints.

This function will be called when Fingerprint().get_similarity() is called.

If set to None upon initialization and a fingerprint type is given, the respective similarity function will be set automatically.

If set to a callable, use this similarity function instead of any other, even if a fingerprint type is given.

default: None

pass_on_exceptions: bool

In order to allow processing of big amounts of data without interruptions, the fingerprint can return 0 similarity instead of raising exceptions. A warning will be printed if the calculation of similarity is not successful.

default: False

importfunction: callable

Function that imports fingerprint classes if the fingerprint type is provided as a string.

default: madas.fingerprint.import_builtin_module

Methods:

calculate(mid: str, *args, **kwargs) object | None

To be defined in child class. Calculate the fingerprint from values.

Expected return value:

self: Fingerprint

It is expected that the object returns itself after calling calculate.

copy() object

Return a deep copy of the fingerprint.

property data: dict

Get data dictionary of the Fingerprint.

classmethod deserialize(data: str) object

Read a fingerprint object from string data. This returns a Fingerprint object, _not_ a subclass of it. The similarity function needs to be set separately, and calculate() won’t work.

Arguments:

data: str

Sting data of fingerprint (json serialized), obtained by Fingerprint().serialize().

Returns:

fingerprint: Fingerprint

Fingerprint object with all fields set.

property fp_type

Property that contains the type of fingerprint.

from_material(material: Material, *args, **kwargs)

To be defined in child class. Calculate the fingerprint from a Material object.

Expected return value:

self: Fingerprint

It is expected that the object returns itself after calling calculate.

get_data_json() str

Return fingerprint data in as a json-coded string.

get_similarities(fingerprint_list: list) List[float]

Calculate similarity to all other fingerprints in fingerprint_list.

Arguments:

fingerprint_list: List[Fingerpint]

Other fingerprints to calculate similarity

Returns:

similarities: List[float]

Similarities of self to all other fingerprints

Raises:

TypeError: Different fingerprint types are used.

get_similarity(other: object) float

Calculate similarity to another fingerprint.

Arguments:

other: Fingerpint

Other fingerprint to calculate similarity

Returns:

similarity: float

Similarity between both fingerprints

Raises:

TypeError: Different fingerprint types are used.

Warnings:

UserWarning: Fingerprints of different names are used.

property mid

Material identifier property.

property name

Property that contains the name of fingerprint.

property pass_on_exceptions

Property that controls if exceptions should be raised.

serialize() str

Write fingerprint data and metadata to dictionary or string.

Returns:

data: str

json dump of fingerprint

set_data(key: str, data: Any) None

Set data entries of the Fingerprint.

Arguments:

key: str

Name of the property that is meant to be stored

data: Any

Properties to be stored as fingerprint data

set_import_function(import_function: Callable) None

Set the function used to import specialized fingerprint objects.

Arguments:

import_function: Callable;

A function that returns a specialized Fingerprint class and a similarity function.

set_mid(mid: str | Material) None

Set material id of Fingerprint.

Arguments:

mid: str or Material

Material id to be set.

If a Material is given, the mid will be extracted from there.

Returns:

None

set_pass_on_exceptions(behavior: bool) None

Set if fingerprint should pass and return None if an exception occures during calculation of similarities, or raise an Exception.

Arguments:

behavior: bool

Set behavior.

True -> Return None if exceptions are raised during calculation of similarities.

False -> Raise exceptions.

set_similarity_function(similarity_function: Callable, **kwargs) object

Set the function for calculating similarity and return self.

Arguments:

similarity_function: Callable

Function that takes two fingerprint objects as input and calculates the similarity between them

Keyword arguments are passed to the function.

specify(fingerprint_class, **kwargs)

Change self to class given by fingerprint_class.

Arguments:

fingerprint_class: type

Subclass of Fingerprint

Keyword arguments are passed to the __init__ function of the specialized fingerprint.

Built-in fingerprints