Implements Refactoring in Player Class and Initial Working Version

This commit is contained in:
2023-06-02 20:20:38 -03:00
parent b440a0f05d
commit 33612f2d7b
21 changed files with 1193 additions and 983 deletions

View File

@@ -1,24 +1,24 @@
diceplayer: diceplayer:
maxcyc: 3
opt: no opt: no
ncores: 4 mem: 24
maxcyc: 10
ncores: 5
nprocs: 4 nprocs: 4
qmprog: 'g16' qmprog: 'g16'
lps: no lps: no
ghosts: no ghosts: no
altsteps: 20000 altsteps: 20000
dice: dice:
nmol: [1, 50] nmol: [1, 1000]
dens: 0.75 dens: 1.0
nstep: [2000, 3000, 4000] nstep: [2000, 3000]
isave: 1000 isave: 1000
outname: 'phb' outname: 'phb'
progname: '~/.local/bin/dice' progname: '~/.local/bin/dice'
ljname: 'phb.ljc' ljname: 'phb.ljc'
randominit: 'first' randominit: 'first'
gaussian: gaussian:
qmprog: 'g16' qmprog: 'g16'
level: 'MP2/aug-cc-pVDZ' level: 'MP2/aug-cc-pVDZ'
keywords: 'freq'

View File

@@ -55,8 +55,25 @@ def main():
player = Player(args.infile) player = Player(args.infile)
player.print_keywords()
player.create_simulation_dir()
player.read_potentials()
player.print_potentials()
player.prepare_system()
player.start() player.start()
logger.info("\n+" + 88 * "-" + "+\n")
player.print_results()
logger.info("\n+" + 88 * "-" + "+\n")
logger.info("Diceplayer finished successfully \n")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -1,19 +1,18 @@
from diceplayer.shared.interface.gaussian_interface import GaussianInterface from diceplayer.shared.interface.gaussian_interface import GaussianInterface
from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.interface.dice_interface import DiceInterface
from diceplayer.shared.utils.dataclass_protocol import Dataclass from diceplayer.shared.utils.dataclass_protocol import Dataclass
from diceplayer.shared.config.gaussian_dto import GaussianDTO from diceplayer.shared.config.gaussian_config import GaussianDTO
from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.config.dice_config import DiceConfig
from diceplayer.shared.utils.misc import weekday_date_time from diceplayer.shared.utils.misc import weekday_date_time
from diceplayer.shared.config.player_dto import PlayerDTO from diceplayer.shared.environment.molecule import Molecule
from diceplayer.shared.environment.system import System from diceplayer.shared.environment.system import System
from diceplayer.shared.config.step_dto import StepDTO
from diceplayer.shared.config.dice_dto import DiceDTO
from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.atom import Atom
from diceplayer import logger from diceplayer import logger
from dataclasses import fields from dataclasses import fields
from pathlib import Path from pathlib import Path
from typing import Type from typing import Type, List
import logging import logging
import yaml import yaml
import sys import sys
@@ -33,20 +32,50 @@ class Player:
config_data.get("diceplayer") config_data.get("diceplayer")
) )
self.gaussian = GaussianInterface(config_data.get("gaussian")) self.dice_interface = DiceInterface()
self.dice = DiceInterface(config_data.get("dice")) self.gaussian_interface = GaussianInterface()
def start(self, initial_cycle: int = 1): def start(self, initial_cycle: int = 1):
self.print_keywords() logger.info(
"==========================================================================================\n"
self.create_simulation_dir() "Starting the iterative process.\n"
"==========================================================================================\n"
self.read_potentials() )
self.print_potentials()
for cycle in range(initial_cycle, self.config.maxcyc + 1): for cycle in range(initial_cycle, self.config.maxcyc + 1):
logger.info(
f"------------------------------------------------------------------------------------------\n"
f" Step # {cycle}\n"
f"------------------------------------------------------------------------------------------\n"
)
self.dice_start(cycle) self.dice_start(cycle)
try:
self.gaussian_start(cycle)
except StopIteration as e:
break
def prepare_system(self):
for i, mol in enumerate(self.system.molecule):
logger.info(
f"Molecule {i + 1} - {mol.molname}"
)
mol.print_mol_info()
logger.info(
"\n Translating and rotating molecule to standard orientation..."
)
mol.standard_orientation()
logger.info("\n Done")
logger.info("\nNew values:\n")
mol.print_mol_info()
logger.info("\n")
def create_simulation_dir(self): def create_simulation_dir(self):
simulation_dir_path = Path(self.config.simulation_dir) simulation_dir_path = Path(self.config.simulation_dir)
if simulation_dir_path.exists(): if simulation_dir_path.exists():
@@ -71,13 +100,10 @@ class Player:
"##########################################################################################\n" "##########################################################################################\n"
"############# Welcome to DICEPLAYER version 1.0 #############\n" "############# Welcome to DICEPLAYER version 1.0 #############\n"
"##########################################################################################\n" "##########################################################################################\n"
"\n"
) )
logger.info("Your python version is {}\n".format(sys.version)) logger.info("Your python version is {}\n".format(sys.version))
logger.info("\n")
logger.info("Program started on {}\n".format(weekday_date_time())) logger.info("Program started on {}\n".format(weekday_date_time()))
logger.info("\n") logger.info("Environment variables:")
logger.info("Environment variables:\n")
for var in ENV: for var in ENV:
logger.info( logger.info(
"{} = {}\n".format( "{} = {}\n".format(
@@ -85,68 +111,55 @@ class Player:
) )
) )
logger.info(
"\n==========================================================================================\n"
" CONTROL variables being used in this run:\n"
"------------------------------------------------------------------------------------------\n"
"\n"
)
logger.info("\n")
logger.info( logger.info(
"------------------------------------------------------------------------------------------\n" "------------------------------------------------------------------------------------------\n"
" DICE variables being used in this run:\n" " DICE variables being used in this run:\n"
"------------------------------------------------------------------------------------------\n" "------------------------------------------------------------------------------------------\n"
"\n"
) )
log_keywords(self.dice.config, DiceDTO) log_keywords(self.config.dice, DiceConfig)
logger.info("\n")
logger.info( logger.info(
"------------------------------------------------------------------------------------------\n" "------------------------------------------------------------------------------------------\n"
" GAUSSIAN variables being used in this run:\n" " GAUSSIAN variables being used in this run:\n"
"------------------------------------------------------------------------------------------\n" "------------------------------------------------------------------------------------------\n"
"\n"
) )
log_keywords(self.gaussian.config, GaussianDTO) log_keywords(self.config.gaussian, GaussianDTO)
logger.info("\n") logger.info("\n")
def read_potentials(self): def read_potentials(self):
ljname_path = Path(self.dice.config.ljname) ljname_path = Path(self.config.dice.ljname)
if ljname_path.exists(): if ljname_path.exists():
with open(self.dice.config.ljname) as file: with open(self.config.dice.ljname) as file:
ljc_data = file.readlines() ljc_data = file.readlines()
else: else:
raise RuntimeError( raise RuntimeError(
f"Potential file {self.dice.config.ljname} not found." f"Potential file {self.config.dice.ljname} not found."
) )
combrule = ljc_data.pop(0).split()[0] combrule = ljc_data.pop(0).split()[0]
if combrule not in ("*", "+"): if combrule not in ("*", "+"):
sys.exit( sys.exit(
"Error: expected a '*' or a '+' sign in 1st line of file {}".format( "Error: expected a '*' or a '+' sign in 1st line of file {}".format(
self.dice.config.ljname self.config.dice.ljname
) )
) )
self.dice.config.combrule = combrule self.config.dice.combrule = combrule
ntypes = ljc_data.pop(0).split()[0] ntypes = ljc_data.pop(0).split()[0]
if not ntypes.isdigit(): if not ntypes.isdigit():
sys.exit( sys.exit(
"Error: expected an integer in the 2nd line of file {}".format( "Error: expected an integer in the 2nd line of file {}".format(
self.dice.config.ljname self.config.dice.ljname
) )
) )
ntypes = int(ntypes) ntypes = int(ntypes)
if ntypes != len(self.dice.config.nmol): if ntypes != len(self.config.dice.nmol):
sys.exit( sys.exit(
f"Error: number of molecule types in file {self.dice.config.ljname} " f"Error: number of molecule types in file {self.config.dice.ljname} "
f"must match that of 'nmol' keyword in config file" f"must match that of 'nmol' keyword in config file"
) )
@@ -165,7 +178,7 @@ class Player:
) )
nsites = int(nsites) nsites = int(nsites)
self.system.add_type(nsites, Molecule(molname)) self.system.add_type(Molecule(molname))
atom_fields = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig"] atom_fields = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig"]
for j in range(nsites): for j in range(nsites):
@@ -178,20 +191,15 @@ class Player:
) )
def print_potentials(self) -> None: def print_potentials(self) -> None:
formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}" formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}"
logger.info( logger.info(
"==========================================================================================\n" "==========================================================================================\n"
) f" Potential parameters from file {self.config.dice.ljname}:\n"
logger.info(
f" Potential parameters from file {self.dice.config.ljname}:"
)
logger.info(
"------------------------------------------------------------------------------------------" "------------------------------------------------------------------------------------------"
"\n" "\n"
) )
logger.info(f"Combination rule: {self.dice.config.combrule}") logger.info(f"Combination rule: {self.config.dice.combrule}")
logger.info( logger.info(
f"Types of molecules: {len(self.system.molecule)}\n" f"Types of molecules: {len(self.system.molecule)}\n"
) )
@@ -229,28 +237,50 @@ class Player:
logger.info("\n") logger.info("\n")
logger.info(
"=========================================================================================="
)
def dice_start(self, cycle: int): def dice_start(self, cycle: int):
self.dice.configure( self.dice_interface.configure(
StepDTO( self.config,
ncores=self.config.ncores, self.system,
nprocs=self.config.nprocs,
simulation_dir=self.config.simulation_dir,
altsteps=self.config.altsteps,
molecule=self.system.molecule,
nmol=self.system.nmols,
)
) )
self.dice.start(cycle) self.dice_interface.start(cycle)
self.dice.reset() self.dice_interface.reset()
def gaussian_start(self, cycle: int): def gaussian_start(self, cycle: int):
self.gaussian.start(cycle) self.gaussian_interface.configure(
self.config,
self.system,
)
result = self.gaussian_interface.start(cycle)
self.gaussian_interface.reset()
if self.config.opt:
if 'position' not in result:
raise RuntimeError(
'Optimization failed. No position found in result.'
)
self.system.update_molecule(result['position'])
else:
if 'charges' not in result:
raise RuntimeError(
'Charges optimization failed. No charges found in result.'
)
diff = self.system.molecule[0]\
.update_charges(result['charges'])
self.system.print_charges_and_dipole(cycle)
if diff < self.config.gaussian.chg_tol:
logger.info(
f'Charges converged after {cycle} cycles.'
)
raise StopIteration()
@staticmethod @staticmethod
def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict: def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict:
@@ -326,9 +356,43 @@ class Player:
return atom_dict return atom_dict
def print_results(self):
formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}"
mol = self.system.molecule[0]
logger.info(
"{} atoms in molecule type {}:".format(len(mol.atom), 1)
)
logger.info(
"---------------------------------------------------------------------------------"
)
logger.info(
"Lbl AN X Y Z Charge Epsilon Sigma Mass"
)
logger.info(
"---------------------------------------------------------------------------------"
)
for atom in mol.atom:
logger.info(
formatstr.format(
atom.lbl,
atom.na,
atom.rx,
atom.ry,
atom.rz,
atom.chg,
atom.eps,
atom.sig,
atom.mass,
)
)
logger.info("\n")
@staticmethod @staticmethod
def set_config(data: dict) -> PlayerDTO: def set_config(data: dict) -> PlayerConfig:
return PlayerDTO.from_dict(data) return PlayerConfig.from_dict(data)
@staticmethod @staticmethod
def read_keywords(infile) -> dict: def read_keywords(infile) -> dict:

