From 0f7484756b160d28e9122e66c9cdf8dbecc52215 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Fri, 10 Feb 2023 09:07:50 -0300 Subject: [PATCH] Fixes Tests Implementations --- .gitignore | 2 ++ config.example.yml | 4 +-- crystal.example.gjf | 4 +-- crystalpol/gaussian.py | 55 ++++++++++++++++++++++++----------- tests/shared/test_gaussian.py | 36 ++++++++++++++--------- tests/test_polarization.py | 8 +++-- 6 files changed, 72 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 058eef3..437962b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.pyc .idea/ + +simfiles \ No newline at end of file diff --git a/config.example.yml b/config.example.yml index 3e57fcd..37a8f6a 100644 --- a/config.example.yml +++ b/config.example.yml @@ -1,8 +1,8 @@ crystal_pol: - mem: 42 + mem: 28 n_procs: 20 level: "b3lyp/aug-cc-pVDZ" pop: "chelpg" mult: [0, 1] n_atoms: 18 - comment: "DC-MBI UAEnvolvida" \ No newline at end of file + comment: "Crystal" \ No newline at end of file diff --git a/crystal.example.gjf b/crystal.example.gjf index 53fb5e9..84334ec 100644 --- a/crystal.example.gjf +++ b/crystal.example.gjf @@ -1,5 +1,5 @@ -%mem=42GB -%Nprocs=20 +%mem=30GB +%Nprocs=24 #p ${LEVEL} POP=${POP} density=current NoSymm (CHARGE - A partir do segundo) ${COMMENTARY} passo 1 diff --git a/crystalpol/gaussian.py b/crystalpol/gaussian.py index 2380627..9cb10a2 100644 --- a/crystalpol/gaussian.py +++ b/crystalpol/gaussian.py @@ -3,7 +3,7 @@ from crystalpol.shared.system.crystal import Crystal from crystalpol.shared.config import Config from pathlib import Path, PosixPath -from typing import TextIO +from typing import TextIO, Union import subprocess import textwrap import shutil @@ -25,8 +25,14 @@ class Gaussian: def run(self, cycle: int, crystal: Crystal) -> None: - file = Path("simfiles", f"crystal-{str(cycle).zfill(2)}.gjf") + self.create_simulation_dir() + file = Path( + "simfiles", + f"crystal-{str(cycle).zfill(2)}", + f"crystal-{str(cycle).zfill(2)}.gjf" + ) + self.create_step_dir(cycle) self.make_gaussian_input(cycle, file, crystal) if shutil.which("bash") is not None: @@ -35,7 +41,7 @@ class Gaussian: "bash", "-c", "exec -a {}-step{} {} {}".format( - self.qmprog, cycle, self.qmprog, file.name + self.qmprog, cycle, self.qmprog, str(file) ), ] ) @@ -47,6 +53,19 @@ class Gaussian: return self.read_charges_from_gaussian_output() + def create_step_dir(self, cycle): + step_dir = Path( + "simfiles", + f"crystal-{str(cycle).zfill(2)}" + ) + if not os.path.exists(step_dir): + os.makedirs(step_dir) + else: + raise RuntimeError( + f"Step directory '{str(step_dir)}' already exists. " + f"Please remove it before proceeding." + ) + def create_simulation_dir(self): if not os.path.exists(self.config.simulation_dir): os.makedirs(self.config.simulation_dir) @@ -56,17 +75,17 @@ class Gaussian: f"Please remove it before proceeding." ) - def make_gaussian_input(self, cycle: int, file: PosixPath, crystal: Crystal) -> str: + def make_gaussian_input(self, cycle: int, file: Union[PosixPath, Path], crystal: Crystal) -> str: with open(file, 'w+') as fh: - fh.write(f"%Mem={self.config.mem}MB\n") + fh.write(f"%Mem={self.config.mem}Gb\n") fh.write(f"%Nprocs={self.config.n_procs}\n") kwords_line = f"#P {self.config.level} " \ - f"Pop = {self.config.pop} " \ - f"Density = Current " \ + f"Pop={self.config.pop} " \ + f"Density=Current " \ f"NoSymm " if cycle > 1: @@ -77,17 +96,19 @@ class Gaussian: fh.write(f"\n{self.config.comment} - Cycle number {cycle}\n") fh.write("\n") - fh.write(f"{self.config.mult[0]}, {self.config.mult[1]}\n") + fh.write(f"{self.config.mult[0]} {self.config.mult[1]}\n") for atom in crystal[0][0]: symbol = atom_symbol[atom.na] fh.write( f"{symbol:<2s} " - f"{atom.rx:>10.5f} " - f"{atom.ry:>10.5f} " - f"{atom.rz:>10.5f}\n" + f"{float(atom.rx):>10.5f} " + f"{float(atom.ry):>10.5f} " + f"{float(atom.rz):>10.5f}\n" ) + fh.write("\n") + if cycle > 1: self.make_gaussian_charges(fh, crystal) @@ -96,8 +117,6 @@ class Gaussian: def make_gaussian_charges(self, fh: TextIO, crystal: Crystal) -> None: - fh.write("\n") - for index_cell, cell in enumerate(crystal): for index_mol, molecule in enumerate(cell): if (index_cell == 0 and index_mol != 0) or (index_cell != 0): @@ -105,10 +124,12 @@ class Gaussian: symbol = atom_symbol[atom.na] fh.write( f"{symbol:<2s} " - f"{atom.rx:>10.5f} " - f"{atom.ry:>10.5f} " - f"{atom.rz:>10.5f}\n" + f"{float(atom.rx):>10.5f} " + f"{float(atom.ry):>10.5f} " + f"{float(atom.rz):>10.5f}\n" ) + fh.write("\n") + def read_charges_from_gaussian_output(self) -> None: - pass \ No newline at end of file + pass diff --git a/tests/shared/test_gaussian.py b/tests/shared/test_gaussian.py index c18fd07..2ecb588 100644 --- a/tests/shared/test_gaussian.py +++ b/tests/shared/test_gaussian.py @@ -4,6 +4,7 @@ from crystalpol.shared.system.atom import Atom from crystalpol.shared.config import Config from crystalpol.gaussian import Gaussian +from pathlib import Path from io import StringIO from unittest import mock, TestCase @@ -38,6 +39,7 @@ class TestGaussian(TestCase): @mock.patch('crystalpol.gaussian.os') def test_create_simulation_dir(self, os_mock): os_mock.path.exists.return_value = False + os_mock.makedirs = mock.MagicMock() gaussian = Gaussian( Config( @@ -53,6 +55,7 @@ class TestGaussian(TestCase): @mock.patch('crystalpol.gaussian.os') def test_create_simulation_dir_raises_exception(self, os_mock): os_mock.path.exists.return_value = True + os_mock.makedirs = mock.MagicMock() gaussian = Gaussian( Config( mem=1, @@ -64,6 +67,7 @@ class TestGaussian(TestCase): with self.assertRaises(RuntimeError): gaussian.create_simulation_dir() + # @mock.patch('crystalpol.gaussian.os') @mock.patch('crystalpol.gaussian.open') def test_make_gaussian_input_cycle_1(self, open_mock): @@ -78,16 +82,17 @@ class TestGaussian(TestCase): n_atoms=10 ) ) - gaussian_input = gaussian.make_gaussian_input(1, crystal) + gaussian_input = gaussian.make_gaussian_input(1, Path(), crystal) expected_output = """\ -%Mem=1MB +%Mem=1Gb %Nprocs=1 -#P b3lyp/aug-cc-pVDZ Pop = chelpg Density = Current NoSymm +#P b3lyp/aug-cc-pVDZ Pop=chelpg Density=Current NoSymm crystalpol - Cycle number 1 -0, 1 -H 0.00000 0.00000 0.00000 +0 1 +H 0.00000 0.00000 0.00000 + """ self.assertEqual(gaussian_input, expected_output) @@ -107,16 +112,17 @@ H 0.00000 0.00000 0.00000 ) gaussian_input = gaussian.make_gaussian_input(2, "test", crystal) expected_output = """\ -%Mem=1MB +%Mem=1Gb %Nprocs=1 -#P b3lyp/aug-cc-pVDZ Pop = chelpg Density = Current NoSymm charge +#P b3lyp/aug-cc-pVDZ Pop=chelpg Density=Current NoSymm charge crystalpol - Cycle number 2 -0, 1 -H 0.00000 0.00000 0.00000 +0 1 +H 0.00000 0.00000 0.00000 + +H 0.00000 0.00000 0.00000 -H 0.00000 0.00000 0.00000 """ self.assertEqual(gaussian_input, expected_output) @@ -136,13 +142,15 @@ H 0.00000 0.00000 0.00000 file.seek(0) charges_string = file.read() - expected_charges = '\nH 0.00000 0.00000 0.00000\n' + expected_charges = 'H 0.00000 0.00000 0.00000\n\n' self.assertEqual(charges_string, expected_charges) + @mock.patch('crystalpol.gaussian.os') @mock.patch('crystalpol.gaussian.subprocess.call', autospec=True, return_value=0) @mock.patch('crystalpol.gaussian.Gaussian.make_gaussian_input') - def test_run(self, subprocess_call_mock, make_gaussian_input_mock): + def test_run(self, make_gaussian_input_mock, subprocess_call_mock, os_mock): + os_mock.path.exists.return_value = False gaussian = Gaussian( Config( @@ -155,9 +163,11 @@ H 0.00000 0.00000 0.00000 self.assertTrue(subprocess_call_mock.called) + @mock.patch('crystalpol.gaussian.os') @mock.patch('crystalpol.gaussian.subprocess.call', autospec=True, return_value=1) @mock.patch('crystalpol.gaussian.Gaussian.make_gaussian_input') - def test_run_raises_exception(self, subprocess_call_mock, make_gaussian_input_mock): + def test_run_raises_exception(self, subprocess_call_mock, make_gaussian_input_mock, os_mock): + os_mock.path.exists.return_value = False gaussian = Gaussian( Config( diff --git a/tests/test_polarization.py b/tests/test_polarization.py index f67476f..e8d598e 100644 --- a/tests/test_polarization.py +++ b/tests/test_polarization.py @@ -6,7 +6,6 @@ from crystalpol.shared.system.molecule import Molecule from unittest import TestCase, mock import unittest - GEOM_DATA = """\ Cl 0.529511 -1.626652 1.247344 N 3.703161 2.470259 1.679277 @@ -85,9 +84,12 @@ class TestPolarization(TestCase): self.assertEqual(len(pol.crystal), 2) self.assertEqual(len(pol.crystal[0]), 1) - @mock.patch('builtins.open', mock.mock_open(read_data=GEOM_DATA)) - def test_run(self): + @mock.patch('crystalpol.gaussian.subprocess.call', autospec=True, return_value=0) + @mock.patch('crystalpol.gaussian.os') + def test_run(self, os_mock, subprocess_call_mock): + os_mock.path.exists.return_value = False + pol = Polarization("geom_file", "outfile", self.config) pol.run()