Ejemplo n.º 1
0
    def calculate(self,
                  atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):
        bad = [
            change for change in system_changes
            if change not in self.supported_changes
        ]

        # First time calculate() is called, system_changes will be
        # all_changes.  After that, only positions and cell may change.
        if self.atoms is not None and any(bad):
            raise PropertyNotImplementedError(
                'Cannot change {} through IPI protocol.  '
                'Please create new socket calculator.'.format(
                    bad if len(bad) > 1 else bad[0]))

        self.atoms = atoms.copy()

        if self.server is None:
            self.server = self.launch_server()
            proc = self.launch_client(atoms,
                                      properties,
                                      port=self._port,
                                      unixsocket=self._unixsocket)
            self.server.proc = proc  # XXX nasty hack

        results = self.server.calculate(atoms)
        results['free_energy'] = results['energy']
        virial = results.pop('virial')
        if self.atoms.cell.rank == 3 and any(self.atoms.pbc):
            vol = atoms.get_volume()
            results['stress'] = -full_3x3_to_voigt_6_stress(virial) / vol
        self.results.update(results)
Ejemplo n.º 2
0
 def adjust_stress(self, atoms, stress):
     # symmetrize stress as rank 2 tensor
     raw_stress = voigt_6_to_full_3x3_stress(stress)
     symmetrized_stress = symmetrize_rank2(atoms.get_cell(),
                                           atoms.cell.reciprocal().T,
                                           raw_stress, self.rotations)
     stress[:] = full_3x3_to_voigt_6_stress(symmetrized_stress)
Ejemplo n.º 3
0
def test_stress():
    # build a water dimer, which has 6 atoms
    water1 = molecule('H2O')
    water2 = molecule('H2O')
    water2.positions[:, 0] += 5.0
    atoms = water1 + water2
    atoms.cell = [10, 10, 10]
    atoms.pbc = True

    # array with clashing name
    atoms.new_array('stress', np.arange(6, dtype=float))
    atoms.calc = EMT()
    a_stress = atoms.get_stress()
    atoms.write('tmp.xyz')
    b = ase.io.read('tmp.xyz')
    assert abs(b.get_stress() - a_stress).max() < 1e-6
    assert abs(b.arrays['stress'] - np.arange(6, dtype=float)).max() < 1e-6
    b_stress = b.info['stress']
    assert abs(full_3x3_to_voigt_6_stress(b_stress) - a_stress).max() < 1e-6
Ejemplo n.º 4
0
    def compute_properties(self) -> Dict:
        if self.neighbors.did_buffer_overflow:
            self.update_neighbor_list()

        properties = self.potential(self.R, neighbor=self.neighbors)
        (
            potential_energy,
            potential_energies,
            forces,
            stress,
        ) = jax_utils.block_and_dispatch(properties)

        result = {
            "energy": potential_energy,
            "energies": potential_energies,
            "forces": forces,
        }

        if stress is not None:
            result["stress"] = full_3x3_to_voigt_6_stress(stress)
        return result
Ejemplo n.º 5
0
    def calculate(
        self,
        atoms=None,
        properties=None,
        system_changes=all_changes,
    ):
        if properties is None:
            properties = self.implemented_properties

        Calculator.calculate(self, atoms, properties, system_changes)

        natoms = len(self.atoms)

        sigma = self.parameters.sigma
        epsilon = self.parameters.epsilon
        rc = self.parameters.rc
        ro = self.parameters.ro
        smooth = self.parameters.smooth

        if self.nl is None or 'numbers' in system_changes:
            self.nl = NeighborList([rc / 2] * natoms,
                                   self_interaction=False,
                                   bothways=True)

        self.nl.update(self.atoms)

        positions = self.atoms.positions
        cell = self.atoms.cell

        # potential value at rc
        e0 = 4 * epsilon * ((sigma / rc)**12 - (sigma / rc)**6)

        energies = np.zeros(natoms)
        forces = np.zeros((natoms, 3))
        stresses = np.zeros((natoms, 3, 3))

        for ii in range(natoms):
            neighbors, offsets = self.nl.get_neighbors(ii)
            cells = np.dot(offsets, cell)

            # pointing *towards* neighbours
            distance_vectors = positions[neighbors] + cells - positions[ii]

            r2 = (distance_vectors**2).sum(1)
            c6 = (sigma**2 / r2)**3
            c6[r2 > rc**2] = 0.0
            c12 = c6**2

            if smooth:
                cutoff_fn = cutoff_function(r2, rc**2, ro**2)
                d_cutoff_fn = d_cutoff_function(r2, rc**2, ro**2)

            pairwise_energies = 4 * epsilon * (c12 - c6)
            pairwise_forces = -24 * epsilon * (2 * c12 - c6) / r2  # du_ij

            if smooth:
                # order matters, otherwise the pairwise energy is already modified
                pairwise_forces = (cutoff_fn * pairwise_forces +
                                   2 * d_cutoff_fn * pairwise_energies)
                pairwise_energies *= cutoff_fn
            else:
                pairwise_energies -= e0 * (c6 != 0.0)

            pairwise_forces = pairwise_forces[:, np.newaxis] * distance_vectors

            energies[ii] += 0.5 * pairwise_energies.sum()  # atomic energies
            forces[ii] += pairwise_forces.sum(axis=0)

            stresses[ii] += 0.5 * np.dot(
                pairwise_forces.T,
                distance_vectors)  # equivalent to outer product

        # no lattice, no stress
        if self.atoms.cell.rank == 3:
            stresses = full_3x3_to_voigt_6_stress(stresses)
            self.results['stress'] = stresses.sum(
                axis=0) / self.atoms.get_volume()
            self.results['stresses'] = stresses / self.atoms.get_volume()

        energy = energies.sum()
        self.results['energy'] = energy
        self.results['energies'] = energies

        self.results['free_energy'] = energy

        self.results['forces'] = forces