diff --git a/.gitignore b/.gitignore index 437962b..8f7378d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +*.log +*.log.backup + *.pyc .idea/ -simfiles \ No newline at end of file +simfiles + diff --git a/crystalpol/__main__.py b/crystalpol/__main__.py index 6df08a0..ee9a650 100644 --- a/crystalpol/__main__.py +++ b/crystalpol/__main__.py @@ -4,10 +4,15 @@ from crystalpol.shared.config import Config from yaml.loader import SafeLoader import yaml +from pathlib import Path import setproctitle import argparse +import logging +import sys import os +from crystalpol.shared.utils import weekday_date_time +from crystalpol.shared.utils.log import Log __VERSION = "v0.0.1" os.nice(+19) @@ -47,6 +52,16 @@ def main(): ) args = parser.parse_args() + log_file = Path("run.log") + if log_file.exists(): + log_file.rename(log_file.with_suffix(".log.backup")) + + logging.basicConfig( + filename=args.outfile, + format='%(message)s', + level=logging.INFO + ) + try: with open(args.config) as file: data = yaml.load(file, Loader=SafeLoader) @@ -54,6 +69,8 @@ def main(): except IOError: raise RuntimeError('Invalid or Missing Config File.') + Log.make_header(__VERSION, data.get('crystal_pol')) + pol = Polarization(args.infile, args.outfile, config) pol.run() diff --git a/crystalpol/polarization.py b/crystalpol/polarization.py index 85ab3b2..9f3090d 100644 --- a/crystalpol/polarization.py +++ b/crystalpol/polarization.py @@ -6,10 +6,12 @@ from crystalpol.shared.system.atom import Atom from crystalpol.shared.config import Config from crystalpol.gaussian import Gaussian -from typing import List +from typing import List, Tuple import sys +from crystalpol.shared.utils.log import Log + class Polarization: __slots__ = ('geom_file', 'outfile', 'config', 'gaussian', 'crystal') @@ -30,12 +32,20 @@ class Polarization: self.read_crystal() cycle = 1 - charge_diff = sys.float_info.max - while charge_diff > self.config.charge_tolerance: + max_charge_diff = sys.float_info.max + while max_charge_diff > self.config.charge_tolerance: - charge_diff = self.update_crystal_charges( + max_charge_diff, charge_diff = self.update_crystal_charges( self.gaussian.run(cycle, self.crystal), ) + + Log.make_run( + cycle, + max_charge_diff, + charge_diff, + self.crystal + ) + cycle += 1 def read_crystal(self) -> None: @@ -49,7 +59,7 @@ class Polarization: for molecule in molecules: self.crystal.add_cell([molecule]) - def update_crystal_charges(self, charges: List[float]) -> float: + def update_crystal_charges(self, charges: List[float]) -> Tuple[float, list]: charge_diff = [] @@ -60,7 +70,9 @@ class Polarization: charge_diff.append(abs(atom.chg - charges[index])) atom.chg = charges[index] - return abs(max(charge_diff, key=abs)) if charge_diff else sys.float_info.max + max_charge_diff = abs(max(charge_diff, key=abs)) if charge_diff else sys.float_info.max + + return max_charge_diff, charge_diff def _get_molecules_from_lines(self, lines: List[str]) -> List[Molecule]: if (len(lines) % self.config.n_atoms) == 0: diff --git a/crystalpol/shared/utils/__init__.py b/crystalpol/shared/utils/__init__.py index e69de29..1d99555 100644 --- a/crystalpol/shared/utils/__init__.py +++ b/crystalpol/shared/utils/__init__.py @@ -0,0 +1,5 @@ +import time + + +def weekday_date_time(): + return time.strftime("%A, %d %b %Y at %H:%M:%S") \ No newline at end of file diff --git a/crystalpol/shared/utils/log.py b/crystalpol/shared/utils/log.py new file mode 100644 index 0000000..eb1c1ff --- /dev/null +++ b/crystalpol/shared/utils/log.py @@ -0,0 +1,45 @@ +import sys + +from crystalpol.shared.config import Config + +import logging + +from crystalpol.shared.utils import weekday_date_time + + +class Log: + @staticmethod + def make_header(version: str, config_dict: dict): + logging.info( + f"##########################################################################################\n" + f"############## Welcome to CRYSTALPOL version {version} ##############\n" + f"##########################################################################################\n" + ) + logging.info(f"Your python version is {sys.version}\n") + logging.info(f"Program started on {weekday_date_time()}\n") + + logging.info("------------------------------------------------------------------------------------------") + logging.info(" CRYSTALPOL variables being used in this run: ") + logging.info("------------------------------------------------------------------------------------------\n") + for key, value in config_dict.items(): + logging.info(f"\t{key} = {(key if key else 'Not set')}") + + logging.info("------------------------------------------------------------------------------------------") + logging.info(f" RUN Results: ") + logging.info("------------------------------------------------------------------------------------------\n") + + @staticmethod + def make_run(cycle, max_charge_diff, charge_diff, crystal): + logging.info(f"cycle: {cycle}") + logging.info(f"\nMax charge diff: {max_charge_diff}") + logging.info(f"Charge Diff: {charge_diff}\n") + + logging.info("------------------------------------------------------------------------------------------") + logging.info(f" S rx ry rz chg ") + logging.info("------------------------------------------------------------------------------------------") + for atom in crystal[0][0]: + logging.info(f" {atom.symbol} {atom.rx} {atom.ry} {atom.rz} {atom.chg} ") + + logging.info("\n------------------------------------------------------------------------------------------\n") + +