def dimer(pot, atoms, elements, folder=None, base64=False, index=None, nsamples=50, zoom=False): """Plots the potential behavior as the distance between two atoms in a dimer. .. note:: This produces a **dict** of all possible 2-body interaction between distinct element types. Args: elements (list): list of chemical symbols in the system. pot (matdb.calculators.basic.AsyncCalculator): IP to calculate properties with. atoms (matdb.atoms.AtomsList): list of atoms from which to calculate correlations. folder (str): path to the folder where the saved image should be stored. base64 (bool): when True, use a base-64 encoded `src` for the output of this image; otherwise, the image is saved to `folder` and only its name is returned. index (int): integer index of this plot in the parent collection. nsamples (int): number of samples to take along the trajectory. zoom (bool): when True, show a zoomed in view of the potential. Returns: dict: keys are concatenated element names (e.g. `AgPd`) and values are :class:`PointDetailImage` instances. """ #First, determine the set of unique element pairs in the list. from itertools import product possible = list(product(elements, repeat=2)) target = list(set(map(lambda l: tuple(sorted(l)), possible))) subplot_kw = {"xlabel": "Distance (Ang)", "ylabel": "IP Energy (eV)"} result = {} for elements in target: #Look up the lattice parameters for each of the elements. Use Vegard's #law to get a decent domain to plot the energy over. rmin, rvegard, rmax = _dimer_range(elements) dimer = Atoms(positions=np.zeros((2, 3)), cell=np.eye(3) * 100) dimer.positions = 0. dimer.set_calculator(pot) dimer.set_chemical_symbols(elements) if zoom: rs = np.linspace(0.7 * rmin, pot.cutoff(), nsamples) else: rs = np.linspace(0.4 * rmin, pot.cutoff(), nsamples) energy = [] for r in rs: dimer.positions[1, 2] = r energy.append(dimer.get_potential_energy()) elemstr = ''.join(elements) + ('z' if zoom else "") img = PDI(rs, np.array(energy), "plot", subplot_kw=subplot_kw, index=index, base64=base64, name=elemstr, imgtype=elemstr, folder=folder) result[elemstr] = img return result
def trimer(pot, atoms, elements, folder=None, base64=False, index=None, nsamples=50): """Plots the potential behavior as the angle between three atoms changes in a trimer. .. note:: This produces a *dict* of all possible 3-body interactions between distinct element types. Args: elements (list): list of chemical symbols in the system. pot (matdb.calculators.basic.AsyncCalculator): IP to calculate properties with. atoms (matdb.atoms.AtomsList): list of atoms from which to calculate correlations. folder (str): path to the folder where the saved image should be stored. base64 (bool): when True, use a base-64 encoded `src` for the output of this image; otherwise, the image is saved to `folder` and only its name is returned. index (int): integer index of this plot in the parent collection. nsamples (int): number of samples to take along the trajectory. Returns: dict: keys are concatenated element names (e.g. `AgPd`) and values are :class:`PointDetailImage` instances. """ #First, determine the set of unique element pairs in the list. from itertools import product possible = list(product(elements, repeat=3)) target = list(set(map(lambda l: tuple(sorted(l)), possible))) subplot_kw = {"xlabel": "Angle (Rad)", "ylabel": "IP Energy (eV)"} result = {} for elements in target: #Look up the lattice parameters for each of the elements. Use Vegard's #law to get a decent domain to plot the energy over. from matdb.data import vegard uelements = list(set(elements)) concdict = [elements.count(e) / 3. for e in uelements] rvegard = vegard(uelements, concdict) trimer = Atoms(positions=np.zeros((3, 3)), cell=np.eye(3) * 100) trimer.positions = 0. trimer.set_chemical_symbols(elements) trimer.set_calculator(pot) #Set the position of the second atom to be at equilibrium with respect #to the Vegard's law calculation. trimer.positions[1, 2] = rvegard #Now, vary the angle of the third atom with respect to the original two #and see how the angle changes. theta = np.linspace(np.pi / 6, np.pi, nsamples) energy = [] for t in theta: x = rvegard * np.cos(t) y = rvegard * np.sin(t) trimer.positions[1, 2] = x trimer.positions[1, 2] = y energy.append(trimer.get_potential_energy()) elemstr = trimer.get_chemical_formula() img = PDI(theta, np.array(energy), "plot", subplot_kw=subplot_kw, index=index, base64=base64, name=elemstr, imgtype=elemstr, folder=folder) result[elemstr] = img return result