def test_forces_CuZr_glass(self): """Calculate interatomic forces in CuZr glass Reference: tabulated forces from a calculation with Lammmps (git version patch_29Mar2019-2-g585403d65) The forces can be re-calculated using the following Lammps commands: units metal atom_style atomic boundary p p p read_data CuZr_glass_460_atoms.lammps.data.gz pair_style eam/alloy pair_coeff * * ZrCu.onecolumn.eam.alloy Zr Cu # The initial configuration is in equilibrium # and the remaining forces are small # Swap atom types to bring system out of # equilibrium and create nonzero forces group originally_Zr type 1 group originally_Cu type 2 set group originally_Zr type 2 set group originally_Cu type 1 run 0 write_dump all custom & CuZr_glass_460_atoms_forces.lammps.dump.gz & id type x y z fx fy fz & modify sort id format float "%.14g" """ if "lammps-dump" in io.formats.ioformats.keys(): atoms = io.read("CuZr_glass_460_atoms_forces.lammps.dump.gz", format="lammps-dump") elif "lammps-dump-text" in io.formats.ioformats.keys(): atoms = io.read("CuZr_glass_460_atoms_forces.lammps.dump.gz", format="lammps-dump-text") else: raise KeyError( "ase.io can read neither 'lammps-dump' nor 'lammps-dump-text'") old_atomic_numbers = atoms.get_atomic_numbers() sel, = np.where(old_atomic_numbers == 1) new_atomic_numbers = np.zeros_like(old_atomic_numbers) new_atomic_numbers[sel] = 40 # Zr sel, = np.where(old_atomic_numbers == 2) new_atomic_numbers[sel] = 29 # Cu atoms.set_atomic_numbers(new_atomic_numbers) calculator = EAM('ZrCu.onecolumn.eam.alloy') atoms.set_calculator(calculator) atoms.pbc = [True, True, True] forces = atoms.get_forces() # Read tabulated forces and compare with gzip.open("CuZr_glass_460_atoms_forces.lammps.dump.gz") as file: for line in file: if line.startswith(b"ITEM: ATOMS "): # ignore header break dump = np.loadtxt(file) forces_dump = dump[:, 5:8] self.assertArrayAlmostEqual(forces, forces_dump, tol=self.force_tolerance)
def test_hessian_monoatomic(self): """Calculate Hessian matrix of pure Cu Reference: finite difference approximation of Hessian from ASE """ atoms = FaceCenteredCubic('Cu', size=[4, 4, 4]) calculator = EAM('CuAg.eam.alloy') self._test_hessian(atoms, calculator)
def test_hessian_amorphous_alloy(self): """Calculate Hessian matrix of amorphous alloy Reference: finite difference approximation of Hessian from ASE """ atoms = io.read('CuZr_glass_460_atoms.gz') atoms.pbc = [True, True, True] calculator = EAM('ZrCu.onecolumn.eam.alloy') self._test_hessian(atoms, calculator)
def test_hessian_monoatomic_with_duplicate_pairs(self): """Calculate Hessian matrix of pure Cu In a small system, the same pair (i,j) will appear multiple times in the neighbor list, with different pair distance. Reference: finite difference approximation of Hessian from ASE """ atoms = FaceCenteredCubic('Cu', size=[2, 2, 2]) calculator = EAM('CuAg.eam.alloy') self._test_hessian(atoms, calculator)
def test_hessian_crystalline_alloy(self): """Calculate Hessian matrix of crystalline alloy Reference: finite difference approximation of Hessian from ASE """ calculator = EAM('ZrCu.onecolumn.eam.alloy') lattice_size = [4, 4, 4] # The lattice parameters are not correct, but that should be irrelevant # CuZr3 atoms = L1_2(['Cu', 'Zr'], size=lattice_size, latticeconstant=4.0) self._test_hessian(atoms, calculator) # Cu3Zr atoms = L1_2(['Zr', 'Cu'], size=lattice_size, latticeconstant=4.0) self._test_hessian(atoms, calculator) # CuZr atoms = B2(['Zr', 'Cu'], size=lattice_size, latticeconstant=3.3) self._test_hessian(atoms, calculator)
def test_dynamical_matrix(self): """Test dynamical matrix construction To obtain the dynamical matrix, one could either divide by masses immediately when constructing the matrix, or one could first form the complete Hessian and then divide by masses. The former method is implemented. """ atoms = io.read('CuZr_glass_460_atoms.gz') atoms.pbc = [True, True, True] calculator = EAM('ZrCu.onecolumn.eam.alloy') dynamical_matrix = calculator.calculate_hessian_matrix( atoms, divide_by_masses=True) # The second method requires a copy of Hessian, since # sparse matrix does not properly support *= operator hessian = calculator.calculate_hessian_matrix(atoms) masses = atoms.get_masses() mass_row = np.repeat(masses, np.diff(hessian.indptr)) mass_col = masses[hessian.indices] inverse_mass = np.sqrt(mass_row * mass_col)**-1.0 blocks = (inverse_mass * np.ones( (inverse_mass.size, 3, 3), dtype=inverse_mass.dtype).T).T nat = len(atoms) dynamical_matrix_ref = hessian.multiply( bsr_matrix((blocks, hessian.indices, hessian.indptr), shape=(3 * nat, 3 * nat))) dynamical_matrix = dynamical_matrix.todense() dynamical_matrix_ref = dynamical_matrix_ref.todense() self.assertArrayAlmostEqual(dynamical_matrix, dynamical_matrix.T, tol=self.hessian_tolerance) self.assertArrayAlmostEqual(dynamical_matrix_ref, dynamical_matrix_ref.T, tol=self.hessian_tolerance) self.assertArrayAlmostEqual(dynamical_matrix, dynamical_matrix_ref, tol=self.hessian_tolerance)
def _test_for_size(size): atoms = FaceCenteredCubic('Cu', size=size) calculator = EAM('CuAg.eam.alloy') self._test_hessian(atoms, calculator)