def _write_fdf_arguments(self, f): """Write directly given fdf-arguments. """ fdf_arguments = self.parameters['fdf_arguments'] fdf_arguments["XC.functional"], \ fdf_arguments["XC.authors"] = self.parameters['xc'] energy_shift = self['energy_shift'] fdf_arguments["PAO.EnergyShift"] = energy_shift mesh_cutoff = '%.4f eV' % self['mesh_cutoff'] fdf_arguments["MeshCutoff"] = mesh_cutoff if self['spin'] == 'UNPOLARIZED': fdf_arguments["SpinPolarized"] = False elif self['spin'] == 'COLLINEAR': fdf_arguments["SpinPolarized"] = True elif self['spin'] == 'FULL': fdf_arguments["SpinPolarized"] = True fdf_arguments["NonCollinearSpin"] = True for key, value in self.allowed_fdf_keywords.items(): if key in fdf_arguments.keys(): if key in self.unit_fdf_keywords: val = '%.8f %s' % (fdf_arguments[key], self.unit_fdf_keywords[key]) f.write(format_fdf(key, val)) elif fdf_arguments[key] != value: f.write(format_fdf(key, fdf_arguments[key]))
def write_input(self, atoms, properties=None, system_changes=None): """Write input (fdf)-file. See calculator.py for further details. Parameters: - atoms : The Atoms object to write. - properties : The properties which should be calculated. - system_changes : List of properties changed since last run. """ # Call base calculator. FileIOCalculator.write_input(self, atoms=atoms, properties=properties, system_changes=system_changes) if system_changes is None and properties is None: return filename = self.label + '.fdf' # On any changes, remove all analysis files. if system_changes is not None: self.remove_analysis() # Start writing the file. with open(filename, 'w') as f: # Write system name and label. f.write(format_fdf('SystemName', self.label)) f.write(format_fdf('SystemLabel', self.label)) f.write("\n") # Write the minimal arg self._write_species(f, atoms) self._write_structure(f, atoms) # First write explicitly given options to # allow the user to overwrite anything. self._write_fdf_arguments(f) # Use the saved density matrix if only 'cell' and 'positions' # haved changes. if (system_changes is None or ('numbers' not in system_changes and 'initial_magmoms' not in system_changes and 'initial_charges' not in system_changes)): f.write(format_fdf('DM.UseSaveDM', True)) # Save density. if 'density' in properties: f.write(format_fdf('SaveRho', True)) # Force siesta to return error on no convergence. # Why?? maybe we don't want to force convergency?? # f.write(format_fdf('SCFMustConverge', True)) self._write_kpts(f)
def write_input(self, atoms, properties=None, system_changes=None): """Write input (fdf)-file. See calculator.py for further details. Parameters: - atoms : The Atoms object to write. - properties : The properties which should be calculated. - system_changes : List of properties changed since last run. """ # Call base calculator. FileIOCalculator.write_input( self, atoms=atoms, properties=properties, system_changes=system_changes) if system_changes is None and properties is None: return filename = self.label + '.fdf' # On any changes, remove all analysis files. if system_changes is not None: self.remove_analysis() # Start writing the file. with open(filename, 'w') as f: # First write explicitly given options to # allow the user to overwrite anything. self._write_fdf_arguments(f) # Use the saved density matrix if only 'cell' and 'positions' # haved changes. if (system_changes is None or ('numbers' not in system_changes and 'initial_magmoms' not in system_changes and 'initial_charges' not in system_changes)): f.write(format_fdf('DM.UseSaveDM', True)) # Save density. if 'density' in properties: f.write(format_fdf('SaveRho', True)) # Write system name and label. f.write(format_fdf('SystemName', self.label)) f.write(format_fdf('SystemLabel', self.label)) # Force siesta to return error on no convergence. f.write(format_fdf('SCFMustConverge', True)) # Write the rest. self._write_species(f, atoms) self._write_kpts(f) self._write_structure(f, atoms)
def _write_fdf_arguments(self, f): """Write directly given fdf-arguments. """ fdf_arguments = self.parameters['fdf_arguments'] # Early return if fdf_arguments is None: return for key, value in fdf_arguments.iteritems(): if key in self.unit_fdf_keywords.keys(): value = ('%.8f ' % value, self.unit_fdf_keywords[key]) f.write(format_fdf(key, value)) elif key in self.allowed_fdf_keywords: f.write(format_fdf(key, value)) else: raise ValueError("%s not in allowed keywords." % key)
def _write_fdf_arguments(self, f): """Write directly given fdf-arguments. """ fdf_arguments = self.parameters['fdf_arguments'] # Early return if fdf_arguments is None: return for key, value in fdf_arguments.iteritems(): if key in self.unit_fdf_keywords.keys(): value = '%.8f %s' % (value, self.unit_fdf_keywords[key]) f.write(format_fdf(key, value)) elif key in self.allowed_fdf_keywords: f.write(format_fdf(key, value)) else: raise ValueError("%s not in allowed keywords." % key)
def _write_structure(self, f, atoms): """Translate the Atoms object to fdf-format. Parameters: - f: An open file object. - atoms: An atoms object. """ unit_cell = atoms.get_cell() xyz = atoms.get_positions() f.write('\n') f.write(format_fdf('NumberOfAtoms', len(xyz))) # Write lattice vectors default_unit_cell = np.eye(3, dtype=float) if np.any(unit_cell != default_unit_cell): f.write(format_fdf('LatticeConstant', '1.0 Ang')) f.write('%block LatticeVectors\n') for i in range(3): for j in range(3): s = string.rjust(' %.15f' % unit_cell[i, j], 16) + ' ' f.write(s) f.write('\n') f.write('%endblock LatticeVectors\n') f.write('\n') self._write_atomic_coordinates(f, atoms) # Write magnetic moments. magmoms = atoms.get_initial_magnetic_moments() # The DM.InitSpin block must be written to initialize to # no spin. SIESTA default is FM initialization, if the # block is not written, but we must conform to the # atoms object. if self['spin'] != 'UNPOLARIZED': f.write('%block DM.InitSpin\n') for n, M in enumerate(magmoms): if M != 0: f.write(' %d %.14f\n' % (n + 1, M)) f.write('%endblock DM.InitSpin\n') f.write('\n')
def _write_structure(self, f, atoms): """Translate the Atoms object to fdf-format. Parameters: - f: An open file object. - atoms: An atoms object. """ cell = atoms.cell f.write('\n') if cell.rank in [1, 2]: raise ValueError('Expected 3D unit cell or no unit cell. You may ' 'wish to add vacuum along some directions.') # Write lattice vectors if np.any(cell): f.write(format_fdf('LatticeConstant', '1.0 Ang')) f.write('%block LatticeVectors\n') for i in range(3): for j in range(3): s = (' %.15f' % cell[i, j]).rjust(16) + ' ' f.write(s) f.write('\n') f.write('%endblock LatticeVectors\n') f.write('\n') self._write_atomic_coordinates(f, atoms) # Write magnetic moments. magmoms = atoms.get_initial_magnetic_moments() # The DM.InitSpin block must be written to initialize to # no spin. SIESTA default is FM initialization, if the # block is not written, but we must conform to the # atoms object. if magmoms is not None: if len(magmoms) == 0: f.write('#Empty block forces ASE initialization.\n') f.write('%block DM.InitSpin\n') if len(magmoms) != 0 and isinstance(magmoms[0], np.ndarray): for n, Mcart in enumerate(magmoms): M = cart2sph(Mcart) if M[0] != 0: f.write(' %d %.14f %.14f %.14f \n' % (n + 1, M[0], M[1], M[2])) elif len(magmoms) != 0 and isinstance(magmoms[0], float): for n, M in enumerate(magmoms): if M != 0: f.write(' %d %.14f \n' % (n + 1, M)) f.write('%endblock DM.InitSpin\n') f.write('\n')
def _write_species(self, f, atoms): """Write input related the different species. Parameters: - f: An open file object. - atoms: An atoms object. """ species, species_numbers = self.species(atoms) if self['pseudo_path'] is not None: pseudo_path = self['pseudo_path'] elif 'SIESTA_PP_PATH' in os.environ: pseudo_path = os.environ['SIESTA_PP_PATH'] else: mess = "Please set the environment variable 'SIESTA_PP_PATH'" raise Exception(mess) f.write(format_fdf('NumberOfSpecies', len(species))) f.write(format_fdf('NumberOfAtoms', len(atoms))) pao_basis = [] chemical_labels = [] basis_sizes = [] synth_blocks = [] for species_number, spec in enumerate(species): species_number += 1 symbol = spec['symbol'] atomic_number = atomic_numbers[symbol] if spec['pseudopotential'] is None: if self.pseudo_qualifier() == '': label = symbol pseudopotential = label + '.psf' else: label = '.'.join([symbol, self.pseudo_qualifier()]) pseudopotential = label + '.psf' else: pseudopotential = spec['pseudopotential'] label = os.path.basename(pseudopotential) label = '.'.join(label.split('.')[:-1]) if not os.path.isabs(pseudopotential): pseudopotential = join(pseudo_path, pseudopotential) if not os.path.exists(pseudopotential): mess = "Pseudopotential '%s' not found" % pseudopotential raise RuntimeError(mess) name = os.path.basename(pseudopotential) name = name.split('.') name.insert(-1, str(species_number)) if spec['ghost']: name.insert(-1, 'ghost') atomic_number = -atomic_number name = '.'.join(name) pseudo_targetpath = self.getpath(name) if join(os.getcwd(), name) != pseudopotential: if islink(pseudo_targetpath) or isfile(pseudo_targetpath): os.remove(pseudo_targetpath) symlink_pseudos = self['symlink_pseudos'] if symlink_pseudos is None: symlink_pseudos = not os.name == 'nt' if symlink_pseudos: os.symlink(pseudopotential, pseudo_targetpath) else: shutil.copy(pseudopotential, pseudo_targetpath) if not spec['excess_charge'] is None: atomic_number += 200 n_atoms = sum(np.array(species_numbers) == species_number) paec = float(spec['excess_charge']) / n_atoms vc = get_valence_charge(pseudopotential) fraction = float(vc + paec) / vc pseudo_head = name[:-4] fractional_command = os.environ['SIESTA_UTIL_FRACTIONAL'] cmd = '%s %s %.7f' % (fractional_command, pseudo_head, fraction) os.system(cmd) pseudo_head += '-Fraction-%.5f' % fraction synth_pseudo = pseudo_head + '.psf' synth_block_filename = pseudo_head + '.synth' os.remove(name) shutil.copyfile(synth_pseudo, name) synth_block = read_vca_synth_block( synth_block_filename, species_number=species_number) synth_blocks.append(synth_block) if len(synth_blocks) > 0: f.write(format_fdf('SyntheticAtoms', list(synth_blocks))) label = '.'.join(np.array(name.split('.'))[:-1]) string = ' %d %d %s' % (species_number, atomic_number, label) chemical_labels.append(string) if isinstance(spec['basis_set'], PAOBasisBlock): pao_basis.append(spec['basis_set'].script(label)) else: basis_sizes.append((" " + label, spec['basis_set'])) f.write((format_fdf('ChemicalSpecieslabel', chemical_labels))) f.write('\n') f.write((format_fdf('PAO.Basis', pao_basis))) f.write((format_fdf('PAO.BasisSizes', basis_sizes))) f.write('\n')
def write_input(self, atoms, properties=None, system_changes=None): """Write input (fdf)-file. See calculator.py for further details. Parameters: - atoms : The Atoms object to write. - properties : The properties which should be calculated. - system_changes : List of properties changed since last run. """ # Call base calculator. FileIOCalculator.write_input( self, atoms=atoms, properties=properties, system_changes=system_changes) if system_changes is None and properties is None: return filename = self.getpath(ext='fdf') # On any changes, remove all analysis files. if system_changes is not None: self.remove_analysis() # Start writing the file. with open(filename, 'w') as f: # Write system name and label. f.write(format_fdf('SystemName', self.prefix)) f.write(format_fdf('SystemLabel', self.prefix)) f.write("\n") # Write explicitly given options first to # allow the user to override anything. fdf_arguments = self['fdf_arguments'] keys = sorted(fdf_arguments.keys()) for key in keys: f.write(format_fdf(key, fdf_arguments[key])) # Force siesta to return error on no convergence. # as default consistent with ASE expectations. if 'SCFMustConverge' not in fdf_arguments.keys(): f.write(format_fdf('SCFMustConverge', True)) f.write("\n") # Write spin level. f.write(format_fdf('Spin ', self['spin'])) # Spin backwards compatibility. if self['spin'] == 'collinear': f.write(format_fdf('SpinPolarized', (True, "# Backwards compatibility."))) elif self['spin'] == 'non-collinear': f.write(format_fdf('NonCollinear', (True, "# Backwards compatibility."))) # Write functional. functional, authors = self['xc'] f.write(format_fdf('XC.functional', functional)) f.write(format_fdf('XC.authors', authors)) f.write("\n") # Write mesh cutoff and energy shift. f.write(format_fdf('MeshCutoff', (self['mesh_cutoff'], 'eV'))) f.write(format_fdf('PAO.EnergyShift', (self['energy_shift'], 'eV'))) f.write("\n") # Write the minimal arg self._write_species(f, atoms) self._write_structure(f, atoms) # Use the saved density matrix if only 'cell' and 'positions' # have changed. if (system_changes is None or ('numbers' not in system_changes and 'initial_magmoms' not in system_changes and 'initial_charges' not in system_changes)): f.write(format_fdf('DM.UseSaveDM', True)) # Save density. if 'density' in properties: f.write(format_fdf('SaveRho', True)) self._write_kpts(f) if self['bandpath'] is not None: lines = bandpath2bandpoints(self['bandpath']) f.write(lines) f.write('\n')
def _write_species(self, f, atoms): """Write input related the different species. Parameters: - f: An open file object. - atoms: An atoms object. """ energy_shift = '%.4f eV' % self['energy_shift'] f.write('\n') f.write(format_fdf('PAO_EnergyShift', energy_shift)) mesh_cutoff = '%.4f eV' % self['mesh_cutoff'] f.write(format_fdf('MeshCutoff', mesh_cutoff)) species, species_numbers = self.species(atoms) if self['spin'] == 'UNPOLARIZED': f.write(format_fdf('SpinPolarized', False)) elif self['spin'] == 'COLLINEAR': f.write(format_fdf('SpinPolarized', True)) elif self['spin'] == 'FULL': f.write(format_fdf('SpinPolarized', True)) f.write(format_fdf('NonCollinearSpin', True)) functional, authors = self.parameters['xc'] f.write('\n') f.write(format_fdf('XC_functional', functional)) if authors is not None: f.write(format_fdf('XC_authors', authors)) f.write('\n') if not self['pseudo_path'] is None: pseudo_path = self['pseudo_path'] elif 'SIESTA_PP_PATH' in os.environ: pseudo_path = os.environ['SIESTA_PP_PATH'] else: mess = "Please set the environment variable 'SIESTA_PP_PATH'" raise Exception(mess) f.write(format_fdf('NumberOfSpecies', len(species))) pao_basis = [] chemical_labels = [] basis_sizes = [] for species_number, specie in enumerate(species): species_number += 1 symbol = specie['symbol'] atomic_number = atomic_numbers[symbol] if specie['pseudopotential'] is None: if self.pseudo_qualifier() == '': label = symbol pseudopotential = label + '.psf' else: label = '.'.join([symbol, self.pseudo_qualifier()]) pseudopotential = label + '.psf' else: pseudopotential = specie['pseudopotential'] label = os.path.basename(pseudopotential) label = '.'.join(label.split('.')[:-1]) if not os.path.isabs(pseudopotential): pseudopotential = join(pseudo_path, pseudopotential) if not os.path.exists(pseudopotential): mess = "Pseudopotential '%s' not found" % pseudopotential raise RuntimeError(mess) name = os.path.basename(pseudopotential) name = name.split('.') name.insert(-1, str(species_number)) if specie['ghost']: name.insert(-1, 'ghost') atomic_number = -atomic_number name = '.'.join(name) if join(os.getcwd(), name) != pseudopotential: if islink(name) or isfile(name): os.remove(name) os.symlink(pseudopotential, name) label = '.'.join(np.array(name.split('.'))[:-1]) string = ' %d %d %s' % (species_number, atomic_number, label) chemical_labels.append(string) if isinstance(specie['basis_set'], PAOBasisBlock): pao_basis.append(specie['basis_set'].script(label)) else: basis_sizes.append((label, specie['basis_set'])) f.write((format_fdf('ChemicalSpecieslabel', chemical_labels))) f.write('\n') f.write((format_fdf('PAO.Basis', pao_basis))) f.write((format_fdf('PAO.BasisSizes', basis_sizes))) f.write('\n')
def _write_species(self, f, atoms): """Write input related the different species. Parameters: - f: An open file object. - atoms: An atoms object. """ energy_shift = '%.4f eV' % self['energy_shift'] f.write('\n') f.write(format_fdf('PAO_EnergyShift', energy_shift)) mesh_cutoff = '%.4f eV' % self['mesh_cutoff'] f.write(format_fdf('MeshCutoff', mesh_cutoff)) species, species_numbers = self.species(atoms) if self['spin'] == 'UNPOLARIZED': f.write(format_fdf('SpinPolarized', False)) elif self['spin'] == 'COLLINEAR': f.write(format_fdf('SpinPolarized', True)) elif self['spin'] == 'FULL': f.write(format_fdf('SpinPolarized', True)) f.write(format_fdf('NonCollinearSpin', True)) functional, authors = self.parameters['xc'] f.write('\n') f.write(format_fdf('XC_functional', functional)) if authors is not None: f.write(format_fdf('XC_authors', authors)) f.write('\n') if not self['pseudo_path'] is None: pseudo_path = self['pseudo_path'] elif 'SIESTA_PP_PATH' in os.environ: pseudo_path = os.environ['SIESTA_PP_PATH'] else: mess = "Please set the environment variable 'SIESTA_PP_PATH'" raise Exception(mess) f.write(format_fdf('NumberOfSpecies', len(species))) pao_basis = [] chemical_labels = [] basis_sizes = [] synth_blocks = [] for species_number, specie in enumerate(species): species_number += 1 symbol = specie['symbol'] atomic_number = atomic_numbers[symbol] if specie['pseudopotential'] is None: if self.pseudo_qualifier() == '': label = symbol pseudopotential = label + '.psf' else: label = '.'.join([symbol, self.pseudo_qualifier()]) pseudopotential = label + '.psf' else: pseudopotential = specie['pseudopotential'] label = os.path.basename(pseudopotential) label = '.'.join(label.split('.')[:-1]) if not os.path.isabs(pseudopotential): pseudopotential = join(pseudo_path, pseudopotential) if not os.path.exists(pseudopotential): mess = "Pseudopotential '%s' not found" % pseudopotential raise RuntimeError(mess) name = os.path.basename(pseudopotential) name = name.split('.') name.insert(-1, str(species_number)) if specie['ghost']: name.insert(-1, 'ghost') atomic_number = -atomic_number name = '.'.join(name) if join(os.getcwd(), name) != pseudopotential: if islink(name) or isfile(name): os.remove(name) os.symlink(pseudopotential, name) if not specie['excess_charge'] is None: atomic_number += 200 n_atoms = sum(np.array(species_numbers) == species_number) paec = float(specie['excess_charge']) / n_atoms vc = get_valence_charge(pseudopotential) fraction = float(vc + paec) / vc pseudo_head = name[:-4] fractional_command = os.environ['SIESTA_UTIL_FRACTIONAL'] cmd = '%s %s %.7f' % (fractional_command, pseudo_head, fraction) os.system(cmd) pseudo_head += '-Fraction-%.5f' % fraction synth_pseudo = pseudo_head + '.psf' synth_block_filename = pseudo_head + '.synth' os.remove(name) shutil.copyfile(synth_pseudo, name) synth_block = read_vca_synth_block( synth_block_filename, species_number=species_number) synth_blocks.append(synth_block) if len(synth_blocks) > 0: f.write(format_fdf('SyntheticAtoms', list(synth_blocks))) label = '.'.join(np.array(name.split('.'))[:-1]) string = ' %d %d %s' % (species_number, atomic_number, label) chemical_labels.append(string) if isinstance(specie['basis_set'], PAOBasisBlock): pao_basis.append(specie['basis_set'].script(label)) else: basis_sizes.append((label, specie['basis_set'])) f.write((format_fdf('ChemicalSpecieslabel', chemical_labels))) f.write('\n') f.write((format_fdf('PAO.Basis', pao_basis))) f.write((format_fdf('PAO.BasisSizes', basis_sizes))) f.write('\n')