def _nto_pairs( molecule: mtr.Molecule, settings: mtr.Settings, num_nto_pairs: int, n_x: int, n_y: int, n_z: int, ) -> mtr.QChemInput: # number of alpha electrons n_alpha = int(round((sum(molecule.atomic_numbers) + molecule.charge) / 2)) inp = mtr.QChemInput(settings=mtr.Settings()) for i in range(settings["rem", "cis_n_roots"]): s = copy.deepcopy(settings) s["rem", "scf_guess"] = "read" s["rem", "skip_cis_rpa"] = True s["rem", "nto_pairs"] = True s["rem", "make_cube_files"] = "ntos" s["rem", "cubefile_state"] = i + 1 s["plots", "comment"] = ( f"\n {n_x} -10.0 10.0\n" + f" {n_y} -10.0 10.0\n" + f" {n_z} -10.0 10.0\n" + f" {2*num_nto_pairs} 0 0 0\n " + " ".join(f"{n_alpha + i}" for i in range(-num_nto_pairs + 1, num_nto_pairs + 1))) inp += mtr.QChemInput(settings=s) return inp
def compute( self, molecule: mtr.Molecule, settings: Optional[mtr.Settings] = None, ) -> mtr.Quantity: s = mtr.Settings() if settings is None else copy.deepcopy(settings) input_settings = self.defaults(s) neutral_sp = self.engine.single_point_frontier(self.gs_io, name="neutral") cation_sp = self.engine.single_point(self.cation_io, name="cation") anion_sp = self.engine.single_point(self.anion_io, name="anion") cation = copy.deepcopy(molecule) cation.charge += 1 cation.multiplicity = cation.multiplicity % 2 + 1 anion = copy.deepcopy(molecule) anion.charge -= 1 anion.multiplicity = anion.multiplicity % 2 + 1 neutral_sp.requires( molecule=molecule, settings=input_settings, ) cation_sp.requires( molecule=cation, settings=input_settings, ) anion_sp.requires( molecule=anion, settings=input_settings, ) wf = Workflow(neutral_sp, cation_sp, anion_sp) out = wf.compute() neutral, h**o, lumo = out["neutral"] cation = out["cation"] anion = out["anion"] ea = neutral - anion ip = cation - neutral J_squared = (ip + h**o)**2 if ea > 0 * ea.unit: J_squared += (ea + lumo)**2 return np.sqrt(J_squared.convert(mtr.eV**2).value.item()) * mtr.eV
def compute( self, molecule: mtr.Molecule, settings: Optional[mtr.Settings] = None, arguments: Optional[Iterable[str]] = None, ) -> Any: s = mtr.Settings() if settings is None else copy.deepcopy(settings) inp = mtr.QChemInput(molecule, settings=self.defaults(s)) with self.io() as io: inp.write(io.inp) self.engine.execute(self.io, arguments=arguments) return self.parse(io.out)
def _objective(omega: float, _alpha: float) -> float: beta = 1 / epsilon - _alpha s = mtr.Settings() if settings is None else copy.deepcopy(settings) s = self.defaults(s) s["rem", "hf_sr"] = int(round(1000 * _alpha)) s["rem", "hf_lr"] = int(1000 / epsilon) s["xc_functional"] = ( ("X", "HF", _alpha), ("X", "wPBE", beta), ("X", "PBE", 1 - _alpha - beta), ("C", "PBE", 1.0), ) omega = int(round(1000 * omega)) s["rem", "omega"] = s["rem", "omega2"] = omega wd = mtr.expand(f"{io.work_dir}/{omega}") gs_io = mtr.IO("gs.in", "gs.out", wd) cation_io = mtr.IO("cation.in", "cation.out", wd) anion_io = mtr.IO("anion.in", "anion.out", wd) ke = self.engine.koopman_error(gs_io, cation_io, anion_io) return ke.compute(molecule, s).value
def compute( self, molecule: mtr.Molecule, settings: Optional[mtr.Settings] = None, num_nto_pairs: Optional[int] = 0, n_x: Optional[int] = 50, n_y: Optional[int] = 50, n_z: Optional[int] = 50, ) -> mtr.Molecule: s = mtr.Settings() if settings is None else copy.deepcopy(settings) inp = mtr.QChemInput(molecule, settings=self.defaults(s)) if num_nto_pairs > 0: inp += _nto_pairs(molecule, s, num_nto_pairs, n_x, n_y, n_z) with self.io() as io: inp.write(io.inp) self.engine.execute(self.io) molecule.electronic_excitations = self.parse(io.out) return molecule
def __add__(self, other: mtr.QChemInput) -> str: return QChemInput(string=str(self) + "\n@@@\n\n" + str(other), settings=mtr.Settings())
def test_write_qchem_tdscf(): settings = materia.Settings( dt=0.02, Stabilize=0, TCLOn=0, MaxIter=100, ApplyImpulse=1, ApplyCw=0, FieldFreq=0.7, Tau=0.07, FieldAmplitude=0.001, ExDir=1.0, EyDir=1.0, EzDir=1.0, Print=0, StatusEvery=10, SaveDipoles=1, DipolesEvery=2, SavePopulations=0, SaveFockEnergies=0, WriteDensities=0, SaveEvery=500, FourierEvery=5000, MMUT=1, LFLPPC=0, ) out_str = textwrap.dedent(""" dt=0.02 Stabilize=0 TCLOn=0 MaxIter=100 ApplyImpulse=1 ApplyCw=0 FieldFreq=0.7 Tau=0.07 FieldAmplitude=0.001 ExDir=1.0 EyDir=1.0 EzDir=1.0 Print=0 StatusEvery=10 SaveDipoles=1 DipolesEvery=2 SavePopulations=0 SaveFockEnergies=0 WriteDensities=0 SaveEvery=500 FourierEvery=5000 MMUT=1 LFLPPC=0""") # FIXME: make this test work on Windows using pathlib mock_open = mock.mock_open() # mock_expand = mock.MagicMock(side_effect=lambda s: s) mock_os_makedirs = mock.MagicMock(side_effect=lambda s: s) with mock.patch("builtins.open", mock_open): with mock.patch("os.makedirs", mock_os_makedirs): materia.WriteQChemTDSCF(settings=settings, work_directory="/mock/path/to/dir").run() # mock_expand.assert_called_once_with("/mock/path") mock_os_makedirs.assert_called_once_with("/mock/path/to/dir") mock_open.assert_called_once_with("/mock/path/to/dir/TDSCF.prm", "w") mock_open().write.assert_called_once_with(out_str)
def test_vasp_input(): s = mtr.Settings() s["incar", "PREC"] = "Normal" s["incar", "ENCUT"] = 550 s["incar", "IBRION"] = -1 s["incar", "NSW"] = 0 s["incar", "ISIF"] = 2 s["incar", "NELMIN"] = 2 s["incar", "EDIFF"] = 1.0e-5 s["incar", "EDIFFG"] = -0.02 s["incar", "VOSKOWN"] = 1 s["incar", "NBLOCK"] = 1 s["incar", "NWRITE"] = 1 s["incar", "NELM"] = 60 s["incar", "LUSE_VDW"] = True s["incar", "LASPH"] = True s["incar", "AGGAC"] = 0.0000 s["incar", "GGA"] = "MK" s["incar", "PARAM1"] = 0.1234 s["incar", "PARAM2"] = 1.0000 s["incar", "ALGO"] = "Normal (blocked Davidson)" s["incar", "ISPIN"] = 2 s["incar", "INIWAV"] = 1 s["incar", "ISTART"] = 0 s["incar", "ICHARG"] = 2 s["incar", "LWAVE"] = False s["incar", "LCHARG"] = False s["incar", "ADDGRID"] = False s["incar", "ISMEAR"] = 1 s["incar", "SIGMA"] = 0.2 s["incar", "LREAL"] = False s["incar", "RWIGS"] = (1.17, 0.73) s["incar", "LDAU"] = True s["incar", "LDAUTYPE"] = 2 s["incar", "LDAUL"] = (2, -1) s["incar", "LDAUU"] = (8.00, 0.00) s["incar", "LDAUJ"] = (4.00, 0.00) s["incar", "LDAUPRINT"] = 2 s["poscar", "comment"] = "(Fe2 O3)24 (P1) ~ (COD #9015065)_1_2x2x1_1 0 0 1\ surface_1 (#1)_2x2x1_1 (MD #5) (VASP)" s["poscar", "scaling"] = 1.0 s["poscar", "bravais_matrix"] = np.hstack([[10.0498, 0, 0], [0, 8.7034, 0], [0, 0, 28.7163]]) s["poscar", "Direct"] = True s["poscar", "num_atoms"] = (48, 72) s["kpoints", "comment"] = "Automatic grid" s["kpoints", "mesh_type"] = "Gamma" s["kpoints", "grid"] = (4, 4, 1) s["kpoints", "shift"] = (0.0, 0.0, 0.0) vasp_str = """PREC = Normal ENCUT = 550 IBRION = -1 NSW = 0 ISIF = 2 NELMIN = 2 EDIFF = 1e-05 EDIFFG = -0.02 VOSKOWN = 1 NBLOCK = 1 NWRITE = 1 NELM = 60 LUSE_VDW = .TRUE. LASPH = .TRUE. AGGAC = 0.0 GGA = MK PARAM1 = 0.1234 PARAM2 = 1.0 ALGO = Normal (blocked Davidson) ISPIN = 2 INIWAV = 1 ISTART = 0 ICHARG = 2 LWAVE = .FALSE. LCHARG = .FALSE. ADDGRID = .FALSE. ISMEAR = 1 SIGMA = 0.2 LREAL = .FALSE. RWIGS = 1.17 0.73 LDAU = .TRUE. LDAUTYPE = 2 LDAUL = 2 -1 LDAUU = 8.0 0.0 LDAUJ = 4.0 0.0 LDAUPRINT = 2 (Fe2 O3)24 (P1) ~ (COD #9015065)_1_2x2x1_1 0 0 1 surface_1 (#1)_2x2x1_1 (MD #5) (VASP) 1.0 10.0498 0.0 0.0 0.0 8.7034 0.0 0.0 0.0 28.7163 48 72 Automatic grid Gamma 4 4 1 0.0 0.0 0.0 """ assert str(mtr.VASPInput(s) == vasp_str)