View File

@@ -6,7 +6,7 @@ from typing import List
@dataclass @dataclass
class DiceDTO(Dataclass): class DiceConfig(Dataclass):
""" """
Data Transfer Object for the Dice configuration. Data Transfer Object for the Dice configuration.
""" """
@@ -53,4 +53,4 @@ class DiceDTO(Dataclass):
@classmethod @classmethod
def from_dict(cls, param: dict): def from_dict(cls, param: dict):
return from_dict(DiceDTO, param) return from_dict(DiceConfig, param)

View File

@@ -11,10 +11,11 @@ class GaussianDTO(Dataclass):
""" """
level: str level: str
qmprog: str qmprog: str
keywords: str
chgmult = [0, 1] chgmult = [0, 1]
pop: str = 'chelpg' pop: str = 'chelpg'
chg_tol: float = 0.01
keywords: str = None
def __post_init__(self): def __post_init__(self):
if self.qmprog not in ("g03", "g09", "g16"): if self.qmprog not in ("g03", "g09", "g16"):

View File

@@ -0,0 +1,47 @@
from diceplayer.shared.utils.dataclass_protocol import Dataclass
from diceplayer.shared.config.gaussian_config import GaussianDTO
from diceplayer.shared.config.dice_config import DiceConfig
from dataclasses import dataclass
from dacite import from_dict
@dataclass
class PlayerConfig(Dataclass):
"""
Data Transfer Object for the player configuration.
"""
opt: bool
maxcyc: int
nprocs: int
ncores: int
dice: DiceConfig
gaussian: GaussianDTO
mem: int = None
switchcyc: int = 3
qmprog: str = 'g16'
altsteps: int = 20000
simulation_dir = 'simfiles'
def __post_init__(self):
MIN_STEP = 20000
# altsteps value is always the nearest multiple of 1000
self.altsteps = round(max(MIN_STEP, self.altsteps) / 1000) * 1000
@classmethod
def from_dict(cls, param: dict):
if param['dice'] is None:
raise ValueError(
"Error: 'dice' keyword not specified in config file."
)
param['dice'] = DiceConfig.from_dict(param['dice'])
if param['gaussian'] is None:
raise ValueError(
"Error: 'gaussian' keyword not specified in config file."
)
param['gaussian'] = GaussianDTO.from_dict(param['gaussian'])
return from_dict(PlayerConfig, param)

View File

@@ -1,28 +0,0 @@
from diceplayer.shared.utils.dataclass_protocol import Dataclass
from dataclasses import dataclass
from dacite import from_dict
@dataclass
class PlayerDTO(Dataclass):
"""
Data Transfer Object for the player configuration.
"""
opt: bool
maxcyc: int
nprocs: int
ncores: int
qmprog: str = 'g16'
altsteps: int = 20000
simulation_dir = 'simfiles'
def __post_init__(self):
MIN_STEP = 20000
# altsteps value is always the nearest multiple of 1000
self.altsteps = round(max(MIN_STEP, self.altsteps) / 1000) * 1000
@classmethod
def from_dict(cls, param: dict):
return from_dict(PlayerDTO, param)

View File

@@ -1,22 +0,0 @@
from diceplayer.shared.environment.molecule import Molecule
from diceplayer.shared.config.player_dto import PlayerDTO
from dataclasses import dataclass
from typing import List
@dataclass
class StepDTO:
"""
Data Transfer Object for the step configuration.
"""
ncores: int
nprocs: int
simulation_dir: str
altsteps: int
nmol: List[int] = None
molecule: List[Molecule] = None
charges: List[float] = None
position: List[float] = None

View File

@@ -1,15 +1,18 @@
import logging from __future__ import annotations
import math
from copy import deepcopy
from typing import List, Any, Tuple, Final, Union
import numpy as np
from nptyping import NDArray, Shape, Float
from numpy.linalg import linalg
from diceplayer.shared.utils.ptable import ghost_number
from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.atom import Atom
from diceplayer.shared.utils.misc import BOHR2ANG from diceplayer.shared.utils.misc import BOHR2ANG
from diceplayer.shared.utils.ptable import ghost_number from diceplayer import logger
from nptyping import NDArray, Shape, Float
from numpy.linalg import linalg
import numpy as np
from typing import List, Any, Tuple, Union
from copy import deepcopy
import logging
import math
class Molecule: class Molecule:
@@ -185,11 +188,18 @@ class Molecule:
return position return position
def update_charges(self, charges: List[float]) -> None: def update_charges(self, charges: NDArray) -> int:
"""
Updates the charges of the atoms of the molecule and
returns the max difference between the new and old charges
"""
diff = 0
for i, atom in enumerate(self.atom): for i, atom in enumerate(self.atom):
diff = max(diff, abs(atom.chg - charges[i]))
atom.chg = charges[i] atom.chg = charges[i]
return diff
# @staticmethod # @staticmethod
# def update_hessian( # def update_hessian(
# step: np.ndarray, # step: np.ndarray,
@@ -299,48 +309,48 @@ class Molecule:
Prints the Molecule information into a Output File Prints the Molecule information into a Output File
""" """
logging.info( logger.info(
" Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )\n".format( " Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )".format(
self.com[0], self.com[1], self.com[2] self.com[0], self.com[1], self.com[2]
) )
) )
inertia = self.inertia_tensor() inertia = self.inertia_tensor()
evals, evecs = self.principal_axes() evals, evecs = self.principal_axes()
logging.info( logger.info(
" Moments of inertia = {:>9E} {:>9E} {:>9E}\n".format( " Moments of inertia = {:>9E} {:>9E} {:>9E}".format(
evals[0], evals[1], evals[2] evals[0], evals[1], evals[2]
) )
) )
logging.info( logger.info(
" Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( " Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
evecs[0, 0], evecs[1, 0], evecs[2, 0] evecs[0, 0], evecs[1, 0], evecs[2, 0]
) )
) )
logging.info( logger.info(
" Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( " Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
evecs[0, 1], evecs[1, 1], evecs[2, 1] evecs[0, 1], evecs[1, 1], evecs[2, 1]
) )
) )
logging.info( logger.info(
" Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )\n".format( " Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
evecs[0, 2], evecs[1, 2], evecs[2, 2] evecs[0, 2], evecs[1, 2], evecs[2, 2]
) )
) )
sizes = self.sizes_of_molecule() sizes = self.sizes_of_molecule()
logging.info( logger.info(
" Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )\n".format( " Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )".format(
sizes[0], sizes[1], sizes[2] sizes[0], sizes[1], sizes[2]
) )
) )
logging.info(" Total mass = {:>8.2f} au\n".format(self.total_mass)) logger.info(" Total mass = {:>8.2f} au".format(self.total_mass))
chg_dip = self.charges_and_dipole() chg_dip = self.charges_and_dipole()
logging.info(" Total charge = {:>8.4f} e\n".format(chg_dip[0])) logger.info(" Total charge = {:>8.4f} e".format(chg_dip[0]))
logging.info( logger.info(
" Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye\n\n".format( " Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye".format(
chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4] chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4]
) )
) )

View File

@@ -1,6 +1,7 @@
from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.molecule import Molecule
from diceplayer.shared.utils.ptable import atomsymb from diceplayer.shared.utils.ptable import atomsymb
from diceplayer.shared.utils.misc import BOHR2ANG from diceplayer.shared.utils.misc import BOHR2ANG
from diceplayer import logger
from typing import List, Tuple, TextIO from typing import List, Tuple, TextIO
from copy import deepcopy from copy import deepcopy
@@ -20,41 +21,33 @@ class System:
def __init__(self) -> None: def __init__(self) -> None:
""" """
Initializes a empty system object that will be populated afterwards Initializes an empty system object that will be populated afterwards
""" """
self.molecule: List[Molecule] = []
self.nmols: List[int] = [] self.nmols: List[int] = []
self.molecule: List[Molecule] = []
def add_type(self, nmols: int, m: Molecule) -> None: def add_type(self, m: Molecule) -> None:
""" """
Adds a new molecule type to the system Adds a new molecule type to the system
Args: Args:
nmols (int): Number of molecules of the new type in the system
m (Molecule): The instance of the new type of molecule m (Molecule): The instance of the new type of molecule
""" """
if isinstance(m, Molecule) is False: if isinstance(m, Molecule) is False:
raise TypeError("Error: molecule is not a Molecule instance") raise TypeError("Error: molecule is not a Molecule instance")
self.molecule.append(m) self.molecule.append(m)
if isinstance(nmols, int) is False: def update_molecule(self, position: np.ndarray) -> None:
raise TypeError("Error: nmols is not an integer")
self.nmols.append(nmols)
def update_molecule(self, position: np.ndarray, fh: TextIO) -> None:
"""Updates the position of the molecule in the Output file """Updates the position of the molecule in the Output file
Args: Args:
position (np.ndarray): numpy position vector position (np.ndarray): numpy position vector
fh (TextIO): Output file
""" """
position_in_ang = (position * BOHR2ANG).tolist() position_in_ang = (position * BOHR2ANG).tolist()
self.add_type(self.nmols[0], deepcopy(self.molecule[0])) self.add_type(deepcopy(self.molecule[0]))
for atom in self.molecule[-1].atom: for atom in self.molecule[-1].atom:
atom.rx = position_in_ang.pop(0) atom.rx = position_in_ang.pop(0)
atom.ry = position_in_ang.pop(0) atom.ry = position_in_ang.pop(0)
atom.rz = position_in_ang.pop(0) atom.rz = position_in_ang.pop(0)
@@ -62,8 +55,8 @@ class System:
rmsd, self.molecule[0] = self.rmsd_fit(-1, 0) rmsd, self.molecule[0] = self.rmsd_fit(-1, 0)
self.molecule.pop(-1) self.molecule.pop(-1)
fh.write("\nProjected new conformation of reference molecule with RMSD fit\n") logger.info("Projected new conformation of reference molecule with RMSD fit")
fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd)) logger.info(f"RMSD = {rmsd:>8.5f} Angstrom")
def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]: def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]:
@@ -200,7 +193,6 @@ class System:
# #
# return min_dist, nearestmol # return min_dist, nearestmol
# def print_geom(self, cycle: int, fh: TextIO) -> None: # def print_geom(self, cycle: int, fh: TextIO) -> None:
# """ # """
# Print the geometry of the molecule in the Output file # Print the geometry of the molecule in the Output file
@@ -220,22 +212,22 @@ class System:
# ) # )
# ) # )
# #
# def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None: def print_charges_and_dipole(self, cycle: int) -> None:
# """ """
# Print the charges and dipole of the molecule in the Output file Print the charges and dipole of the molecule in the Output file
#
# Args: Args:
# cycle (int): Number of the cycle cycle (int): Number of the cycle
# fh (TextIO): Output file fh (TextIO): Output file
# """ """
#
# fh.write("Cycle # {}\n".format(cycle)) logger.info("Cycle # {}\n".format(cycle))
# fh.write("Number of site: {}\n".format(len(self.molecule[0].atom))) logger.info("Number of site: {}\n".format(len(self.molecule[0].atom)))
#
# chargesAndDipole = self.molecule[0].charges_and_dipole() chargesAndDipole = self.molecule[0].charges_and_dipole()
#
# fh.write( logger.info(
# "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format( "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
# chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4] chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4]
# ) )
# ) )

