def test_pbc_diff(self): self.assertArrayAlmostEqual(pbc_diff([0.1, 0.1, 0.1], [0.3, 0.5, 0.9]), [-0.2, -0.4, 0.2]) self.assertArrayAlmostEqual( pbc_diff([0.9, 0.1, 1.01], [0.3, 0.5, 0.9]), [-0.4, -0.4, 0.11]) self.assertArrayAlmostEqual( pbc_diff([0.1, 0.6, 1.01], [0.6, 0.1, 0.9]), [-0.5, 0.5, 0.11]) self.assertArrayAlmostEqual( pbc_diff([100.1, 0.2, 0.3], [0123123.4, 0.5, 502312.6]), [-0.3, -0.3, -0.3])
def test_pbc_diff(self): self.assertTrue(np.allclose(pbc_diff([0.1, 0.1, 0.1], [0.3, 0.5, 0.9]), [-0.2, -0.4, 0.2])) self.assertTrue(np.allclose(pbc_diff([0.9, 0.1, 1.01], [0.3, 0.5, 0.9]), [-0.4, -0.4, 0.11])) self.assertTrue(np.allclose(pbc_diff([0.1, 0.6, 1.01], [0.6, 0.1, 0.9]), [-0.5, 0.5, 0.11])) self.assertTrue(np.allclose(pbc_diff([100.1, 0.2, 0.3], [0123123.4, 0.5, 502312.6]), [-0.3, -0.3, -0.3]))
def test_pbc_diff(self): self.assertArrayAlmostEqual(pbc_diff([0.1, 0.1, 0.1], [0.3, 0.5, 0.9]), [-0.2, -0.4, 0.2]) self.assertArrayAlmostEqual(pbc_diff([0.9, 0.1, 1.01], [0.3, 0.5, 0.9]), [-0.4, -0.4, 0.11]) self.assertArrayAlmostEqual(pbc_diff([0.1, 0.6, 1.01], [0.6, 0.1, 0.9]), [-0.5, 0.5, 0.11]) self.assertArrayAlmostEqual(pbc_diff([100.1, 0.2, 0.3], [0123123.4, 0.5, 502312.6]), [-0.3, -0.3, -0.3])
def get_matching_coord(coord): for op in self.symmetry_operations: c = op.operate(coord) for k in coord_to_species.keys(): if np.allclose(pbc_diff(c, k), (0, 0, 0), atol=self._site_tolerance): return tuple(k) return False
def should_stop(self, old_centroids, centroids, iterations): if iterations > self.max_iterations: warnings.warn("Max iterations %d reached!" % self.max_iterations) return True if old_centroids is None: return False for c1, c2 in zip(old_centroids, centroids): if not np.allclose(pbc_diff(c1, c2), [0, 0, 0]): return False return True
def from_vaspruns(cls, vaspruns, specie, min_obs=30, weighted=True): """ Convenient constructor that takes in a list of Vasprun objects to perform diffusion analysis. Args: vaspruns: list of Vasprun objects (must be ordered in sequence of run). E.g., you may have performed sequential VASP runs to obtain sufficient statistics. specie: Specie to calculate diffusivity for as a String. E.g., "Li". min_obs: Minimum number of observations to have before including in the MSD vs dt calculation. E.g. If a structure has 10 diffusing atoms, and min_obs = 30, the MSD vs dt will be calculated up to dt = total_run_time / 3, so that each diffusing atom is measured at least 3 uncorrelated times. weighted: Uses a weighted least squares to fit the MSD vs dt. Weights are proportional to 1/dt, since the number of observations are also proportional to 1/dt (and hence the variance is proportional to dt) """ structure = vaspruns[0].initial_structure step_skip = vaspruns[0].ionic_step_skip or 1 p = [] final_structure = vaspruns[0].initial_structure for vr in vaspruns: #check that the runs are continuous fdist = pbc_diff(vr.initial_structure.frac_coords, final_structure.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structures do not ' 'match.') final_structure = vr.final_structure assert (vr.ionic_step_skip or 1) == step_skip p.extend([np.array(s['structure'].frac_coords)[:, None] for s in vr.ionic_steps]) p = np.concatenate(p, axis=1) dp = p[:, 1:] - p[:, :-1] dp = np.concatenate([np.zeros_like(dp[:, (0,)]), dp], axis=1) dp = dp - np.round(dp) f_disp = np.cumsum(dp, axis=1) disp = structure.lattice.get_cartesian_coords(f_disp) temperature = vaspruns[0].parameters['TEEND'] time_step = vaspruns[0].parameters['POTIM'] return cls(structure, disp, specie, temperature, time_step, step_skip=step_skip, min_obs=min_obs, weighted=weighted)
def from_vaspruns(cls, vaspruns, specie, min_obs=30, weighted=True): """ Convenient constructor that takes in a list of Vasprun objects to perform diffusion analysis. Args: vaspruns ([Vasprun]): List of Vaspruns (must be ordered in sequence of MD simulation). E.g., you may have performed sequential VASP runs to obtain sufficient statistics. specie (Element/Specie): Specie to calculate diffusivity for as a String. E.g., "Li". min_obs (int): Minimum number of observations to have before including in the MSD vs dt calculation. E.g. If a structure has 10 diffusing atoms, and min_obs = 30, the MSD vs dt will be calculated up to dt = total_run_time / 3, so that each diffusing atom is measured at least 3 uncorrelated times. weighted (bool): Uses a weighted least squares to fit the MSD vs dt. Weights are proportional to 1/dt, since the number of observations are also proportional to 1/dt (and hence the variance is proportional to dt) """ step_skip = vaspruns[0].ionic_step_skip or 1 final_structure = vaspruns[0].initial_structure structures = [] for vr in vaspruns: #check that the runs are continuous fdist = pbc_diff(vr.initial_structure.frac_coords, final_structure.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structures do not ' 'match.') final_structure = vr.final_structure assert (vr.ionic_step_skip or 1) == step_skip structures.extend([s['structure'] for s in vr.ionic_steps]) temperature = vaspruns[0].parameters['TEEND'] time_step = vaspruns[0].parameters['POTIM'] return cls.from_structures(structures, specie, temperature, time_step, step_skip=step_skip, min_obs=min_obs, weighted=weighted)
def get_structure(vaspruns): for i, vr in enumerate(vaspruns): if i == 0: skipstep = vr.ionic_skipstep or 1 final_material = vr.initial_material temp = vr.parameters['TEEND'] steptime = vr.parameters['POTIM'] yield skipstep, temp, steptime fdist = pbc_diff(vr.initial_material.frac_coords, final_material.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structure do not ''match.') final_material = vr.final_material assert (vr.ionic_skipstep or 1) == skipstep for s in vr.ionic_steps: yield s['material']
def get_structures(vaspruns): for i, vr in enumerate(vaspruns): if i == 0: step_skip = vr.ionic_step_skip or 1 final_structure = vr.initial_structure temperature = vr.parameters['TEEND'] time_step = vr.parameters['POTIM'] yield step_skip, temperature, time_step # check that the runs are continuous fdist = pbc_diff(vr.initial_structure.frac_coords, final_structure.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structures do not ' 'match.') final_structure = vr.final_structure assert (vr.ionic_step_skip or 1) == step_skip for s in vr.ionic_steps: yield s['structure']
def test_cluster(self): lattice = Lattice.cubic(4) pts = [] initial = [[0, 0, 0], [0.5, 0.5, 0.5], [0.25, 0.25, 0.25], [0.5, 0, 0]] for c in initial: for i in range(100): pts.append(np.array(c) + np.random.randn(3) * 0.01 + np.random.randint(3)) pts = np.array(pts) k = KmeansPBC(lattice) centroids, labels, ss = k.cluster(pts, 4) for c1 in centroids: found = False for c2 in centroids: if np.allclose(pbc_diff(c1, c2), [0, 0, 0], atol=0.1): found = True break self.assertTrue(found)
def is_periodic_image(self, other, tolerance=1e-8, check_lattice=True): """ Returns True if sites are periodic images of each other. Args: other: Other site tolerance: Tolerance to compare fractional coordinates check_lattice: Whether to check if the two sites have the same lattice. """ if check_lattice and self._lattice != other._lattice: return False if self._species != other._species: return False frac_diff = pbc_diff(self._fcoords, other._fcoords) return np.allclose(frac_diff, [0, 0, 0], atol=tolerance)
def from_vaspruns(cls, vaspruns, specie, smoothed="max", min_obs=30, avg_nsteps=1000, initial_disp=None, initial_structure=None): """ Convenient constructor that takes in a list of Vasprun objects to perform diffusion analysis. Args: vaspruns ([Vasprun]): List of Vaspruns (must be ordered in sequence of MD simulation). E.g., you may have performed sequential VASP runs to obtain sufficient statistics. specie (Element/Specie): Specie to calculate diffusivity for as a String. E.g., "Li". min_obs (int): Minimum number of observations to have before including in the MSD vs dt calculation. E.g. If a structure has 10 diffusing atoms, and min_obs = 30, the MSD vs dt will be calculated up to dt = total_run_time / 3, so that each diffusing atom is measured at least 3 uncorrelated times. smoothed (str): Whether to smooth the MSD, and what mode to smooth. Supported modes are: i. "max", which tries to use the maximum # of data points for each time origin, subject to a minimum # of observations given by min_obs, and then weights the observations based on the variance accordingly. This is the default. ii. "constant", in which each timestep is averaged over the same number of observations given by min_obs. iii. None / False / any other false-like quantity. No smoothing. min_obs (int): Used with smoothed="max". Minimum number of observations to have before including in the MSD vs dt calculation. E.g. If a structure has 10 diffusing atoms, and min_obs = 30, the MSD vs dt will be calculated up to dt = total_run_time / 3, so that each diffusing atom is measured at least 3 uncorrelated times. Only applies in smoothed="max". avg_nsteps (int): Used with smoothed="constant". Determines the number of time steps to average over to get the msd for each timestep. Default of 1000 is usually pretty good. initial_disp (np.ndarray): Sometimes, you need to iteratively compute estimates of the diffusivity. This supplies an initial displacement that will be added on to the initial displacements. Note that this makes sense only when smoothed=False. initial_structure (Structure): Like initial_disp, this is used for iterative computations of estimates of the diffusivity. You typically need to supply both variables. This stipulates the initial strcture from which the current set of displacements are computed. """ step_skip = vaspruns[0].ionic_step_skip or 1 final_structure = vaspruns[0].initial_structure structures = [] for vr in vaspruns: #check that the runs are continuous fdist = pbc_diff(vr.initial_structure.frac_coords, final_structure.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structures do not ' 'match.') final_structure = vr.final_structure assert (vr.ionic_step_skip or 1) == step_skip structures.extend([s['structure'] for s in vr.ionic_steps]) temperature = vaspruns[0].parameters['TEEND'] time_step = vaspruns[0].parameters['POTIM'] return cls.from_structures(structures=structures, specie=specie, temperature=temperature, time_step=time_step, step_skip=step_skip, smoothed=smoothed, min_obs=min_obs, avg_nsteps=avg_nsteps, initial_disp=initial_disp, initial_structure=initial_structure)
def from_vaspruns(cls, vaspruns, specie, min_obs=30, weighted=True): """ Convenient constructor that takes in a list of Vasprun objects to perform diffusion analysis. Args: vaspruns: list of Vasprun objects (must be ordered in sequence of run). E.g., you may have performed sequential VASP runs to obtain sufficient statistics. specie: Specie to calculate diffusivity for as a String. E.g., "Li". min_obs: Minimum number of observations to have before including in the MSD vs dt calculation. E.g. If a structure has 10 diffusing atoms, and min_obs = 30, the MSD vs dt will be calculated up to dt = total_run_time / 3, so that each diffusing atom is measured at least 3 uncorrelated times. weighted: Uses a weighted least squares to fit the MSD vs dt. Weights are proportional to 1/dt, since the number of observations are also proportional to 1/dt (and hence the variance is proportional to dt) """ structure = vaspruns[0].initial_structure step_skip = vaspruns[0].ionic_step_skip or 1 p = [] final_structure = vaspruns[0].initial_structure for vr in vaspruns: #check that the runs are continuous fdist = pbc_diff(vr.initial_structure.frac_coords, final_structure.frac_coords) if np.any(fdist > 0.001): raise ValueError('initial and final structures do not ' 'match.') final_structure = vr.final_structure assert (vr.ionic_step_skip or 1) == step_skip p.extend([ np.array(s['structure'].frac_coords)[:, None] for s in vr.ionic_steps ]) p = np.concatenate(p, axis=1) dp = p[:, 1:] - p[:, :-1] dp = np.concatenate([np.zeros_like(dp[:, (0, )]), dp], axis=1) dp = dp - np.round(dp) f_disp = np.cumsum(dp, axis=1) disp = structure.lattice.get_cartesian_coords(f_disp) temperature = vaspruns[0].parameters['TEEND'] time_step = vaspruns[0].parameters['POTIM'] return cls(structure, disp, specie, temperature, time_step, step_skip=step_skip, min_obs=min_obs, weighted=weighted)