def _geometry_block(outstr, indict, atom_props): # Geometry outstr += "EXTERNAL\n" # we assume external geometry # Geometry Optional Keywords (including optimisation) for keyword in get_keys(indict, ["geometry", "info_print"], []): outstr += "{}\n".format(keyword) for keyword in get_keys(indict, ["geometry", "info_external"], []): outstr += "{}\n".format(keyword) if "optimise" in indict.get("geometry", {}): outstr += "OPTGEOM\n" outstr += format_value(indict, ["geometry", "optimise", "type"]) unfixed = atom_props.get("unfixed", []) if unfixed: outstr += "FRAGMENT\n" outstr += "{}\n".format(len(unfixed)) outstr += " ".join([str(a) for a in sorted(unfixed)]) + " \n" outstr += format_value(indict, ["geometry", "optimise", "hessian"]) outstr += format_value(indict, ["geometry", "optimise", "gradient"]) for keyword in get_keys(indict, ["geometry", "optimise", "info_print"], []): outstr += "{}\n".format(keyword) outstr += format_value(indict, ["geometry", "optimise", "convergence"]) outstr += "ENDOPT\n" # Geometry End outstr += "END\n" return outstr
def _read_geom_block(lines, output_dict, schema): while lines[0].strip() not in ["OPTGEOM", "END"]: line = _pop_line(lines) if line in [ "FIELD", "FIELDCON", "CPHF", "ELASTCON", "EOS", "FREQCALC", "ANHARM", "CONFCNT", "CONFRAND", "RUNCONFS", "MOLEBSSE", "ATOMBSSE" ]: raise NotImplementedError("Geometry Block: {}".format(line)) elif line in get_keys( schema, [ "properties", "geometry", "properties", "info_print", "items", "enum" ], raise_error=True): _append_key(output_dict, "geometry.info_print", line) elif line in get_keys( schema, [ "properties", "geometry", "properties", "info_external", "items", "enum" ], raise_error=True): _append_key(output_dict, "geometry.info_external", line)
def _read_geomopt_block(atom_props, line, lines, output_dict, schema): if lines[0].strip().startswith("END"): output_dict["geometry.optimise"] = True while not lines[0].strip().startswith("END"): line = _pop_line(lines) if line in ["EXTPRESS"]: raise NotImplementedError("GeomOpt Block: {}".format(line)) elif line in get_keys( schema, [ "properties", "geometry", "properties", "optimise", "properties", "type", "enum" ], raise_error=True): output_dict["geometry.optimise.type"] = line elif line in get_keys( schema, [ "properties", "geometry", "properties", "optimise", "properties", "hessian", "enum" ], raise_error=True): output_dict["geometry.optimise.hessian"] = line elif line in get_keys( schema, [ "properties", "geometry", "properties", "optimise", "properties", "gradient", "enum" ], raise_error=True): output_dict["geometry.optimise.gradient"] = line elif line in get_keys( schema, [ "properties", "geometry", "properties", "optimise", "properties", "info_print", "items", "enum" ], raise_error=True): _append_key(output_dict, "geometry.optimise.info_print", line) elif line in get_keys( schema, [ "properties", "geometry", "properties", "optimise", "properties", "convergence", "properties" ], raise_error=True).keys(): key = "geometry.optimise.convergence.{}".format(line) line = _pop_line(lines) try: output_dict[key] = int(line) except ValueError: output_dict[key] = float(line) elif line == "FRAGMENT": val, line = _get_atom_prop(lines, "fragment") atom_props["fragment"] = val else: raise NotImplementedError("OPTGEOM block: {}".format(line)) line = _pop_line(lines, 2) return line
def _hamiltonian_block(outstr, indict, atom_props): # Hamiltonian Optional Keywords outstr += format_value(indict, ["scf", "single"]) # DFT Optional Block if get_keys(indict, ["scf", "dft"], False): outstr += "DFT\n" xc = get_keys(indict, ["scf", "dft", "xc"], raise_error=True) if isinstance(xc, (tuple, list)): if len(xc) == 2: outstr += "CORRELAT\n" outstr += "{}\n".format(xc[0]) outstr += "EXCHANGE\n" outstr += "{}\n".format(xc[1]) else: outstr += format_value(indict, ["scf", "dft", "xc"]) if get_keys(indict, ["scf", "dft", "SPIN"], False): outstr += "SPIN\n" outstr += format_value(indict, ["scf", "dft", "grid"]) outstr += format_value(indict, ["scf", "dft", "grid_weights"]) outstr += format_value(indict, ["scf", "dft", "numerical"]) outstr += "END\n" # # K-POINTS (SHRINK\nPMN Gilat) outstr += "SHRINK\n" outstr += "{0} {1}\n".format( *get_keys(indict, ["scf", "k_points"], raise_error=True)) # ATOMSPIN spins = [] for anum in atom_props.get("spin_alpha", []): spins.append((anum, 1)) for anum in atom_props.get("spin_beta", []): spins.append((anum, -1)) if spins: outstr += "ATOMSPIN\n" outstr += "{}\n".format(len(spins)) for anum, spin in sorted(spins): outstr += "{0} {1}\n".format(anum, spin) # SCF/Other Optional Keywords outstr += format_value(indict, ["scf", "numerical"]) outstr += format_value(indict, ["scf", "fock_mixing"]) outstr += format_value(indict, ["scf", "spinlock"]) for keyword in get_keys(indict, ["scf", "post_scf"], []): outstr += "{}\n".format(keyword) # Hamiltonian and SCF End outstr += "END\n" return outstr
def _read_dft_block(lines, output_dict, schema): correlat = None exchange = None while lines[0].strip() != "END": line = _pop_line(lines) if line == "SPIN": output_dict["scf.dft.SPIN"] = True elif line in get_keys( schema, [ "properties", "scf", "properties", "dft", "properties", "xc", "oneOf", 1, "enum" ], raise_error=True): output_dict["scf.dft.xc"] = line elif line == "CORRELAT": line = _pop_line(lines) correlat = line elif line == "EXCHANGE": line = _pop_line(lines) exchange = line elif line == "LSRSH-PBE": line = _pop_line(lines) output_dict["scf.dft.xc.LSRSH-PBE"] = _split_line(line) elif line in get_keys( schema, [ "properties", "scf", "properties", "dft", "properties", "grid", "enum" ], raise_error=True): output_dict["scf.dft.grid"] = line elif line in get_keys( schema, [ "properties", "scf", "properties", "dft", "properties", "grid_weights", "enum" ], raise_error=True): output_dict["scf.dft.grid_weights"] = line elif line in get_keys( schema, [ "properties", "scf", "properties", "dft", "properties", "numerical", "properties" ], raise_error=True).keys(): key = line line = _pop_line(lines) output_dict["scf.dft.numerical.{}".format(key)] = _split_line(line) else: raise NotImplementedError("DFT Block: {}".format(line)) if (correlat, exchange) != (None, None): if None in (correlat, exchange): raise IOError("found only one of CORRELAT EXCHANGE: {} {}".format( correlat, exchange)) output_dict["scf.dft.xc"] = (exchange, correlat)
def _read_hamiltonian_block(atom_props, lines, output_dict, schema): sblock = ["properties", "scf", "properties"] while lines[0].strip() != "END": line = _pop_line(lines) if line == "DFT": _read_dft_block(lines, output_dict, schema) line = _pop_line(lines) elif line == "SHRINK": line = _pop_line(lines) try: kis, kisp = line.split() kis = int(kis) kisp = int(kisp) except ValueError: raise IOError( "expecting SHRINK in form 'is isp': {}".format(line)) output_dict["scf.k_points"] = (kis, kisp) elif line in get_keys( schema, sblock + ["single", "enum"], raise_error=True): output_dict["scf.single"] = line elif line in get_keys( schema, sblock + ["numerical", "properties"], raise_error=True).keys(): key = line if get_keys( schema, sblock + ["numerical", "properties", key, "type"], raise_error=True) == "boolean": output_dict["scf.numerical.{}".format(key)] = True else: line = _pop_line(lines) output_dict["scf.numerical.{}".format(key)] = _split_line(line) elif line in get_keys( schema, sblock + ["post_scf", "items", "enum"], raise_error=True): _append_key(output_dict, "scf.post_scf", line) elif line in get_keys( schema, sblock + ["spinlock", "properties"], raise_error=True).keys(): key = line line = _pop_line(lines) output_dict["scf.spinlock.{}".format(key)] = _split_line(line) elif line in get_keys( schema, sblock + ["fock_mixing", "oneOf", 0, "enum"], raise_error=True): output_dict["scf.fock_mixing"] = line elif line == "BROYDEN": line = _pop_line(lines) output_dict["scf.fock_mixing.BROYDEN"] = _split_line(line) elif line == "ATOMSPIN": val, line = _get_atom_prop(lines, "atomspin") atom_props["spin_alpha"] = val[0] atom_props["spin_beta"] = val[1] else: raise NotImplementedError("Hamiltonian Block: {}".format(line))
def write_input(indict, basis_sets, atom_props=None): """write input of a validated input dictionary :param indict: dictionary of input :param basis_sets: list of basis set strings or objects with `content` property :param atom_props: dictionary of atom ids with specific properties ("spin_alpha", "spin_beta", "unfixed", "ghosts") :return: """ # validation validate_with_json(indict) if not basis_sets: raise ValueError("there must be at least one basis set") elif not (all([isinstance(b, six.string_types) for b in basis_sets]) or all([hasattr(b, "content") for b in basis_sets])): raise ValueError( "basis_sets must be either all strings or all objects with a `content` property" ) if atom_props is None: atom_props = {} if not set(atom_props.keys()).issubset( ["spin_alpha", "spin_beta", "unfixed", "ghosts"]): raise ValueError( "atom_props should only contain: 'spin_alpha', 'spin_beta', 'unfixed', 'ghosts'" ) # validate that a index isn't in both spin_alpha and spin_beta allspin = atom_props.get("spin_alpha", []) + atom_props.get( "spin_beta", []) if len(set(allspin)) != len(allspin): raise ValueError( "a kind cannot be in both spin_alpha and spin_beta: {}".format( allspin)) outstr = "" # Title title = get_keys(indict, ["title"], "CRYSTAL run") outstr += "{}\n".format(" ".join(title.splitlines())) # must be one line outstr = _geometry_block(outstr, indict, atom_props) outstr = _basis_set_block(outstr, indict, basis_sets, atom_props) outstr = _hamiltonian_block(outstr, indict, atom_props) return outstr
def format_value(dct, keys): """return the value + a new line, or empty string if keys not found""" value = get_keys(dct, keys, None) if value is None: return "" if isinstance(value, dict): outstr = "" for keyword in value.keys(): args = value[keyword] if isinstance(args, bool): if args: outstr += "{}\n".format(keyword) elif isinstance(args, (list, tuple)): outstr += "{0}\n{1}\n".format(keyword, " ".join([str(a) for a in args])) else: outstr += "{0}\n{1}\n".format(keyword, args) return outstr return "{}\n".format(value)
def _read_basis_block(atom_props, basis_sets, lines, output_dict, schema): basis_lines = [] while not lines[0].startswith("99 "): line = _pop_line(lines) basis_lines.append(line) try: anum, nshells = line.split() # pylint: disable=unused-variable nshells = int(nshells) except ValueError: raise IOError("expected 'anum nshells': {}".format(line)) for i in range(nshells): line = _pop_line(lines) basis_lines.append(line) try: btype, stype, nfuncs, _, _ = line.split() btype, stype, nfuncs = [int(i) for i in [btype, stype, nfuncs]] # charge, scale = [float(i) for i in [charge, scale]] except ValueError: raise IOError( "expected 'btype, stype, nfuncs, charge, scale': {}". format(line)) if btype == 0: for _ in range(nfuncs): line = _pop_line(lines) basis_lines.append(line) basis_sets.append("\n".join(basis_lines)) basis_lines = [] line = _pop_line(lines) while lines[0].strip() != "END": line = _pop_line(lines) if line in get_keys( schema, ["properties", "basis_set", "properties"], raise_error=True).keys(): output_dict["basis_set.{}".format(line)] = True elif line == "GHOSTS": val, line = _get_atom_prop(lines, "ghosts") atom_props["ghosts"] = val else: raise NotImplementedError("Basis Set Block: {}".format(line))