diff --git a/.gitignore b/.gitignore index f9cca34..a987b49 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ __pycache__/ simfiles/* .vscode/* -.idea/* \ No newline at end of file +.idea/* +*.pkl diff --git a/control.example.yml b/control.example.yml index f475b7d..fddc56c 100644 --- a/control.example.yml +++ b/control.example.yml @@ -1,16 +1,16 @@ diceplayer: opt: no mem: 24 - maxcyc: 10 + maxcyc: 5 ncores: 5 nprocs: 4 qmprog: 'g16' lps: no ghosts: no - altsteps: 20000 + altsteps: 2000 dice: - nmol: [1, 1000] + nmol: [1, 100] dens: 1.0 nstep: [2000, 3000] isave: 1000 diff --git a/diceplayer/__main__.py b/diceplayer/__main__.py index 3bfd18d..2be65fc 100644 --- a/diceplayer/__main__.py +++ b/diceplayer/__main__.py @@ -43,23 +43,17 @@ def main(): # Open OUTFILE for writing and print keywords and initial info logger.set_logger(args.outfile, logging.INFO) - try: + if args.opt_continue: + player = Player.from_save() + else: + player = Player.from_file(args.infile) - pickle_path = Path("latest-step.pkl") - if args.opt_continue and pickle_path.exists(): - with open(pickle_path) as pickle_file: - save = pickle.load(pickle_file) + player.read_potentials() - except Exception as err: - sys.exit(err) - - player = Player(args.infile) + player.create_simulation_dir() player.print_keywords() - player.create_simulation_dir() - - player.read_potentials() player.print_potentials() player.prepare_system() diff --git a/diceplayer/player.py b/diceplayer/player.py index 7300bd3..11814d5 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,3 +1,5 @@ +import pickle + from diceplayer.shared.interface.gaussian_interface import GaussianInterface from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.utils.dataclass_protocol import Dataclass @@ -11,38 +13,54 @@ from diceplayer.shared.environment.atom import Atom from diceplayer import logger from dataclasses import fields +from typing import Type, Tuple from pathlib import Path -from typing import Type, List -import logging import yaml import sys import os - ENV = ["OMP_STACKSIZE"] class Player: - def __init__(self, infile: str): - config_data = self.read_keywords(infile) + def __init__(self, infile: str = None, optimization: bool = False): + if infile is None and optimization is False: + raise ValueError("Must specify either infile or optimization") - self.system = System() + elif infile is not None: + config_data = self.read_keywords(infile) - self.config = self.set_config( - config_data.get("diceplayer") - ) + self.config = self.set_config( + config_data.get("diceplayer") + ) + + self.system = System() + + self.initial_cycle = 1 + + elif optimization is True: + save = self.load_run_from_pickle() + + self.config = save[0] + + self.system = save[1] + + self.initial_cycle = save[2] + + else: + raise ValueError("Must specify either infile or config") self.dice_interface = DiceInterface() self.gaussian_interface = GaussianInterface() - def start(self, initial_cycle: int = 1): + def start(self): logger.info( "==========================================================================================\n" "Starting the iterative process.\n" "==========================================================================================\n" ) - for cycle in range(initial_cycle, self.config.maxcyc + 1): + for cycle in range(self.initial_cycle, self.config.maxcyc + 1): logger.info( f"------------------------------------------------------------------------------------------\n" @@ -54,9 +72,12 @@ class Player: try: self.gaussian_start(cycle) + pass except StopIteration as e: break + self.save_run_in_pickle(cycle) + def prepare_system(self): for i, mol in enumerate(self.system.molecule): logger.info( @@ -75,7 +96,6 @@ class Player: logger.info("\n") - def create_simulation_dir(self): simulation_dir_path = Path(self.config.simulation_dir) if simulation_dir_path.exists(): @@ -169,12 +189,12 @@ class Player: nsites, molname = ljc_data.pop(0).split()[:2] except ValueError: raise ValueError( - f"Error: expected nsites and molname for the molecule type {i+1}" + f"Error: expected nsites and molname for the molecule type {i + 1}" ) if not nsites.isdigit(): raise ValueError( - f"Error: expected nsites to be an integer for molecule type {i+1}" + f"Error: expected nsites to be an integer for molecule type {i + 1}" ) nsites = int(nsites) @@ -271,7 +291,7 @@ class Player: 'Charges optimization failed. No charges found in result.' ) - diff = self.system.molecule[0]\ + diff = self.system.molecule[0] \ .update_charges(result['charges']) self.system.print_charges_and_dipole(cycle) @@ -390,6 +410,31 @@ class Player: logger.info("\n") + def save_run_in_pickle(self, cycle): + try: + with open('latest-step.pkl', 'wb') as pickle_file: + pickle.dump( + (self.config, self.system, cycle), + pickle_file + ) + except Exception: + raise RuntimeError( + f'Could not save pickle file latest-step.pkl.' + ) + + @staticmethod + def load_run_from_pickle() -> Tuple[PlayerConfig, System, int]: + pickle_path = Path("latest-step.pkl") + try: + with open(pickle_path, 'rb') as pickle_file: + save = pickle.load(pickle_file) + return save[0], save[1], save[2] + 1 + + except Exception: + raise RuntimeError( + f'Could not load pickle file {pickle_path}.' + ) + @staticmethod def set_config(data: dict) -> PlayerConfig: return PlayerConfig.from_dict(data) @@ -398,3 +443,11 @@ class Player: def read_keywords(infile) -> dict: with open(infile, 'r') as yml_file: return yaml.load(yml_file, Loader=yaml.SafeLoader) + + @classmethod + def from_file(cls, infile: str) -> 'Player': + return cls(infile=infile) + + @classmethod + def from_save(cls): + return cls(optimization=True) diff --git a/tests/mocks/mock_inputs.py b/tests/mocks/mock_inputs.py index 406a35a..eadf05b 100644 --- a/tests/mocks/mock_inputs.py +++ b/tests/mocks/mock_inputs.py @@ -107,5 +107,7 @@ def mock_open(file, *args, **kwargs): "phb.error.nsites.ljc": get_potentials_error_nsites(), "phb.error.molname.ljc": get_potentials_error_molname(), } - mock_file = mock.mock_open(read_data=values[file]) - return mock_file() \ No newline at end of file + if file in values: + return mock.mock_open(read_data=values[file])() + + return mock.mock_open(read_data="")() diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 4a0ec90..0c5b931 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -417,7 +417,7 @@ class TestDiceInterface(unittest.TestCase): dice = DiceInterface() dice.configure(self.config, System()) - dice._make_nvt_eq('test') + dice._make_nvt_eq(1, 'test') mock_handler = mock_open() calls = mock_handler.write.call_args_list diff --git a/tests/test_player.py b/tests/test_player.py index 65e45d5..d1b50e9 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -27,7 +27,7 @@ class TestPlayer(unittest.TestCase): player.gaussian_start = mock.MagicMock() player.dice_start = mock.MagicMock() - player.start(1) + player.start() self.assertEqual(player.dice_start.call_count, 3) self.assertEqual(player.gaussian_start.call_count, 3) @@ -66,21 +66,30 @@ class TestPlayer(unittest.TestCase): player.print_keywords() expected_output = [ - 'INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n\n', - 'INFO:diceplayer:Your python version is TEST\n', 'INFO:diceplayer:\n', - 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', 'INFO:diceplayer:\n', - 'INFO:diceplayer:Environment variables:\n', 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', - 'INFO:diceplayer:\n==========================================================================================\n CONTROL variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:\n', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:dens = 0.75', 'INFO:diceplayer:isave = 1000', 'INFO:diceplayer:ljname = phb.ljc', - 'INFO:diceplayer:nmol = [ 1 50 ]', 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', - 'INFO:diceplayer:outname = phb', 'INFO:diceplayer:press = 1.0', - 'INFO:diceplayer:progname = ~/.local/bin/dice', 'INFO:diceplayer:randominit = first', - 'INFO:diceplayer:temp = 300.0', 'INFO:diceplayer:\n', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n\n', - 'INFO:diceplayer:keywords = freq', 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', - 'INFO:diceplayer:pop = chelpg', 'INFO:diceplayer:qmprog = g16', 'INFO:diceplayer:\n'] + 'INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version 1.0 #############\n##########################################################################################\n', + 'INFO:diceplayer:Your python version is TEST\n', + 'INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n', + 'INFO:diceplayer:Environment variables:', + 'INFO:diceplayer:OMP_STACKSIZE = Not set\n', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:dens = 0.75', + 'INFO:diceplayer:isave = 1000', + 'INFO:diceplayer:ljname = phb.ljc', + 'INFO:diceplayer:nmol = [ 1 50 ]', + 'INFO:diceplayer:nstep = [ 2000 3000 4000 ]', + 'INFO:diceplayer:outname = phb', + 'INFO:diceplayer:press = 1.0', + 'INFO:diceplayer:progname = ~/.local/bin/dice', + 'INFO:diceplayer:randominit = first', + 'INFO:diceplayer:temp = 300.0', + 'INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:chg_tol = 0.01', + 'INFO:diceplayer:keywords = freq', + 'INFO:diceplayer:level = MP2/aug-cc-pVDZ', + 'INFO:diceplayer:pop = chelpg', + 'INFO:diceplayer:qmprog = g16', + 'INFO:diceplayer:\n' + ] self.assertEqual(cm.output, expected_output) @@ -294,22 +303,22 @@ class TestPlayer(unittest.TestCase): player.print_potentials() expected_output = [ - 'INFO:diceplayer:==========================================================================================\n', - 'INFO:diceplayer: Potential parameters from file phb.ljc:', - 'INFO:diceplayer:------------------------------------------------------------------------------------------\n', - 'INFO:diceplayer:Combination rule: *', 'INFO:diceplayer:Types of molecules: 2\n', + 'INFO:diceplayer:==========================================================================================\n Potential parameters from file phb.ljc:\n------------------------------------------------------------------------------------------\n', + 'INFO:diceplayer:Combination rule: *', + 'INFO:diceplayer:Types of molecules: 2\n', 'INFO:diceplayer:1 atoms in molecule type 1:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', - 'INFO:diceplayer:\n', 'INFO:diceplayer:1 atoms in molecule type 2:', + 'INFO:diceplayer:\n', + 'INFO:diceplayer:1 atoms in molecule type 2:', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass', 'INFO:diceplayer:---------------------------------------------------------------------------------', 'INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079', - 'INFO:diceplayer:\n', - 'INFO:diceplayer:=========================================================================================='] + 'INFO:diceplayer:\n' + ] self.assertEqual( context.output,