def do_RSS(initial_configs_file, index=':', tol=0.01): import model ats = ase.io.read(initial_configs_file, index) range_slice_args = [None if i == '' else int(i) for i in index.split(':')] print("got index ", index, "range_slice_args", range_slice_args) print("using i_config", range(len(ats))[slice(*range_slice_args)]) energies = [] volumes = [] for (i_config, at) in zip(range(len(ats))[slice(*range_slice_args)], ats): robust_minim_cell_pos(at, tol, "RSS_%04d" % i_config) print("RSS completed minimization") if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence() energies.append(at.get_potential_energy() / len(at)) volumes.append(at.get_volume() / len(at)) ase.io.write("RSS_relaxed_%04d.extxyz" % i_config, at) return {'energies': energies, 'volumes': volumes}
def robust_minim_cell_pos(atoms, final_tol, label="robust_minim", max_sd2_iter=50, sd2_tol=1.0, max_lbfgs_iter=20, max_n_lbfgs=50, keep_symmetry=True): import model # do each minim at fixed cell-dependent model params (e.g. k-point mesh) if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(atoms) relax_config(atoms, relax_pos=True, relax_cell=True, tol=sd2_tol, max_steps=max_sd2_iter, traj_file="%s_sd2_traj.extxyz" % label, method='sd2', keep_symmetry=keep_symmetry, config_label=label) done = False i_iter = 0 while not done and i_iter < max_n_lbfgs: try: if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(atoms) relax_config(atoms, relax_pos=True, relax_cell=True, tol=final_tol, max_steps=max_lbfgs_iter, traj_file="%s_lbfgs_traj.%02d.extxyz" % (label, i_iter), method='lbfgs', keep_symmetry=keep_symmetry, config_label=label) done = (atoms.info["n_minim_iter"] < max_lbfgs_iter) print("robust_minim relax_configs LBFGS finished in ", atoms.info["n_minim_iter"], "iters, max", max_lbfgs_iter) except: print("robust_minim relax_configs LBFGS failed, trying again") i_iter += 1 # Undo fixed cell dependence. Hopefully no one is using robust_minim as part of a # more complex process that is doing its own fix_cell_depdence() if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence()
def calc_E_vs_V(bulk, dV=0.025, n_steps=(-10,10), tol=1e-2, method='lbfgs'): # hack tol to deal with Te C2/m import model V0 = bulk.get_volume() dV *= V0 E_vs_V=[] scaled_bulk = bulk.copy() for i in range(0, n_steps[0]-1, -1): V_cur = scaled_bulk.get_volume() scaled_bulk.set_cell(scaled_bulk.get_cell()*((V0+i*dV)/V_cur)**(1.0/3.0), scale_atoms=True) ase.io.write(sys.stdout, scaled_bulk, format='extxyz') print("trying to relax i",i) try: if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(scaled_bulk) ase.io.write(run_root+"-E_vs_V_%03d-unrelaxed.xyz" % i, scaled_bulk, format='extxyz') scaled_bulk = relax_config(scaled_bulk, relax_pos=True, relax_cell=True, tol=tol, max_steps=200, save_traj=True, constant_volume=True, method=method, refine_symmetry_tol=1.0e-1, keep_symmetry=True, config_label="E_vs_V_%03d" % i, from_base_model=True, save_config=True) except Exception as e: print("WARNING: failed config in calc_E_vs_V", str(e)) sys.exit(1) #### NB break ase.io.write(sys.stdout, scaled_bulk, format='extxyz') E_vs_V.insert(0, (scaled_bulk.get_volume()/len(scaled_bulk), scaled_bulk.get_potential_energy()/len(bulk), list(scaled_bulk.get_stress())) ) scaled_bulk = bulk.copy() for i in range(1,n_steps[1]+1): V_cur = scaled_bulk.get_volume() scaled_bulk.set_cell(scaled_bulk.get_cell()*((V0+i*dV)/V_cur)**(1.0/3.0), scale_atoms=True) ase.io.write(sys.stdout, scaled_bulk, format='extxyz') print("trying to relax i",i) try: if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(scaled_bulk) ase.io.write(run_root+"-E_vs_V_%02d-unrelaxed.xyz" % i, scaled_bulk, format='extxyz') scaled_bulk = relax_config(scaled_bulk, relax_pos=True, relax_cell=True, tol=tol, max_steps=200, save_traj=True, constant_volume=True, method=method, refine_symmetry_tol=1.0e-1, keep_symmetry=True, config_label="E_vs_V_%02d" % i, from_base_model=True, save_config=True) except Exception as e: print("failed", str(e)) break ase.io.write(sys.stdout, scaled_bulk, format='extxyz') E_vs_V.append( (scaled_bulk.get_volume()/len(scaled_bulk), scaled_bulk.get_potential_energy()/len(bulk), list(scaled_bulk.get_stress())) ) if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence() scaled_bulk.calc = model.calculator return E_vs_V
def do_lattice(test_dir, lattice_type, dV=0.025, n_steps=(-10,10), tol=1.0e-2, method='lbfgs', applied_P=0.0): import model bulk = ase.io.read(test_dir+"/bulk.xyz", format="extxyz") results_dict = {} print("relax bulk") # relax the initial unit cell and atomic positions (orig_cell, new_cell) = (None, None) while new_cell is None or np.max(np.abs(np.dot(np.linalg.inv(new_cell),orig_cell) - np.eye(3))) > 0.05: if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(bulk) orig_cell = bulk.get_cell() bulk = relax_config(bulk, relax_pos=True, relax_cell=True, tol=tol, save_traj=True, method=method, refine_symmetry_tol=1.0e-2, keep_symmetry=True, config_label="bulk", from_base_model=True, save_config=True, applied_P=applied_P) new_cell = bulk.get_cell() if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence() bulk.calc = model.calculator else: break print("final relaxed bulk") ase.io.write(sys.stdout, bulk, format='extxyz') ase.io.write(os.path.join("..",run_root+"-relaxed.xyz"), bulk, format='extxyz') print("calculating E vs. V") E_vs_V = calc_E_vs_V(bulk, dV=dV, n_steps=n_steps, tol=tol) results_dict.update({ 'E_vs_V' : E_vs_V }) print("calculating elastic constants") if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(bulk) bulk.calc = model.calculator opt = lambda atoms, **kwargs: PreconLBFGS(atoms, **kwargs) if lattice_type == 'cubic': elastic_consts = elasticity.fit_elastic_constants(bulk, symmetry='cubic', optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0,0]/GPa c12 = elastic_consts[0][0,1]/GPa c44 = elastic_consts[0][3,3]/GPa results_dict.update({'c11' : c11, 'c12': c12, 'c44' : c44, 'B' : (c11+2.0*c12)/3.0}) elif lattice_type == 'orthorhombic': elastic_consts = elasticity.fit_elastic_constants(bulk, optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0,0]/GPa c22 = elastic_consts[0][1,1]/GPa c33 = elastic_consts[0][2,2]/GPa c12 = elastic_consts[0][0,1]/GPa c13 = elastic_consts[0][0,2]/GPa c23 = elastic_consts[0][1,2]/GPa c44 = elastic_consts[0][3,3]/GPa c55 = elastic_consts[0][4,4]/GPa c66 = elastic_consts[0][5,5]/GPa results_dict.update({'c11' : c11, 'c22' : c22, 'c33' : c33, 'c12': c12, 'c13' : c13, 'c23' : c23, 'c44' : c44, 'c55' : c55, 'c66' : c66}) elif lattice_type == 'tetragonal': elastic_consts = elasticity.fit_elastic_constants(bulk, symmetry='tetragonal_high', optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0,0]/GPa c33 = elastic_consts[0][2,2]/GPa c12 = elastic_consts[0][0,1]/GPa c13 = elastic_consts[0][0,2]/GPa c44 = elastic_consts[0][3,3]/GPa c66 = elastic_consts[0][5,5]/GPa results_dict.update({'c11' : c11, 'c33' : c33, 'c12': c12, 'c13' : c13, 'c44' : c44, 'c66' : c66, 'B' : VRH_B(c11, c33, c12, c13, c44, c66)}) elif lattice_type == 'hexagonal': # Need to check if hexagonal structures are truly trigonal_high # symmetry=triginal_high not hexagonal until matscipy is debugged elastic_consts = elasticity.fit_elastic_constants(bulk, symmetry='trigonal_high', optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0,0]/GPa c33 = elastic_consts[0][2,2]/GPa c12 = elastic_consts[0][0,1]/GPa c13 = elastic_consts[0][0,2]/GPa c44 = elastic_consts[0][3,3]/GPa c14 = elastic_consts[0][0,3]/GPa c15 = elastic_consts[0][0,4]/GPa c25 = elastic_consts[0][1,4]/GPa c66 = elastic_consts[0][5,5]/GPa results_dict.update({'c11' : c11, 'c33' : c33, 'c12': c12, 'c13' : c13, 'c44' : c44, 'c14' : c14, 'c15' : c15, 'c25' : c25, 'c66' : c66, 'B' : HTT_B(c11, c33, c12, c13)}) elif lattice_type == 'trigonal': elastic_consts = elasticity.fit_elastic_constants(bulk, symmetry='trigonal_high', optimizer=opt, logfile=sys.stdout) c11 = elastic_consts[0][0,0]/GPa c33 = elastic_consts[0][2,2]/GPa c12 = elastic_consts[0][0,1]/GPa c13 = elastic_consts[0][0,2]/GPa c44 = elastic_consts[0][3,3]/GPa c14 = elastic_consts[0][0,3]/GPa c15 = elastic_consts[0][0,4]/GPa c25 = elastic_consts[0][1,4]/GPa c66 = elastic_consts[0][5,5]/GPa results_dict.update({'c11' : c11, 'c33' : c33, 'c12': c12, 'c13' : c13, 'c44' : c44, 'c14' : c14, 'c15' : c15, 'c25' : c25, 'c66' : c66, 'B' : HTT_B(c11, c33, c12, c13)}) if hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence() bulk.calc = model.calculator return results_dict
def relax_config(atoms, relax_pos, relax_cell, tol=1e-3, method='lbfgs', max_steps=200, save_traj=False, constant_volume=False, refine_symmetry_tol=None, keep_symmetry=False, strain_mask=None, config_label=None, from_base_model=False, save_config=False, try_restart=False, fix_cell_dependence=False, applied_P=0.0, hydrostatic_strain=False, **kwargs): # get from base model if requested import model if config_label is not None: save_file = run_root + '-' + config_label + '-relaxed.xyz' traj_file = run_root + '-' + config_label + '-traj.xyz' else: save_file = None traj_file = None if try_restart: # try from saved final config try: atoms = read(save_file, format='extxyz') print("relax_config read config from final file", save_file) return atoms except: pass # try from last config in traj file try: atoms_in = read(traj_file, -1, format='extxyz') # set positions from atoms_in rescaling to match current cell saved_cell = atoms.get_cell().copy() atoms.set_cell(atoms_in.get_cell()) atoms.set_positions(atoms_in.get_positions()) atoms.set_cell(saved_cell, scale_atoms=True) print("relax_config read config from traj", traj_file) except: pass else: if from_base_model: if config_label is None: raise ValueError( 'from_base_model is set but no config_label provided') try: base_run_file = os.path.join( '..', base_run_root, base_run_root + '-' + config_label + '-relaxed.xyz') atoms_in = read(base_run_file, format='extxyz') # set positions from atoms_in rescaling to match current cell saved_cell = atoms.get_cell().copy() atoms.set_cell(atoms_in.get_cell()) atoms.set_positions(atoms_in.get_positions()) atoms.set_cell(saved_cell, scale_atoms=True) print("relax_config read config from base model ", base_run_file) except: try: print("relax_config failed to read base run config from ", base_run_root + '-' + config_label + '-relaxed.xyz') except: print("relax_config failed to determined base_run_root") print("relax_config symmetry before refinement at default tol 1.0e-6") check_symmetry(atoms, 1.0e-6, verbose=True) if refine_symmetry_tol is not None: refine_symmetry(atoms, refine_symmetry_tol) print("relax_config symmetry after refinement") check_symmetry(atoms, refine_symmetry_tol, verbose=True) if keep_symmetry: print("relax_config trying to maintain symmetry") atoms.set_constraint(FixSymmetry(atoms)) # if needed, fix cell dependence before running if fix_cell_dependence and hasattr(model, "fix_cell_dependence"): model.fix_cell_dependence(atoms) atoms.set_calculator(model.calculator) if method == 'lbfgs' or method == 'sd2': if 'move_mask' in atoms.arrays: atoms.set_constraint( FixAtoms(np.where(atoms.arrays['move_mask'] == 0)[0])) if relax_cell: atoms_cell = ExpCellFilter(atoms, mask=strain_mask, constant_volume=constant_volume, scalar_pressure=applied_P * GPa, hydrostatic_strain=hydrostatic_strain) else: atoms_cell = atoms atoms.info["n_minim_iter"] = 0 if method == 'sd2': (traj, run_stat) = sd2_run("", atoms_cell, tol, lambda i: sd2_converged(i, atoms_cell, tol), max_steps) if save_traj is not None: write(traj_file, traj) else: # precon="Exp" specified to resolve an error with the lbfgs not optimising opt = PreconLBFGS(atoms_cell, use_armijo=False, **kwargs) if save_traj: traj = open(traj_file, "w") def write_trajectory(): if "n_minim_iter" in atoms.info: atoms.info["n_minim_iter"] += 1 write(traj, atoms, format='extxyz') traj.flush() opt.attach(write_trajectory) elif method == 'cg_n': raise ValueError( 'minim method cg_n not supported in new python3 quippy') # if strain_mask is not None: # raise(Exception("strain_mask not supported with method='cg_n'")) # atoms.info['Minim_Constant_Volume'] = constant_volume # opt = Minim(atoms, relax_positions=relax_pos, relax_cell=relax_cell, method='cg_n') else: raise ValueError('unknown method %s!' % method) if method != 'sd2': opt.run(tol, max_steps) if refine_symmetry_tol is not None: print("symmetry at end of relaxation at desired tol") check_symmetry(atoms, refine_symmetry_tol, verbose=True) print("symmetry at end of relaxation at default tol 1e-6") check_symmetry(atoms, 1.0e-6, verbose=True) # in case we had a trajectory saved try: traj.close() except: pass if save_config: if config_label is None: raise ValueError('save_config is set but no config_label provided') write(save_file, atoms, format='extxyz') if keep_symmetry: for (i_c, c) in enumerate(atoms.constraints): if isinstance(c, FixSymmetry): del atoms.constraints[i_c] break # undo fix cell dependence if fix_cell_dependence and hasattr(model, "fix_cell_dependence"): sys.stderr.write( "WARNING: relax_config undoing fix_cell_dependence, whether or not it was set before it started\n" ) model.fix_cell_dependence() atoms.calc = model.calculator return atoms