def calculate(self, atoms): ''' Blocking/Non-blocking calculate method If we are in blocking mode we just run, wait for the job to end and read in the results. Easy ... The non-blocking mode is a little tricky. We need to start the job and guard against it reading back possible old data from the directory - the queuing system may not even started the job when we get control back from the starting script. Thus anything we read after invocation is potentially garbage - even if it is a converged calculation data. We handle it by custom run function above which raises an exception after submitting the job. This skips post-run processing in the calculator, preserves the state of the data and signals here that we need to wait for results. ''' with work_dir(self.working_dir): self.prepare_calc_dir() self.calc_running = True #print('Run VASP.calculate') try: Vasp.calculate(self, atoms) self.calc_running = False #print('VASP.calculate returned') except _NonBlockingRunException as e: # We have nothing else to docs # until the job finishes #print('Interrupted ', self.working_dir, os.getcwd()) pass
def calculate(self, atoms): ''' Blocking/Non-blocking calculate method If we are in blocking mode we just run, wait for the job to end and read in the results. Easy ... The non-blocking mode is a little tricky. We need to start the job and guard against it reading back possible old data from the directory - the queuing system may not even started the job when we get control back from the starting script. Thus anything we read after invocation is potentially garbage - even if it is a converged calculation data. We handle it by custom run function above which raises an exception after submitting the job. This skips post-run processing in the calculator, preserves the state of the data and signals here that we need to wait for results. ''' with work_dir(self.working_dir) : self.prepare_calc_dir() self.calc_running=True #print('Run VASP.calculate') try : Vasp.calculate(self, atoms) self.calc_running=False #print('VASP.calculate returned') except _NonBlockingRunException as e: # We have nothing else to docs # until the job finishes #print('Interrupted ', self.working_dir, os.getcwd()) pass
def vasp_vol_relax(): Al = bulk('Al', 'fcc', a=4.5, cubic=True) calc = Vasp(xc='LDA', isif=7, nsw=5, ibrion=1, ediffg=-1e-3, lwave=False, lcharg=False) calc.calculate(Al) # Explicitly parse atomic position output file from Vasp CONTCAR_Al = io.read('CONTCAR', format='vasp') print('Stress after relaxation:\n', calc.read_stress()) print('Al cell post relaxation from calc:\n', calc.get_atoms().get_cell()) print('Al cell post relaxation from atoms:\n', Al.get_cell()) print('Al cell post relaxation from CONTCAR:\n', CONTCAR_Al.get_cell()) # All the cells should be the same. assert (calc.get_atoms().get_cell() == CONTCAR_Al.get_cell()).all() assert (Al.get_cell() == CONTCAR_Al.get_cell()).all() return Al
def test_not_atoms(bad_atoms): """Check that passing in objects which are not actually Atoms objects raises a setup error """ with pytest.raises(CalculatorSetupError): check_atoms_type(bad_atoms) with pytest.raises(CalculatorSetupError): check_atoms(bad_atoms) # Test that error is also raised properly when launching # from calculator calc = Vasp() with pytest.raises(CalculatorSetupError): calc.calculate(atoms=bad_atoms)
def vasp_vol_relax(): Al = bulk("Al", "fcc", a=4.5, cubic=True) calc = Vasp(xc="LDA", isif=7, nsw=5, ibrion=1, ediffg=-1e-3, lwave=False, lcharg=False) calc.calculate(Al) # Explicitly parse atomic position output file from Vasp CONTCAR_Al = io.read("CONTCAR", format="vasp") print("Stress after relaxation:\n", calc.read_stress()) print("Al cell post relaxation from calc:\n", calc.get_atoms().get_cell()) print("Al cell post relaxation from atoms:\n", Al.get_cell()) print("Al cell post relaxation from CONTCAR:\n", CONTCAR_Al.get_cell()) # All the cells should be the same. assert (calc.get_atoms().get_cell() == CONTCAR_Al.get_cell()).all() assert (Al.get_cell() == CONTCAR_Al.get_cell()).all() return Al
def vasp_vol_relax(): Al = bulk('Al', 'fcc', a=4.5, cubic=True) calc = Vasp(xc='LDA', isif=7, nsw=5, ibrion=1, ediffg=-1e-3, lwave=False, lcharg=False) calc.calculate(Al) # Explicitly parse atomic position output file from Vasp CONTCAR_Al = io.read('CONTCAR', format='vasp') print 'Stress after relaxation:\n', calc.read_stress() print 'Al cell post relaxation from calc:\n', calc.get_atoms().get_cell() print 'Al cell post relaxation from atoms:\n', Al.get_cell() print 'Al cell post relaxation from CONTCAR:\n', CONTCAR_Al.get_cell() # All the cells should be the same. assert (calc.get_atoms().get_cell() == CONTCAR_Al.get_cell()).all() assert (Al.get_cell() == CONTCAR_Al.get_cell()).all() return Al
def test_vasp_charge(): """ Run VASP tests to ensure that determining number of electrons from user-supplied charge works correctly. This is conditional on the existence of the VASP_COMMAND or VASP_SCRIPT environment variables. """ from ase.build import bulk from ase.calculators.vasp import Vasp from ase.test import must_raise from ase.test.vasp import installed assert installed() system = bulk('Al', 'fcc', a=4.5, cubic=True) # Dummy calculation to let VASP determine default number of electrons calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False) calc.calculate(system) default_nelect_from_vasp = calc.get_number_of_electrons() assert default_nelect_from_vasp == 12 # Make sure that no nelect was written into INCAR yet (as it wasn't necessary) calc = Vasp() calc.read_incar() assert calc.float_params['nelect'] is None # Compare VASP's output nelect from before minus charge to default nelect # determined by us minus charge charge = -2 calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, charge=charge) calc.initialize(system) calc.write_input(system) calc.read_incar() assert calc.float_params['nelect'] == default_nelect_from_vasp - charge # Test that conflicts between explicitly given nelect and charge are detected with must_raise(ValueError): calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, nelect=default_nelect_from_vasp-charge+1, charge=charge) calc.calculate(system) # Test that nothing is written if charge is 0 and nelect not given calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, charge=0) calc.initialize(system) calc.write_input(system) calc.read_incar() assert calc.float_params['nelect'] is None # Test that explicitly given nelect still works as expected calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, nelect=15) calc.calculate(system) assert calc.get_number_of_electrons() == 15
Should be removed along with the net_charge parameter itself at some point. """ from ase.build import bulk from ase.calculators.vasp import Vasp from ase.test import must_raise, must_warn from ase.test.vasp import installed assert installed() system = bulk('Al', 'fcc', a=4.5, cubic=True) # Dummy calculation to let VASP determine default number of electrons calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False) calc.calculate(system) default_nelect_from_vasp = calc.get_number_of_electrons() assert default_nelect_from_vasp == 12 # Compare VASP's output nelect from before + net charge to default nelect # determined by us + net charge with must_warn(FutureWarning): net_charge = -2 calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, net_charge=net_charge) calc.initialize(system)
os.environ['VASP_COMMAND'] = "srun --cpu_bind=cores vasp_std" ##### from numpy import loadtxt temp = loadtxt('temperature.txt') ### minimal tags to run from ase.calculators.vasp import Vasp calc = Vasp(xc='PBE', setups='minimal', kpts=kpts) ### good tags to set calc.set(prec='Accurate', ediff=1E-8 * len(atoms), encut=450, algo='Fast', ispin=1, nelm=200, lmaxmix=4) calc.set(lreal='Auto') ################ molecular dynamics ########### ### vasp settings calc.set(isym=0, ibrion=0) # turn on MD calc.set(nsw=10000, potim=1.0) # 10000 steps, 2.0 fs step #calc.set(smass=-3, tebeg = 300 )# NVE, tebeg sets the intial random velocities calc.set(smass=0, tebeg=temp[0], teend=temp[1]) # Nose thermostat, NVT calc.calculate(atoms)
def test_vasp_net_charge(): """ Run VASP tests to ensure that determining number of electrons from user-supplied net charge (via the deprecated net_charge parameter) works correctly. This is conditional on the existence of the VASP_COMMAND or VASP_SCRIPT environment variables. This is mainly a slightly reduced duplicate of the vasp_charge test, but with flipped signs and with checks that ensure FutureWarning is emitted. Should be removed along with the net_charge parameter itself at some point. """ from ase.build import bulk from ase.calculators.vasp import Vasp from ase.test import must_raise, must_warn from ase.test.vasp import installed assert installed() system = bulk('Al', 'fcc', a=4.5, cubic=True) # Dummy calculation to let VASP determine default number of electrons calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False) calc.calculate(system) default_nelect_from_vasp = calc.get_number_of_electrons() assert default_nelect_from_vasp == 12 # Compare VASP's output nelect from before + net charge to default nelect # determined by us + net charge with must_warn(FutureWarning): net_charge = -2 calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, net_charge=net_charge) calc.initialize(system) calc.write_input(system) calc.read_incar() assert calc.float_params['nelect'] == default_nelect_from_vasp + net_charge # Test that conflicts between explicitly given nelect and net charge are # detected with must_raise(ValueError): with must_warn(FutureWarning): calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, nelect=default_nelect_from_vasp + net_charge + 1, net_charge=net_charge) calc.calculate(system) # Test that conflicts between charge and net_charge are detected with must_raise(ValueError): with must_warn(FutureWarning): calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, charge=-net_charge - 1, net_charge=net_charge) calc.calculate(system) # Test that nothing is written if net charge is 0 and nelect not given with must_warn(FutureWarning): calc = Vasp(xc='LDA', nsw=-1, ibrion=-1, nelm=1, lwave=False, lcharg=False, net_charge=0) calc.initialize(system) calc.write_input(system) calc.read_incar() assert calc.float_params['nelect'] is None
def run_task(self, fw_spec): # if encode is given, use it as input structure if 'encode' in self: atoms = encode_to_atoms(self['encode']) # else, read the input structure from the output of the previous step else: job_info_array = fw_spec['_job_info'] prev_job_info = job_info_array[-1] atoms = read(os.path.join(prev_job_info['launch_dir'], 'OUTCAR')) if 'pert_step' in self: atom_ucalc = Element(self['atom_ucalc']) elem_list_sorted, indices = np.unique(atoms.get_chemical_symbols(), return_index=True) elem_list = elem_list_sorted[np.argsort(indices)] self['calc_params']['ldaul'] = [] self['calc_params']['ldauu'] = [] self['calc_params']['ldauj'] = [] for atom in elem_list: if atom == self['dummy_atom']: if atom_ucalc.is_transition_metal: self['calc_params']['ldaul'].append(2) elif atom_ucalc.is_lanthanoid or atom_ucalc.is_actinoid: self['calc_params']['ldaul'].append(3) else: raise ValueError( f"Cannot calculate U for the element {self['atom_ucalc']}" ) self['calc_params']['ldauu'].append(self['pert_value']) self['calc_params']['ldauj'].append(self['pert_value']) else: self['calc_params']['ldaul'].append(-1) self['calc_params']['ldauu'].append(0) self['calc_params']['ldauj'].append(0) self['calc_params']['ldau'] = True self['calc_params']['ldautype'] = 3 job_info_array = fw_spec['_job_info'] prev_job_info = job_info_array[-1] shutil.copy(os.path.join(prev_job_info['launch_dir'], 'WAVECAR'), '.') # if pert_step is NSC, copy CHGCAR from previous step if self['pert_step'] == 'NSC': shutil.copy( os.path.join(prev_job_info['launch_dir'], 'CHGCAR'), '.') self['calc_params']['icharg'] = 11 # if magnetic calculation if 'magmoms' in self: if self['magmoms'] == 'previous': assert 'encode' not in self magmoms = atoms.get_magnetic_moments().round() else: magmoms = np.array(self['magmoms']) if magmoms.any(): # add the necessary VASP parameters self['calc_params']['lorbit'] = 11 self['calc_params']['ispin'] = 2 atoms.set_initial_magnetic_moments(magmoms) # convert any lists from the parameter settings into arrays keys = self['calc_params'] for k, v in keys.items(): if isinstance(v, list): keys[k] = np.asarray(v) # initialize and run VASP calc = Vasp(**self['calc_params']) calc.calculate(atoms) # save information about convergence with open('is_converged', 'w') as f1: for filename in os.listdir('.'): if filename.endswith('.out'): with open(filename, 'r') as f2: if calc.converged is False and 'fatal error in bracketing' not in f2.read( ): f1.write('NONCONVERGED') else: f1.write('converged')