View File

@@ -1,20 +1,23 @@
from diceplayer.shared.utils.dataclass_protocol import Dataclass from __future__ import annotations
from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.environment.system import System
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
class Interface(ABC): class Interface(ABC):
__slots__ = [ __slots__ = [
'config' 'step',
'system'
] ]
@abstractmethod def __init__(self):
def __init__(self, data: dict): self.system: System | None = None
pass self.step: PlayerConfig | None = None
@staticmethod
@abstractmethod @abstractmethod
def set_config(data: dict) -> Dataclass: def configure(self, step: PlayerConfig, system: System):
pass pass
@abstractmethod @abstractmethod

View File

@@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from diceplayer.shared.config.dice_dto import DiceDTO from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.config.step_dto import StepDTO from diceplayer.shared.environment.system import System
from diceplayer.shared.interface import Interface from diceplayer.shared.interface import Interface
from diceplayer import logger from diceplayer import logger
@@ -26,23 +26,14 @@ MAX_SEED: Final[int] = 4294967295
class DiceInterface(Interface): class DiceInterface(Interface):
title = "Diceplayer run" title = "Diceplayer run"
def __init__(self, data: dict): def configure(self, step: PlayerConfig, system: System):
self.config: DiceDTO = self.set_config(data)
self.step: StepDTO | None = None
@staticmethod
def set_config(data: dict) -> DiceDTO:
return DiceDTO.from_dict(data)
def configure(self, step: any):
self.step = step self.step = step
self.system = system
def start(self, cycle: int): def start(self, cycle: int):
procs = [] procs = []
sentinels = [] sentinels = []
logger.info(f"---------------------- DICE - CYCLE {cycle} --------------------------\n")
for proc in range(1, self.step.nprocs + 1): for proc in range(1, self.step.nprocs + 1):
p = Process(target=self._simulation_process, args=(cycle, proc)) p = Process(target=self._simulation_process, args=(cycle, proc))
p.start() p.start()
@@ -66,6 +57,7 @@ class DiceInterface(Interface):
def reset(self): def reset(self):
del self.step del self.step
del self.system
def _simulation_process(self, cycle: int, proc: int): def _simulation_process(self, cycle: int, proc: int):
setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}") setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}")
@@ -102,7 +94,7 @@ class DiceInterface(Interface):
# This is logic is used to make the initial configuration file # This is logic is used to make the initial configuration file
# for the next cycle using the last.xyz file from the previous cycle. # for the next cycle using the last.xyz file from the previous cycle.
if self.config.randominit == 'first' and cycle > 1: if self.step.dice.randominit == 'first' and cycle > 1:
last_xyz = Path( last_xyz = Path(
self.step.simulation_dir, self.step.simulation_dir,
f"step{(cycle - 1):02d}", f"step{(cycle - 1):02d}",
@@ -115,15 +107,15 @@ class DiceInterface(Interface):
with open(last_xyz, 'r') as last_xyz_file: with open(last_xyz, 'r') as last_xyz_file:
self._make_init_file(proc_dir, last_xyz_file) self._make_init_file(proc_dir, last_xyz_file)
last_xyz_file.seek(0) last_xyz_file.seek(0)
self.config.dens = self._new_density(last_xyz_file) self.step.dice.dens = self._new_density(last_xyz_file)
else: else:
self._make_nvt_ter(cycle, proc_dir) self._make_nvt_ter(cycle, proc_dir)
if len(self.config.nstep) == 2: if len(self.step.dice.nstep) == 2:
self._make_nvt_eq(proc_dir) self._make_nvt_eq(cycle, proc_dir)
elif len(self.config.nstep) == 3: elif len(self.step.dice.nstep) == 3:
self._make_npt_ter(cycle, proc_dir) self._make_npt_ter(cycle, proc_dir)
self._make_npt_eq(proc_dir) self._make_npt_eq(proc_dir)
@@ -142,13 +134,13 @@ class DiceInterface(Interface):
os.chdir(proc_dir) os.chdir(proc_dir)
if not (self.config.randominit == 'first' and cycle > 1): if not (self.step.dice.randominit == 'first' and cycle > 1):
self.run_dice_file(cycle, proc, "NVT.ter") self.run_dice_file(cycle, proc, "NVT.ter")
if len(self.config.nstep) == 2: if len(self.step.dice.nstep) == 2:
self.run_dice_file(cycle, proc, "NVT.eq") self.run_dice_file(cycle, proc, "NVT.eq")
elif len(self.config.nstep) == 3: elif len(self.step.dice.nstep) == 3:
self.run_dice_file(cycle, proc, "NPT.ter") self.run_dice_file(cycle, proc, "NPT.ter")
self.run_dice_file(cycle, proc, "NPT.eq") self.run_dice_file(cycle, proc, "NPT.eq")
@@ -175,15 +167,15 @@ class DiceInterface(Interface):
xyz_lines = last_xyz_file.readlines() xyz_lines = last_xyz_file.readlines()
nsites_mm = 0 nsites_mm = 0
for i in range(1, len(self.step.nmol)): for i in range(1, len(self.step.dice.nmol)):
nsites_mm += self.step.nmol[i] * len(self.step.molecule[i].atom) nsites_mm += self.step.dice.nmol[i] * len(self.system.molecule[i].atom)
xyz_lines = xyz_lines[-nsites_mm:] xyz_lines = xyz_lines[-nsites_mm:]
input_file = Path(proc_dir, self.config.outname + ".xy") input_file = Path(proc_dir, self.step.dice.outname + ".xy")
with open(input_file, 'w') as f: with open(input_file, 'w') as f:
for atom in self.step.molecule[0].atom: for atom in self.system.molecule[0].atom:
f.write( f.write(
f"{atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n" f"{atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n"
) )
@@ -204,8 +196,8 @@ class DiceInterface(Interface):
volume = float(box[-3]) * float(box[-2]) * float(box[-1]) volume = float(box[-3]) * float(box[-2]) * float(box[-1])
total_mass = 0 total_mass = 0
for i in range(len(self.step.molecule)): for i in range(len(self.system.molecule)):
total_mass += self.step.molecule[i].total_mass * self.step.nmol[i] total_mass += self.system.molecule[i].total_mass * self.step.dice.nmol[i]
density = (total_mass / volume) * UMAANG3_TO_GCM3 density = (total_mass / volume) * UMAANG3_TO_GCM3
@@ -216,21 +208,21 @@ class DiceInterface(Interface):
with open(file, 'w') as f: with open(file, 'w') as f:
f.write(f"title = {self.title} - NVT Thermalization\n") f.write(f"title = {self.title} - NVT Thermalization\n")
f.write(f"ncores = {self.step.ncores}\n") f.write(f"ncores = {self.step.ncores}\n")
f.write(f"ljname = {self.config.ljname}\n") f.write(f"ljname = {self.step.dice.ljname}\n")
f.write(f"outname = {self.config.outname}\n") f.write(f"outname = {self.step.dice.outname}\n")
mol_string = " ".join(str(x) for x in self.config.nmol) mol_string = " ".join(str(x) for x in self.step.dice.nmol)
f.write(f"nmol = {mol_string}\n") f.write(f"nmol = {mol_string}\n")
f.write(f"dens = {self.config.dens}\n") f.write(f"dens = {self.step.dice.dens}\n")
f.write(f"temp = {self.config.temp}\n") f.write(f"temp = {self.step.dice.temp}\n")
if self.config.randominit == "first" and cycle > 1: if self.step.dice.randominit == "first" and cycle > 1:
f.write(f"init = yesreadxyz\n") f.write(f"init = yesreadxyz\n")
f.write(f"nstep = {self.step.altsteps}\n") f.write(f"nstep = {self.step.altsteps}\n")
else: else:
f.write(f"init = yes\n") f.write(f"init = yes\n")
f.write(f"nstep = {self.config.nstep[0]}\n") f.write(f"nstep = {self.step.dice.nstep[0]}\n")
f.write("vstep = 0\n") f.write("vstep = 0\n")
f.write("mstop = 1\n") f.write("mstop = 1\n")
@@ -241,30 +233,36 @@ class DiceInterface(Interface):
seed = int(1e6 * random.random()) seed = int(1e6 * random.random())
f.write(f"seed = {seed}\n") f.write(f"seed = {seed}\n")
f.write(f"upbuf = {self.config.upbuf}") f.write(f"upbuf = {self.step.dice.upbuf}")
def _make_nvt_eq(self, proc_dir): def _make_nvt_eq(self, cycle, proc_dir):
file = Path(proc_dir, "NVT.eq") file = Path(proc_dir, "NVT.eq")
with open(file, 'w') as f: with open(file, 'w') as f:
f.write(f"title = {self.title} - NVT Production\n") f.write(f"title = {self.title} - NVT Production\n")
f.write(f"ncores = {self.step.ncores}\n") f.write(f"ncores = {self.step.ncores}\n")
f.write(f"ljname = {self.config.ljname}\n") f.write(f"ljname = {self.step.dice.ljname}\n")
f.write(f"outname = {self.config.outname}\n") f.write(f"outname = {self.step.dice.outname}\n")
mol_string = " ".join(str(x) for x in self.config.nmol) mol_string = " ".join(str(x) for x in self.step.dice.nmol)
f.write(f"nmol = {mol_string}\n") f.write(f"nmol = {mol_string}\n")
f.write(f"dens = {self.config.dens}\n") f.write(f"dens = {self.step.dice.dens}\n")
f.write(f"temp = {self.config.temp}\n") f.write(f"temp = {self.step.dice.temp}\n")
if self.step.dice.randominit == "first" and cycle > 1:
f.write("init = yesreadxyz\n")
else:
f.write("init = no\n") f.write("init = no\n")
f.write(f"nstep = {self.config.nstep[1]}\n")
f.write(f"nstep = {self.step.dice.nstep[1]}\n")
f.write("vstep = 0\n") f.write("vstep = 0\n")
f.write("mstop = 1\n") f.write("mstop = 1\n")
f.write("accum = no\n") f.write("accum = no\n")
f.write("iprint = 1\n") f.write("iprint = 1\n")
f.write(f"isave = {self.config.isave}\n") f.write(f"isave = {self.step.dice.isave}\n")
f.write(f"irdf = {10 * self.step.nprocs}\n") f.write(f"irdf = {10 * self.step.nprocs}\n")
seed = int(1e6 * random.random()) seed = int(1e6 * random.random())
@@ -276,22 +274,22 @@ class DiceInterface(Interface):
with open(file, 'w') as f: with open(file, 'w') as f:
f.write(f"title = {self.title} - NPT Thermalization\n") f.write(f"title = {self.title} - NPT Thermalization\n")
f.write(f"ncores = {self.step.ncores}\n") f.write(f"ncores = {self.step.ncores}\n")
f.write(f"ljname = {self.config.ljname}\n") f.write(f"ljname = {self.step.dice.ljname}\n")
f.write(f"outname = {self.config.outname}\n") f.write(f"outname = {self.step.dice.outname}\n")
mol_string = " ".join(str(x) for x in self.config.nmol) mol_string = " ".join(str(x) for x in self.step.dice.nmol)
f.write(f"nmol = {mol_string}\n") f.write(f"nmol = {mol_string}\n")
f.write(f"press = {self.config.press}\n") f.write(f"press = {self.step.dice.press}\n")
f.write(f"temp = {self.config.temp}\n") f.write(f"temp = {self.step.dice.temp}\n")
if self.config.randominit == "first" and cycle > 1: if self.step.dice.randominit == "first" and cycle > 1:
f.write("init = yesreadxyz\n") f.write("init = yesreadxyz\n")
f.write(f"dens = {self.config.dens:<8.4f}\n") f.write(f"dens = {self.step.dice.dens:<8.4f}\n")
f.write(f"vstep = {int(self.step.altsteps / 5)}\n") f.write(f"vstep = {int(self.step.altsteps / 5)}\n")
else: else:
f.write("init = no\n") f.write("init = no\n")
f.write(f"vstep = {int(self.config.nstep[1] / 5)}\n") f.write(f"vstep = {int(self.step.dice.nstep[1] / 5)}\n")
f.write("nstep = 5\n") f.write("nstep = 5\n")
f.write("mstop = 1\n") f.write("mstop = 1\n")
@@ -308,23 +306,23 @@ class DiceInterface(Interface):
with open(file, 'w') as f: with open(file, 'w') as f:
f.write(f"title = {self.title} - NPT Production\n") f.write(f"title = {self.title} - NPT Production\n")
f.write(f"ncores = {self.step.ncores}\n") f.write(f"ncores = {self.step.ncores}\n")
f.write(f"ljname = {self.config.ljname}\n") f.write(f"ljname = {self.step.dice.ljname}\n")
f.write(f"outname = {self.config.outname}\n") f.write(f"outname = {self.step.dice.outname}\n")
mol_string = " ".join(str(x) for x in self.config.nmol) mol_string = " ".join(str(x) for x in self.step.dice.nmol)
f.write(f"nmol = {mol_string}\n") f.write(f"nmol = {mol_string}\n")
f.write(f"press = {self.config.press}\n") f.write(f"press = {self.step.dice.press}\n")
f.write(f"temp = {self.config.temp}\n") f.write(f"temp = {self.step.dice.temp}\n")
f.write(f"nstep = 5\n") f.write(f"nstep = 5\n")
f.write(f"vstep = {int(self.config.nstep[2] / 5)}\n") f.write(f"vstep = {int(self.step.dice.nstep[2] / 5)}\n")
f.write("init = no\n") f.write("init = no\n")
f.write("mstop = 1\n") f.write("mstop = 1\n")
f.write("accum = no\n") f.write("accum = no\n")
f.write("iprint = 1\n") f.write("iprint = 1\n")
f.write(f"isave = {self.config.isave}\n") f.write(f"isave = {self.step.dice.isave}\n")
f.write(f"irdf = {10 * self.step.nprocs}\n") f.write(f"irdf = {10 * self.step.nprocs}\n")
seed = int(1e6 * random.random()) seed = int(1e6 * random.random())
@@ -333,15 +331,15 @@ class DiceInterface(Interface):
def _make_potentials(self, proc_dir): def _make_potentials(self, proc_dir):
fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n" fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n"
file = Path(proc_dir, self.config.ljname) file = Path(proc_dir, self.step.dice.ljname)
with open(file, 'w') as f: with open(file, 'w') as f:
f.write(f"{self.config.combrule}\n") f.write(f"{self.step.dice.combrule}\n")
f.write(f"{len(self.step.nmol)}\n") f.write(f"{len(self.step.dice.nmol)}\n")
nsites_qm = len(self.step.molecule[0].atom) nsites_qm = len(self.system.molecule[0].atom)
f.write(f"{nsites_qm} {self.step.molecule[0].molname}\n") f.write(f"{nsites_qm} {self.system.molecule[0].molname}\n")
for atom in self.step.molecule[0].atom: for atom in self.system.molecule[0].atom:
f.write( f.write(
fstr.format( fstr.format(
atom.lbl, atom.lbl,
@@ -355,7 +353,7 @@ class DiceInterface(Interface):
) )
) )
for mol in self.step.molecule[1:]: for mol in self.system.molecule[1:]:
f.write(f"{len(mol.atom)} {mol.molname}\n") f.write(f"{len(mol.atom)} {mol.molname}\n")
for atom in mol.atom: for atom in mol.atom:
f.write( f.write(
@@ -378,12 +376,12 @@ class DiceInterface(Interface):
[ [
"bash", "bash",
"-c", "-c",
f"exec -a dice-step{cycle}-p{proc} {self.config.progname} < {infile.name} > {outfile.name}", f"exec -a dice-step{cycle}-p{proc} {self.step.dice.progname} < {infile.name} > {outfile.name}",
] ]
) )
else: else:
exit_status = subprocess.call( exit_status = subprocess.call(
self.config.progname, stdin=infile, stdout=outfile self.step.dice.progname, stdin=infile, stdout=outfile
) )
if exit_status != 0: if exit_status != 0:

View File

@@ -1,22 +1,380 @@
from diceplayer.shared.config.gaussian_dto import GaussianDTO from __future__ import annotations
from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.environment.molecule import Molecule
from diceplayer.shared.environment.system import System
from diceplayer.shared.environment.atom import Atom
from diceplayer.shared.utils.misc import date_time
from diceplayer.shared.utils.ptable import atomsymb
from diceplayer.shared.interface import Interface from diceplayer.shared.interface import Interface
from diceplayer import logger
from typing import Tuple, List, Dict, Any
from nptyping import NDArray
import numpy as np
from pathlib import Path
import subprocess
import textwrap
import shutil
import os
class GaussianInterface(Interface): class GaussianInterface(Interface):
def configure(self, step_dto: PlayerConfig, system: System):
self.system = system
self.step = step_dto
def __init__(self, data: dict): def start(self, cycle: int) -> Dict[str, NDArray]:
self.config: GaussianDTO = self.set_config(data) self._make_qm_dir(cycle)
@staticmethod if cycle > 1:
def set_config(data: dict) -> GaussianDTO: self._copy_chk_file_from_previous_step(cycle)
return GaussianDTO.from_dict(data)
def configure(self): asec_charges = self.populate_asec_vdw(cycle)
pass self._make_gaussian_input_file(
cycle,
asec_charges
)
def start(self, cycle: int): self._run_gaussian(cycle)
pass self._run_formchk(cycle)
return_value = {}
if self.step.opt:
# return_value['position'] = np.array(
# self._run_optimization(cycle)
# )
raise NotImplementedError("Optimization not implemented yet.")
else:
return_value['charges'] = np.array(
self._read_charges_from_fchk(cycle)
)
return return_value
def reset(self): def reset(self):
pass del self.step
del self.system
def _make_qm_dir(self, cycle: int):
qm_dir_path = Path(
self.step.simulation_dir,
f"step{cycle:02d}",
"qm"
)
if not qm_dir_path.exists():
qm_dir_path.mkdir()
def _copy_chk_file_from_previous_step(self, cycle: int):
current_chk_file_path = Path(
self.step.simulation_dir,
f"step{cycle:02d}",
"qm",
f"asec.chk"
)
if current_chk_file_path.exists():
raise FileExistsError(
f"File {current_chk_file_path} already exists."
)
previous_chk_file_path = Path(
self.step.simulation_dir,
f"step{(cycle - 1):02d}",
"qm",
f"asec.chk"
)
if not previous_chk_file_path.exists():
raise FileNotFoundError(
f"File {previous_chk_file_path} does not exist."
)
shutil.copy(previous_chk_file_path, current_chk_file_path)
def populate_asec_vdw(self, cycle: int) -> list[dict]:
norm_factor = self._calculate_norm_factor()
nsitesref = len(self.system.molecule[0].atom)
nsites_total = self._calculate_total_number_of_sites(nsitesref)
proc_charges = []
for proc in range(1, self.step.nprocs + 1):
proc_charges.append(self._read_charges_from_last_step(cycle, proc))
asec_charges, thickness, picked_mols = \
self._evaluate_proc_charges(nsites_total, proc_charges)
logger.info(f"In average, {(sum(picked_mols) / norm_factor):^7.2f} molecules\n"
f"were selected from each of the {len(picked_mols)} configurations\n"
f"of the production simulations to form the ASEC, comprising a shell with\n"
f"minimum thickness of {(sum(thickness) / norm_factor):>6.2f} Angstrom\n"
)
for charge in asec_charges:
charge['chg'] = charge['chg'] / norm_factor
return asec_charges
def _calculate_norm_factor(self) -> int:
if self.step.dice.nstep[-1] % self.step.dice.isave == 0:
nconfigs = round(self.step.dice.nstep[-1] / self.step.dice.isave)
else:
nconfigs = int(self.step.dice.nstep[-1] / self.step.dice.isave)
return nconfigs * self.step.nprocs
def _calculate_total_number_of_sites(self, nsitesref) -> int:
nsites_total = self.step.dice.nmol[0] * nsitesref
for i in range(1, len(self.step.dice.nmol)):
nsites_total += self.step.dice.nmol[i] * len(self.system.molecule[i].atom)
return nsites_total
def _read_charges_from_last_step(self, cycle: int, proc: int) -> list[str]:
last_xyz_file_path = Path(
self.step.simulation_dir,
f"step{cycle:02d}",
f"p{proc:02d}",
"last.xyz"
)
if not last_xyz_file_path.exists():
raise FileNotFoundError(
f"File {last_xyz_file_path} does not exist."
)
with open(last_xyz_file_path, 'r') as last_xyz_file:
lines = last_xyz_file.readlines()
return lines
def _evaluate_proc_charges(self, total_nsites: int, proc_charges: list[list[str]]) -> Tuple[
List[Dict[str, float | Any]], List[float], List[int]]:
asec_charges = []
thickness = []
picked_mols = []
for charges in proc_charges:
charges_nsites = int(charges.pop(0))
if int(charges_nsites) != total_nsites:
raise ValueError(
f"Number of sites does not match total number of sites."
)
thickness.append(
self._calculate_proc_thickness(charges)
)
nsites_ref_mol = len(self.system.molecule[0].atom)
charges = charges[nsites_ref_mol:]
mol_count = 0
for type in range(len(self.step.dice.nmol)):
if type == 0:
# Reference Molecule must be ignored from type 0
nmols = self.step.dice.nmol[type] - 1
else:
nmols = self.step.dice.nmol[type]
for mol in range(nmols):
new_molecule = Molecule("ASEC TMP MOLECULE")
for site in range(len(self.system.molecule[type].atom)):
line = charges.pop(0).split()
if line[0].title() != atomsymb[self.system.molecule[type].atom[site].na].strip():
raise SyntaxError(
f"Error: Invalid Dice Output. Atom type does not match."
)
new_molecule.add_atom(
Atom(
self.system.molecule[type].atom[site].lbl,
self.system.molecule[type].atom[site].na,
float(line[1]),
float(line[2]),
float(line[3]),
self.system.molecule[type].atom[site].chg,
self.system.molecule[type].atom[site].eps,
self.system.molecule[type].atom[site].sig,
)
)
distance = self.system.molecule[0] \
.minimum_distance(new_molecule)
if distance < thickness[-1]:
for atom in new_molecule.atom:
asec_charges.append(
{"lbl": atomsymb[atom.na], "rx": atom.rx, "ry": atom.ry, "rz": atom.rz, "chg": atom.chg}
)
mol_count += 1
picked_mols.append(mol_count)
return asec_charges, thickness, picked_mols
def _calculate_proc_thickness(self, charges: list[str]) -> float:
box = charges.pop(0).split()[-3:]
box = [float(box[0]), float(box[1]), float(box[2])]
sizes = self.system.molecule[0].sizes_of_molecule()
return min(
[
(box[0] - sizes[0]) / 2,
(box[1] - sizes[1]) / 2,
(box[2] - sizes[2]) / 2,
]
)
def _make_gaussian_input_file(self, cycle: int, asec_charges: list[dict]) -> None:
gaussian_input_file_path = Path(
self.step.simulation_dir,
f"step{cycle:02d}",
"qm",
f"asec.gjf"
)
with open(gaussian_input_file_path, 'w') as gaussian_input_file:
gaussian_input_file.writelines(
self._generate_gaussian_input(cycle, asec_charges)
)
def _generate_gaussian_input(self, cycle: int, asec_charges: list[dict]) -> list[str]:
gaussian_input = ["%Chk=asec.chk\n"]
if self.step.mem is not None:
gaussian_input.append(f"%Mem={self.step.mem}GB\n")
gaussian_input.append(f"%Nprocs={self.step.nprocs * self.step.ncores}\n")
kwords_line = f"#P {self.step.gaussian.level}"
if self.step.gaussian.keywords:
kwords_line += " " + self.step.gaussian.keywords
if self.step.opt == "yes":
kwords_line += " Force"
kwords_line += " NoSymm"
kwords_line += f" Pop={self.step.gaussian.pop} Density=Current"
if cycle > 1:
kwords_line += " Guess=Read"
gaussian_input.append(textwrap.fill(kwords_line, 90))
gaussian_input.append("\n")
gaussian_input.append("\nForce calculation - Cycle number {}\n".format(cycle))
gaussian_input.append("\n")
gaussian_input.append(f"{self.step.gaussian.chgmult[0]},{self.step.gaussian.chgmult[1]}\n")
for atom in self.system.molecule[0].atom:
symbol = atomsymb[atom.na]
gaussian_input.append(
"{:<2s} {:>10.5f} {:>10.5f} {:>10.5f}\n".format(
symbol, atom.rx, atom.ry, atom.rz
)
)
gaussian_input.append("\n")
for charge in asec_charges:
gaussian_input.append(
"{:>10.5f} {:>10.5f} {:>10.5f} {:>11.8f}\n".format(
charge['rx'], charge['ry'], charge['rz'], charge['chg']
)
)
gaussian_input.append("\n")
return gaussian_input
def _run_gaussian(self, cycle: int) -> None:
qm_dir = Path(
self.step.simulation_dir,
f"step{(cycle):02d}",
"qm"
)
working_dir = os.getcwd()
os.chdir(qm_dir)
infile = "asec.gjf"
operation = None
if self.step.opt:
operation = "forces"
else:
operation = "charges"
logger.info(
f"Calculation of {operation} initiated with Gaussian on {date_time()}\n"
)
if shutil.which("bash") is not None:
exit_status = subprocess.call(
[
"bash",
"-c",
"exec -a {}-step{} {} {}".format(
self.step.gaussian.qmprog, cycle, self.step.gaussian.qmprog, infile
),
]
)
else:
exit_status = subprocess.call([self.step.gaussian.qmprog, infile])
if exit_status != 0:
raise SystemError("Gaussian process did not exit properly")
logger.info(f"Calculation of {operation} finished on {date_time()}")
os.chdir(working_dir)
def _run_formchk(self, cycle: int):
qm_dir = Path(
self.step.simulation_dir,
f"step{(cycle):02d}",
"qm"
)
work_dir = os.getcwd()
os.chdir(qm_dir)
logger.info("Formatting the checkpoint file... \n")
exit_status = subprocess.call(["formchk", "asec.chk"], stdout=subprocess.DEVNULL)
if exit_status != 0:
raise SystemError("Formchk process did not exit properly")
logger.info("Done\n")
os.chdir(work_dir)
def _read_charges_from_fchk(self, cycle: int):
fchk_file_path = Path(
"simfiles",
f"step{cycle:02d}",
"qm",
"asec.fchk"
)
with open(fchk_file_path) as fchk:
fchkfile = fchk.readlines()
if self.step.gaussian.pop in ["chelpg", "mk"]:
CHARGE_FLAG = "ESP Charges"
else:
CHARGE_FLAG = "ESP Charges"
start = fchkfile.pop(0).strip()
while start.find(CHARGE_FLAG) != 0: # expression in begining of line
start = fchkfile.pop(0).strip()
charges: List[float] = []
while len(charges) < len(self.system.molecule[0].atom):
charges.extend([float(x) for x in fchkfile.pop(0).split()])
return charges

111
tests/mocks/mock_inputs.py Normal file
View File

@@ -0,0 +1,111 @@
from unittest import mock
def get_config_example():
return """
diceplayer:
opt: no
mem: 12
maxcyc: 3
ncores: 4
nprocs: 4
qmprog: 'g16'
lps: no
ghosts: no
altsteps: 20000
dice:
nmol: [1, 50]
dens: 0.75
nstep: [2000, 3000, 4000]
isave: 1000
outname: 'phb'
progname: '~/.local/bin/dice'
ljname: 'phb.ljc'
randominit: 'first'
gaussian:
qmprog: 'g16'
level: 'MP2/aug-cc-pVDZ'
keywords: 'freq'
"""
def get_potentials_exemple():
return """\
*
2
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_combrule():
return """\
.
2
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_ntypes():
return """\
*
a
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_ntypes_config():
return """\
*
3
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_nsites():
return """\
*
2
. TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_molname():
return """\
*
2
1
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def mock_open(file, *args, **kwargs):
values = {
"control.test.yml": get_config_example(),
"phb.ljc": get_potentials_exemple(),
"phb.error.combrule.ljc": get_potentials_error_combrule(),
"phb.error.ntypes.ljc": get_potentials_error_ntypes(),
"phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(),
"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()

View File

@@ -1,11 +1,11 @@
from diceplayer.shared.config.dice_dto import DiceDTO from diceplayer.shared.config.dice_config import DiceConfig
import unittest import unittest
class TestDiceDto(unittest.TestCase): class TestDiceDto(unittest.TestCase):
def test_class_instantiation(self): def test_class_instantiation(self):
dice_dto = DiceDTO( dice_dto = DiceConfig(
ljname='test', ljname='test',
outname='test', outname='test',
dens=1.0, dens=1.0,
@@ -13,11 +13,11 @@ class TestDiceDto(unittest.TestCase):
nstep=[1, 1], nstep=[1, 1],
) )
self.assertIsInstance(dice_dto, DiceDTO) self.assertIsInstance(dice_dto, DiceConfig)
def test_validate_jname(self): def test_validate_jname(self):
with self.assertRaises(ValueError) as ex: with self.assertRaises(ValueError) as ex:
DiceDTO( DiceConfig(
ljname=None, ljname=None,
outname='test', outname='test',
dens=1.0, dens=1.0,
@@ -28,7 +28,7 @@ class TestDiceDto(unittest.TestCase):
def test_validate_outname(self): def test_validate_outname(self):
with self.assertRaises(ValueError) as ex: with self.assertRaises(ValueError) as ex:
DiceDTO( DiceConfig(
ljname='test', ljname='test',
outname=None, outname=None,
dens=1.0, dens=1.0,
@@ -39,7 +39,7 @@ class TestDiceDto(unittest.TestCase):
def test_validate_dens(self): def test_validate_dens(self):
with self.assertRaises(ValueError) as ex: with self.assertRaises(ValueError) as ex:
DiceDTO( DiceConfig(
ljname='test', ljname='test',
outname='test', outname='test',
dens=None, dens=None,
@@ -50,7 +50,7 @@ class TestDiceDto(unittest.TestCase):
def test_validate_nmol(self): def test_validate_nmol(self):
with self.assertRaises(ValueError) as ex: with self.assertRaises(ValueError) as ex:
DiceDTO( DiceConfig(
ljname='test', ljname='test',
outname='test', outname='test',
dens=1.0, dens=1.0,
@@ -61,7 +61,7 @@ class TestDiceDto(unittest.TestCase):
def test_validate_nstep(self): def test_validate_nstep(self):
with self.assertRaises(ValueError) as ex: with self.assertRaises(ValueError) as ex:
DiceDTO( DiceConfig(
ljname='test', ljname='test',
outname='test', outname='test',
dens=1.0, dens=1.0,
@@ -71,7 +71,7 @@ class TestDiceDto(unittest.TestCase):
self.assertEqual(ex.exception, "Error: 'nstep' keyword not defined appropriately in config file") self.assertEqual(ex.exception, "Error: 'nstep' keyword not defined appropriately in config file")
def test_from_dict(self): def test_from_dict(self):
dice_dto = DiceDTO.from_dict({ dice_dto = DiceConfig.from_dict({
'ljname': 'test', 'ljname': 'test',
'outname': 'test', 'outname': 'test',
'dens': 1.0, 'dens': 1.0,
@@ -79,4 +79,4 @@ class TestDiceDto(unittest.TestCase):
'nstep': [1, 1], 'nstep': [1, 1],
}) })
self.assertIsInstance(dice_dto, DiceDTO) self.assertIsInstance(dice_dto, DiceConfig)

View File

@@ -1,4 +1,4 @@
from diceplayer.shared.config.gaussian_dto import GaussianDTO from diceplayer.shared.config.gaussian_config import GaussianDTO
import unittest import unittest

View File

@@ -1,28 +1,84 @@
from diceplayer.shared.config.player_dto import PlayerDTO from diceplayer.shared.config.gaussian_config import GaussianDTO
from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.config.dice_config import DiceConfig
import unittest import unittest
class TestPlayerDTO(unittest.TestCase): def get_config_dict():
def test_class_instantiation(self): return {
player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4) 'opt': True,
'mem': 12,
'maxcyc': 100,
'nprocs': 4,
'ncores': 4,
'dice': {
'ljname': 'test',
'outname': 'test',
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
},
'gaussian': {
'level': 'test',
'qmprog': 'g16',
'keywords': 'test',
}
}
self.assertIsInstance(player_dto, PlayerDTO)
class TestPlayerDTO(unittest.TestCase):
def setUp(self) -> None:
self.dice_dto = DiceConfig(
ljname='test',
outname='test',
dens=1.0,
nmol=[1],
nstep=[1, 1],
)
self.gaussian_dto = GaussianDTO(
level='test',
qmprog='g16',
keywords='test',
)
def test_class_instantiation(self):
player_dto = PlayerConfig(
opt=True,
mem=12,
maxcyc=100,
nprocs=4,
ncores=4,
dice=self.dice_dto,
gaussian=self.gaussian_dto
)
self.assertIsInstance(player_dto, PlayerConfig)
self.assertIsInstance(player_dto.dice, DiceConfig)
self.assertIsInstance(player_dto.gaussian, GaussianDTO)
def test_min_altsteps(self): def test_min_altsteps(self):
player_dto = PlayerDTO(opt=True, maxcyc=100, nprocs=4, ncores=4, altsteps=100) player_dto = PlayerConfig(
opt=True,
mem=12,
maxcyc=100,
nprocs=4,
ncores=4,
altsteps=100,
dice=self.dice_dto,
gaussian=self.gaussian_dto
)
self.assertEqual(player_dto.altsteps, 20000) self.assertEqual(player_dto.altsteps, 20000)
def test_from_dict(self): def test_from_dict(self):
player_dto = PlayerDTO.from_dict({ player_dto = PlayerConfig.from_dict(
'opt': True, get_config_dict()
'maxcyc': 100, )
'nprocs': 4,
'ncores': 4,
})
self.assertIsInstance(player_dto, PlayerDTO) self.assertIsInstance(player_dto, PlayerConfig)
self.assertIsInstance(player_dto.dice, DiceConfig)
self.assertIsInstance(player_dto.gaussian, GaussianDTO)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -13,18 +13,14 @@ class TestSystem(unittest.TestCase):
def test_add_type(self): def test_add_type(self):
system = System() system = System()
system.add_type(0, Molecule('test')) system.add_type(Molecule('test'))
self.assertIsInstance(system.molecule, list) self.assertIsInstance(system.molecule, list)
self.assertIsInstance(system.nmols, list)
with self.assertRaises(TypeError) as ex: with self.assertRaises(TypeError) as ex:
system.add_type(0, 'test') system.add_type('test')
self.assertEqual(ex.exception, 'Error: molecule is not a Molecule instance') self.assertEqual(ex.exception, 'Error: molecule is not a Molecule instance')
with self.assertRaises(TypeError) as ex:
system.add_type('test', Molecule('test'))
self.assertEqual(ex.exception, 'Error: nmols is not an integer')
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -1,11 +1,14 @@
from diceplayer.shared.interface.dice_interface import DiceInterface from diceplayer.shared.interface.dice_interface import DiceInterface
from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.molecule import Molecule
from diceplayer.shared.environment.system import System
from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.atom import Atom
from diceplayer.shared.config.step_dto import StepDTO
from diceplayer import logger from diceplayer import logger
import yaml
import io import io
from tests.mocks.mock_inputs import get_config_example
from tests.mocks.mock_proc import MockConnection, MockProc from tests.mocks.mock_proc import MockConnection, MockProc
from unittest import mock from unittest import mock
@@ -16,122 +19,58 @@ class TestDiceInterface(unittest.TestCase):
def setUp(self): def setUp(self):
logger.set_logger(stream=io.StringIO()) logger.set_logger(stream=io.StringIO())
config = yaml.load(get_config_example(), Loader=yaml.Loader)
self.config = PlayerConfig.from_dict(config['diceplayer'])
def test_class_instantiation(self): def test_class_instantiation(self):
dice = DiceInterface( dice = DiceInterface()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
self.assertIsInstance(dice, DiceInterface) self.assertIsInstance(dice, DiceInterface)
def test_configure(self): def test_configure(self):
dice = DiceInterface( dice = DiceInterface()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
self.assertIsNone(dice.step) self.assertIsNone(dice.step)
self.assertIsNone(dice.system)
dice.configure('test') # Ignoring the types for testing purposes
dice.configure(self.config, System())
self.assertIsNotNone(dice.step) self.assertIsNotNone(dice.step)
self.assertIsNotNone(dice.system)
def test_reset(self): def test_reset(self):
dice = DiceInterface( dice = DiceInterface()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure('test') dice.configure(self.config, System())
self.assertTrue(hasattr(dice, 'step')) self.assertTrue(hasattr(dice, 'step'))
self.assertTrue(hasattr(dice, 'system'))
dice.reset() dice.reset()
self.assertFalse(hasattr(dice, 'step')) self.assertFalse(hasattr(dice, 'step'))
self.assertFalse(hasattr(dice, 'system'))
@mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc()) @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc())
@mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection)
def test_start(self): def test_start(self):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.start(1) dice.start(1)
@mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection) @mock.patch('diceplayer.shared.interface.dice_interface.connection', MockConnection)
@mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc(exitcode=1)) @mock.patch('diceplayer.shared.interface.dice_interface.Process', MockProc(exitcode=1))
def test_start_with_process_error(self): def test_start_with_process_error(self):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=2,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
dice.start(1) dice.start(1)
def test_simulation_process_raises_exception(self): def test_simulation_process_raises_exception(self):
dice = DiceInterface( dice = DiceInterface()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
dice._simulation_process(1, 1) dice._simulation_process(1, 1)
@@ -140,16 +79,7 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._make_dice_inputs') @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._make_dice_inputs')
@mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._run_dice') @mock.patch('diceplayer.shared.interface.dice_interface.DiceInterface._run_dice')
def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir): def test_simulation_process(self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir):
dice = DiceInterface( dice = DiceInterface()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice._simulation_process(1, 1) dice._simulation_process(1, 1)
@@ -160,26 +90,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists')
def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir): def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
mock_path_exists.return_value = False mock_path_exists.return_value = False
@@ -190,26 +102,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir') @mock.patch('diceplayer.shared.interface.dice_interface.Path.mkdir')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists') @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists')
def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir): def test_make_proc_dir_if_simdir_doesnt_exists(self, mock_path_exists, mock_path_mkdir):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
mock_path_exists.return_value = False mock_path_exists.return_value = False
@@ -218,42 +112,15 @@ class TestDiceInterface(unittest.TestCase):
self.assertEqual(mock_path_mkdir.call_count, 2) self.assertEqual(mock_path_mkdir.call_count, 2)
def test_make_dice_seed(self): def test_make_dice_seed(self):
dice = DiceInterface( seed = DiceInterface._make_dice_seed()
{
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
seed = dice._make_dice_seed()
self.assertIsInstance(seed, int) self.assertIsInstance(seed, int)
def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_one(self): def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_one(self):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test', dice.step.dice.nstep = [1, 1]
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_potentials = mock.Mock() dice._make_potentials = mock.Mock()
@@ -281,26 +148,10 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('builtins.open', new_callable=mock.mock_open, read_data='test') @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='test')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True)
def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_two(self, mock_path_exists, mock_open): def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_two(self, mock_path_exists, mock_open):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test', dice.step.dice.nstep = [1, 1]
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_potentials = mock.Mock() dice._make_potentials = mock.Mock()
@@ -327,26 +178,10 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False)
def test_make_dice_inputs_raises_exception_on_last_not_found(self, mock_path_exists): def test_make_dice_inputs_raises_exception_on_last_not_found(self, mock_path_exists):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test', dice.step.dice.nstep = [1, 1]
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_potentials = mock.Mock() dice._make_potentials = mock.Mock()
@@ -362,26 +197,8 @@ class TestDiceInterface(unittest.TestCase):
dice._make_dice_inputs(2, 1) dice._make_dice_inputs(2, 1)
def test_make_dice_inputs_nstep_len_three_with_randoninit_first_cycle_one(self): def test_make_dice_inputs_nstep_len_three_with_randoninit_first_cycle_one(self):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_potentials = mock.Mock() dice._make_potentials = mock.Mock()
@@ -410,26 +227,10 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.shutil')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True)
def test_run_dice_on_first_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): def test_run_dice_on_first_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test', dice.step.dice.nstep = [1, 1, 1]
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.run_dice_file = mock.Mock() dice.run_dice_file = mock.Mock()
@@ -441,26 +242,10 @@ class TestDiceInterface(unittest.TestCase):
self.assertEqual(dice.run_dice_file.call_count, 3) self.assertEqual(dice.run_dice_file.call_count, 3)
self.assertTrue(mock_shutils.copy.called) self.assertTrue(mock_shutils.copy.called)
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test', dice.step.dice.nstep = [1, 1]
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.run_dice_file = mock.Mock() dice.run_dice_file = mock.Mock()
@@ -476,26 +261,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.shutil')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True) @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=True)
def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.run_dice_file = mock.Mock() dice.run_dice_file = mock.Mock()
@@ -507,26 +274,8 @@ class TestDiceInterface(unittest.TestCase):
self.assertEqual(dice.run_dice_file.call_count, 2) self.assertEqual(dice.run_dice_file.call_count, 2)
self.assertTrue(mock_shutils.copy.called) self.assertTrue(mock_shutils.copy.called)
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.run_dice_file = mock.Mock() dice.run_dice_file = mock.Mock()
@@ -542,26 +291,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('diceplayer.shared.interface.dice_interface.shutil') @mock.patch('diceplayer.shared.interface.dice_interface.shutil')
@mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False) @mock.patch('diceplayer.shared.interface.dice_interface.Path.exists', return_value=False)
def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os): def test_run_dice_on_second_cycle_run_successful(self, mock_path_exists, mock_shutils, mock_os):
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice.run_dice_file = mock.Mock() dice.run_dice_file = mock.Mock()
@@ -587,32 +318,14 @@ class TestDiceInterface(unittest.TestCase):
secondary_molecule = Molecule('secondary_molecule') secondary_molecule = Molecule('secondary_molecule')
secondary_molecule.add_atom(example_atom) secondary_molecule.add_atom(example_atom)
dice = DiceInterface( system = System()
{ system.add_type(main_molecule)
'ljname': 'test', system.add_type(secondary_molecule)
'outname': 'test',
'ncores': 1, dice = DiceInterface()
'dens': 1.0, dice.configure(self.config, system)
'nmol': [1],
'nstep': [1, 1], dice.step.dice.nmol = [1, 1]
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[
main_molecule,
secondary_molecule,
],
nmol=[
len(main_molecule.atom),
len(secondary_molecule.atom),
],
)
)
last_xyz_file = io.StringIO() last_xyz_file = io.StringIO()
last_xyz_file.writelines([ last_xyz_file.writelines([
@@ -657,32 +370,12 @@ class TestDiceInterface(unittest.TestCase):
secondary_molecule = Molecule('secondary_molecule') secondary_molecule = Molecule('secondary_molecule')
secondary_molecule.add_atom(example_atom) secondary_molecule.add_atom(example_atom)
dice = DiceInterface( system = System()
{ system.add_type(main_molecule)
'ljname': 'test', system.add_type(secondary_molecule)
'outname': 'test',
'ncores': 1, dice = DiceInterface()
'dens': 1.0, dice.configure(self.config, system)
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[
main_molecule,
secondary_molecule,
],
nmol=[
len(main_molecule.atom),
len(secondary_molecule.atom),
],
)
)
last_xyz_file = io.StringIO() last_xyz_file = io.StringIO()
last_xyz_file.writelines([ last_xyz_file.writelines([
@@ -695,33 +388,15 @@ class TestDiceInterface(unittest.TestCase):
density = dice._new_density(last_xyz_file) density = dice._new_density(last_xyz_file)
self.assertEqual(density, 3.3472359000000003) self.assertEqual(density, 85.35451545000001)
@mock.patch('builtins.open', new_callable=mock.mock_open) @mock.patch('builtins.open', new_callable=mock.mock_open)
@mock.patch('diceplayer.shared.interface.dice_interface.random') @mock.patch('diceplayer.shared.interface.dice_interface.random')
def test_make_nvt_ter(self, mock_random, mock_open): def test_make_nvt_ter(self, mock_random, mock_open):
mock_random.random.return_value = 1 mock_random.random.return_value = 1
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_nvt_ter(1, 'test') dice._make_nvt_ter(1, 'test')
@@ -730,7 +405,7 @@ class TestDiceInterface(unittest.TestCase):
lines = list(map(lambda x: x[0][0], calls)) lines = list(map(lambda x: x[0][0], calls))
expected_lines = ['title = Diceplayer run - NVT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = yes\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n', 'upbuf = 360'] expected_lines = ['title = Diceplayer run - NVT Thermalization\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'dens = 0.75\n', 'temp = 300.0\n', 'init = yes\n', 'nstep = 2000\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n', 'upbuf = 360']
self.assertEqual(lines, expected_lines) self.assertEqual(lines, expected_lines)
@@ -739,26 +414,8 @@ class TestDiceInterface(unittest.TestCase):
def test_make_nvt_eq(self, mock_random, mock_open): def test_make_nvt_eq(self, mock_random, mock_open):
mock_random.random.return_value = 1 mock_random.random.return_value = 1
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_nvt_eq('test') dice._make_nvt_eq('test')
@@ -767,7 +424,7 @@ class TestDiceInterface(unittest.TestCase):
lines = list(map(lambda x: x[0][0], calls)) lines = list(map(lambda x: x[0][0], calls))
expected_lines = ['title = Diceplayer run - NVT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'dens = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'nstep = 1\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] expected_lines = ['title = Diceplayer run - NVT Production\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'dens = 0.75\n', 'temp = 300.0\n', 'init = no\n', 'nstep = 3000\n', 'vstep = 0\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 40\n', 'seed = 1000000\n']
self.assertEqual(lines, expected_lines) self.assertEqual(lines, expected_lines)
@@ -776,26 +433,8 @@ class TestDiceInterface(unittest.TestCase):
def test_make_npt_ter(self, mock_random, mock_open): def test_make_npt_ter(self, mock_random, mock_open):
mock_random.random.return_value = 1 mock_random.random.return_value = 1
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_npt_ter(1, 'test') dice._make_npt_ter(1, 'test')
@@ -804,7 +443,7 @@ class TestDiceInterface(unittest.TestCase):
lines = list(map(lambda x: x[0][0], calls)) lines = list(map(lambda x: x[0][0], calls))
expected_lines = ['title = Diceplayer run - NPT Thermalization\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'vstep = 0\n', 'nstep = 5\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n'] expected_lines = ['title = Diceplayer run - NPT Thermalization\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'press = 1.0\n', 'temp = 300.0\n', 'init = no\n', 'vstep = 600\n', 'nstep = 5\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 0\n', 'irdf = 0\n', 'seed = 1000000\n']
self.assertEqual(lines, expected_lines) self.assertEqual(lines, expected_lines)
@@ -813,26 +452,8 @@ class TestDiceInterface(unittest.TestCase):
def test_make_npt_eq(self, mock_random, mock_open): def test_make_npt_eq(self, mock_random, mock_open):
mock_random.random.return_value = 1 mock_random.random.return_value = 1
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[],
nmol=[],
)
)
dice._make_npt_eq('test') dice._make_npt_eq('test')
@@ -841,7 +462,7 @@ class TestDiceInterface(unittest.TestCase):
lines = list(map(lambda x: x[0][0], calls)) lines = list(map(lambda x: x[0][0], calls))
expected_lines = ['title = Diceplayer run - NPT Production\n', 'ncores = 1\n', 'ljname = test\n', 'outname = test\n', 'nmol = 1\n', 'press = 1.0\n', 'temp = 300.0\n', 'nstep = 5\n', 'vstep = 0\n', 'init = no\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 10\n', 'seed = 1000000\n'] expected_lines = ['title = Diceplayer run - NPT Production\n', 'ncores = 4\n', 'ljname = phb.ljc\n', 'outname = phb\n', 'nmol = 1 50\n', 'press = 1.0\n', 'temp = 300.0\n', 'nstep = 5\n', 'vstep = 800\n', 'init = no\n', 'mstop = 1\n', 'accum = no\n', 'iprint = 1\n', 'isave = 1000\n', 'irdf = 40\n', 'seed = 1000000\n']
self.assertEqual(lines, expected_lines) self.assertEqual(lines, expected_lines)
@@ -864,32 +485,12 @@ class TestDiceInterface(unittest.TestCase):
secondary_molecule = Molecule('secondary_molecule') secondary_molecule = Molecule('secondary_molecule')
secondary_molecule.add_atom(example_atom) secondary_molecule.add_atom(example_atom)
dice = DiceInterface( system = System()
{ system.add_type(main_molecule)
'ljname': 'test', system.add_type(secondary_molecule)
'outname': 'test',
'ncores': 1, dice = DiceInterface()
'dens': 1.0, dice.configure(self.config, system)
'nmol': [1],
'nstep': [1, 1],
}
)
dice.configure(
StepDTO(
ncores=1,
nprocs=1,
simulation_dir='test',
altsteps=1,
molecule=[
main_molecule,
secondary_molecule,
],
nmol=[
len(main_molecule.atom),
len(secondary_molecule.atom),
],
)
)
dice._make_potentials('test') dice._make_potentials('test')
@@ -906,16 +507,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA')
def test_run_dice_file(self, mock_open, mock_subprocess): def test_run_dice_file(self, mock_open, mock_subprocess):
mock_subprocess.call.return_value = 0 mock_subprocess.call.return_value = 0
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
dice.run_dice_file(1, 1, 'test') dice.run_dice_file(1, 1, 'test')
@@ -926,16 +519,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('builtins.open', new_callable=mock.mock_open, read_data='Error\nBLABLA') @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='Error\nBLABLA')
def test_run_dice_file_raises_runtime_error_on_dice_file(self, mock_open, mock_subprocess): def test_run_dice_file_raises_runtime_error_on_dice_file(self, mock_open, mock_subprocess):
mock_subprocess.call.return_value = 0 mock_subprocess.call.return_value = 0
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
dice.run_dice_file(1, 1, 'test') dice.run_dice_file(1, 1, 'test')
@@ -944,16 +529,8 @@ class TestDiceInterface(unittest.TestCase):
@mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA') @mock.patch('builtins.open', new_callable=mock.mock_open, read_data='End of simulation\nBLABLA')
def test_run_dice_file_raises_runtime_error_of_dice_exit_code(self, mock_open, mock_subprocess): def test_run_dice_file_raises_runtime_error_of_dice_exit_code(self, mock_open, mock_subprocess):
mock_subprocess.call.return_value = 1 mock_subprocess.call.return_value = 1
dice = DiceInterface( dice = DiceInterface()
{ dice.configure(self.config, System())
'ljname': 'test',
'outname': 'test',
'ncores': 1,
'dens': 1.0,
'nmol': [1],
'nstep': [1, 1],
}
)
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
dice.run_dice_file(1, 1, 'test') dice.run_dice_file(1, 1, 'test')

View File

@@ -0,0 +1,113 @@
from diceplayer.shared.interface.gaussian_interface import GaussianInterface
from diceplayer.shared.config.player_config import PlayerConfig
from diceplayer.shared.environment.system import System
from diceplayer import logger
from tests.mocks.mock_inputs import get_config_example
import yaml
import io
from unittest import mock
import unittest
class TestGaussianInterface(unittest.TestCase):
def setUp(self) -> None:
logger.set_logger(stream=io.StringIO())
config = yaml.load(get_config_example(), Loader=yaml.Loader)
self.config = PlayerConfig.from_dict(config['diceplayer'])
def test_class_instantiation(self):
gaussian_interface = GaussianInterface()
self.assertIsInstance(gaussian_interface, GaussianInterface)
def test_configure(self):
gaussian_interface = GaussianInterface()
self.assertIsNone(gaussian_interface.step)
self.assertIsNone(gaussian_interface.system)
gaussian_interface.configure(self.config, System())
self.assertIsNotNone(gaussian_interface.step)
self.assertIsNotNone(gaussian_interface.system)
def test_reset(self):
gaussian_interface = GaussianInterface()
gaussian_interface.configure(self.config, System())
self.assertIsNotNone(gaussian_interface.step)
self.assertIsNotNone(gaussian_interface.system)
gaussian_interface.reset()
self.assertFalse(hasattr(gaussian_interface, 'step'))
self.assertFalse(hasattr(gaussian_interface, 'system'))
@mock.patch('diceplayer.shared.interface.gaussian_interface.Path.mkdir')
@mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists')
def test_make_qm_dir(self, mock_exists, mock_mkdir):
mock_exists.return_value = False
gaussian_interface = GaussianInterface()
gaussian_interface.configure(self.config, System())
gaussian_interface._make_qm_dir(1)
mock_exists.assert_called_once()
mock_mkdir.assert_called_once()
@mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy')
@mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists')
def test_copy_chk_file_from_previous_step(self, mock_exists, mock_copy):
gaussian_interface = GaussianInterface()
gaussian_interface.configure(self.config, System())
mock_exists.side_effect = [False, True]
gaussian_interface._copy_chk_file_from_previous_step(2)
self.assertTrue(mock_exists.called)
self.assertTrue(mock_copy.called)
@mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy')
@mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists')
def test_copy_chk_file_from_previous_step_no_previous_step(self, mock_exists, mock_copy):
gaussian_interface = GaussianInterface()
gaussian_interface.configure(self.config, System())
mock_exists.side_effect = [False, False]
with self.assertRaises(FileNotFoundError):
gaussian_interface._copy_chk_file_from_previous_step(2)
@mock.patch('diceplayer.shared.interface.gaussian_interface.shutil.copy')
@mock.patch('diceplayer.shared.interface.gaussian_interface.Path.exists')
def test_copy_chk_file_from_previous_step_current_exists(self, mock_exists, mock_copy):
gaussian_interface = GaussianInterface()
gaussian_interface.configure(self.config, System())
mock_exists.side_effect = [True, True]
with self.assertRaises(FileExistsError):
gaussian_interface._copy_chk_file_from_previous_step(2)
# def test_start(self):
# gaussian_interface = GaussianInterface()
# gaussian_interface.configure(self.config, System())
#
# gaussian_interface._make_qm_dir = mock.Mock()
# gaussian_interface._copy_chk_file_from_previous_step = mock.Mock()
#
# gaussian_interface.start(2)
#
# gaussian_interface._make_qm_dir.assert_called_once_with(2)
# gaussian_interface._copy_chk_file_from_previous_step.assert_called_once_with(2)
if __name__ == '__main__':
unittest.main()

View File

@@ -3,119 +3,12 @@ from diceplayer import logger
import io import io
from tests.mocks.mock_inputs import mock_open
from unittest import mock from unittest import mock
import unittest import unittest
def get_config_example():
return """
diceplayer:
maxcyc: 3
opt: no
ncores: 4
nprocs: 4
qmprog: 'g16'
lps: no
ghosts: no
altsteps: 20000
dice:
nmol: [1, 50]
dens: 0.75
nstep: [2000, 3000, 4000]
isave: 1000
outname: 'phb'
progname: '~/.local/bin/dice'
ljname: 'phb.ljc'
randominit: 'first'
gaussian:
qmprog: 'g16'
level: 'MP2/aug-cc-pVDZ'
keywords: 'freq'
"""
def get_potentials_exemple():
return """\
*
2
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_combrule():
return """\
.
2
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_ntypes():
return """\
*
a
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_ntypes_config():
return """\
*
3
1 TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_nsites():
return """\
*
2
. TEST
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def get_potentials_error_molname():
return """\
*
2
1
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
1 PLACEHOLDER
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
"""
def mock_open(file, *args, **kwargs):
values = {
"control.test.yml": get_config_example(),
"phb.ljc": get_potentials_exemple(),
"phb.error.combrule.ljc": get_potentials_error_combrule(),
"phb.error.ntypes.ljc": get_potentials_error_ntypes(),
"phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(),
"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()
class TestPlayer(unittest.TestCase): class TestPlayer(unittest.TestCase):
def setUp(self): def setUp(self):
logger.set_logger(stream=io.StringIO()) logger.set_logger(stream=io.StringIO())
@@ -131,19 +24,13 @@ class TestPlayer(unittest.TestCase):
def test_start(self): def test_start(self):
player = Player("control.test.yml") player = Player("control.test.yml")
player.print_keywords = mock.MagicMock() player.gaussian_start = mock.MagicMock()
player.create_simulation_dir = mock.MagicMock()
player.read_potentials = mock.MagicMock()
player.print_potentials = mock.MagicMock()
player.dice_start = mock.MagicMock() player.dice_start = mock.MagicMock()
player.start(1) player.start(1)
self.assertTrue(player.print_keywords.called)
self.assertTrue(player.create_simulation_dir.called)
self.assertTrue(player.read_potentials.called)
self.assertTrue(player.print_potentials.called)
self.assertEqual(player.dice_start.call_count, 3) self.assertEqual(player.dice_start.call_count, 3)
self.assertEqual(player.gaussian_start.call_count, 3)
@mock.patch("builtins.open", mock_open) @mock.patch("builtins.open", mock_open)
@mock.patch("diceplayer.player.Path") @mock.patch("diceplayer.player.Path")
@@ -178,7 +65,22 @@ class TestPlayer(unittest.TestCase):
with self.assertLogs() as cm: with self.assertLogs() as cm:
player.print_keywords() 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'] 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']
self.assertEqual(cm.output, expected_output) self.assertEqual(cm.output, expected_output)
@@ -333,7 +235,7 @@ class TestPlayer(unittest.TestCase):
# Testing combrule error # Testing combrule error
with self.assertRaises(SystemExit) as context: with self.assertRaises(SystemExit) as context:
player.dice.config.ljname = "phb.error.combrule.ljc" player.config.dice.ljname = "phb.error.combrule.ljc"
player.read_potentials() player.read_potentials()
self.assertEqual( self.assertEqual(
@@ -343,7 +245,7 @@ class TestPlayer(unittest.TestCase):
# Testing ntypes error # Testing ntypes error
with self.assertRaises(SystemExit) as context: with self.assertRaises(SystemExit) as context:
player.dice.config.ljname = "phb.error.ntypes.ljc" player.config.dice.ljname = "phb.error.ntypes.ljc"
player.read_potentials() player.read_potentials()
self.assertEqual( self.assertEqual(
@@ -353,7 +255,7 @@ class TestPlayer(unittest.TestCase):
# Testing ntypes error on config # Testing ntypes error on config
with self.assertRaises(SystemExit) as context: with self.assertRaises(SystemExit) as context:
player.dice.config.ljname = "phb.error.ntypes.config.ljc" player.config.dice.ljname = "phb.error.ntypes.config.ljc"
player.read_potentials() player.read_potentials()
self.assertEqual( self.assertEqual(
@@ -364,7 +266,7 @@ class TestPlayer(unittest.TestCase):
# Testing nsite error # Testing nsite error
with self.assertRaises(ValueError) as context: with self.assertRaises(ValueError) as context:
player.dice.config.ljname = "phb.error.nsites.ljc" player.config.dice.ljname = "phb.error.nsites.ljc"
player.read_potentials() player.read_potentials()
self.assertEqual( self.assertEqual(
@@ -374,7 +276,7 @@ class TestPlayer(unittest.TestCase):
# Testing molname error # Testing molname error
with self.assertRaises(ValueError) as context: with self.assertRaises(ValueError) as context:
player.dice.config.ljname = "phb.error.molname.ljc" player.config.dice.ljname = "phb.error.molname.ljc"
player.read_potentials() player.read_potentials()
self.assertEqual( self.assertEqual(
@@ -391,7 +293,23 @@ class TestPlayer(unittest.TestCase):
with self.assertLogs(level='INFO') as context: with self.assertLogs(level='INFO') as context:
player.print_potentials() 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: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:---------------------------------------------------------------------------------', '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:=========================================================================================='] 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: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:---------------------------------------------------------------------------------',
'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:==========================================================================================']
self.assertEqual( self.assertEqual(
context.output, context.output,
@@ -401,23 +319,22 @@ class TestPlayer(unittest.TestCase):
@mock.patch("builtins.open", mock_open) @mock.patch("builtins.open", mock_open)
def test_dice_start(self): def test_dice_start(self):
player = Player("control.test.yml") player = Player("control.test.yml")
player.dice = mock.MagicMock() player.dice_interface = mock.MagicMock()
player.dice.start = mock.MagicMock() player.dice_interface.start = mock.MagicMock()
player.dice_start(1) player.dice_start(1)
player.dice.start.assert_called_once() player.dice_interface.start.assert_called_once()
@mock.patch("builtins.open", mock_open)
def test_gaussian_start(self):
player = Player("control.test.yml")
player.gaussian = mock.MagicMock()
player.gaussian.start = mock.MagicMock()
player.gaussian_start(1)
player.gaussian.start.assert_called_once()
# @mock.patch("builtins.open", mock_open)
# def test_gaussian_start(self):
# player = Player("control.test.yml")
# player.gaussian_interface = mock.MagicMock()
# player.gaussian_interface.start = mock.MagicMock()
#
# player.gaussian_start(1)
#
# player.gaussian_interface.start.assert_called_once()
if __name__ == '__main__': if __name__ == '__main__':