From 5f45aed36324ad70e912759ebd15fba2ff6c9593 Mon Sep 17 00:00:00 2001 From: harryswift01 Date: Mon, 7 Apr 2025 16:24:39 +0100 Subject: [PATCH 1/4] Fix: Ensure verbose flag in YAML sets logging to DEBUG mode - Updated `merge_configs` method to explicitly handle the `verbose` flag from YAML configuration - Added `update_logging_level` method to `LoggingConfig` class to update logging levels for all loggers and handlers - Modified `main` function to use the new method for updating logging levels - Ensured `DEBUG` level messages are directed to file handlers while console handler remains at `INFO` level - Updated the input YAML file template to make sure they correctly match up to the arguments in argsparse --- CodeEntropy/config/logging_config.py | 40 +++++++++++++++++++++------- CodeEntropy/main_mcc.py | 25 +++++++++-------- config.yaml | 5 ++-- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/CodeEntropy/config/logging_config.py b/CodeEntropy/config/logging_config.py index 475fc2e..106b3ae 100644 --- a/CodeEntropy/config/logging_config.py +++ b/CodeEntropy/config/logging_config.py @@ -4,7 +4,7 @@ class LoggingConfig: - def __init__(self, folder, default_level=logging.INFO): + def __init__(self, folder, log_level=logging.INFO): log_directory = os.path.join(folder, "logs") os.makedirs(log_directory, exist_ok=True) @@ -26,52 +26,52 @@ def __init__(self, folder, default_level=logging.INFO): "console": { "class": "logging.StreamHandler", "formatter": "simple", - "level": "INFO", + "level": logging.INFO, }, "stdout": { "class": "logging.FileHandler", "filename": os.path.join(log_directory, "program.out"), "formatter": "simple", - "level": "INFO", + "level": logging.INFO, }, "logfile": { "class": "logging.FileHandler", "filename": os.path.join(log_directory, "program.log"), "formatter": "detailed", - "level": "DEBUG", + "level": logging.DEBUG, }, "errorfile": { "class": "logging.FileHandler", "filename": os.path.join(log_directory, "program.err"), "formatter": "detailed", - "level": "ERROR", + "level": logging.ERROR, }, "commandfile": { "class": "logging.FileHandler", "filename": os.path.join(log_directory, "program.com"), "formatter": "simple", - "level": "INFO", + "level": logging.INFO, }, "mdanalysis_log": { "class": "logging.FileHandler", "filename": os.path.join(log_directory, "mdanalysis.log"), "formatter": "detailed", - "level": "DEBUG", + "level": logging.DEBUG, }, }, "loggers": { "": { "handlers": ["console", "stdout", "logfile", "errorfile"], - "level": default_level, + "level": log_level, }, "MDAnalysis": { "handlers": ["mdanalysis_log"], - "level": "DEBUG", + "level": logging.DEBUG, "propagate": False, }, "commands": { "handlers": ["commandfile"], - "level": "INFO", + "level": logging.INFO, "propagate": False, }, }, @@ -82,3 +82,23 @@ def setup_logging(self): logging.getLogger("MDAnalysis") logging.getLogger("commands") return logging.getLogger(__name__) + + def update_logging_level(self, log_level): + # Update the root logger level + root_logger = logging.getLogger() + root_logger.setLevel(log_level) + for handler in root_logger.handlers: + if isinstance(handler, logging.FileHandler): + handler.setLevel(logging.DEBUG) + else: + handler.setLevel(logging.INFO) + + # Update all other loggers and their handlers + for logger_name in self.LOGGING["loggers"]: + logger = logging.getLogger(logger_name) + logger.setLevel(log_level) + for handler in logger.handlers: + if isinstance(handler, logging.FileHandler): + handler.setLevel(logging.DEBUG) + else: + handler.setLevel(logging.INFO) diff --git a/CodeEntropy/main_mcc.py b/CodeEntropy/main_mcc.py index e163640..3c52d37 100644 --- a/CodeEntropy/main_mcc.py +++ b/CodeEntropy/main_mcc.py @@ -67,24 +67,27 @@ def main(): args, unknown = parser.parse_known_args() args.outfile = os.path.join(folder, args.outfile) - # Determine logging level - log_level = logging.DEBUG if args.verbose else logging.INFO - - # Initialize the logging system with the determined log level - logging_config = LoggingConfig(folder, default_level=log_level) - logger = logging_config.setup_logging() - - # Capture and log the command-line invocation - command = " ".join(sys.argv) - logging.getLogger("commands").info(command) - try: + # Initialize the logging system once + logging_config = LoggingConfig(folder) + logger = logging_config.setup_logging() + # Process each run in the YAML configuration for run_name, run_config in config.items(): if isinstance(run_config, dict): # Merging CLI arguments with YAML configuration args = arg_config.merge_configs(args, run_config) + # Determine logging level + log_level = logging.DEBUG if args.verbose else logging.INFO + + # Update the logging level + logging_config.update_logging_level(log_level) + + # Capture and log the command-line invocation + command = " ".join(sys.argv) + logging.getLogger("commands").info(command) + # Ensure necessary arguments are provided if not getattr(args, "top_traj_file"): raise ValueError( diff --git a/config.yaml b/config.yaml index aee4538..10303a9 100644 --- a/config.yaml +++ b/config.yaml @@ -7,11 +7,10 @@ run1: end: step: bin_width: - tempra: + temperature: verbose: thread: outfile: - resfile: mout: force_partitioning: - waterEntropy: + waterEntropy: From bfb0b77e2fb66ee36b580ca4f5232770811cfd68 Mon Sep 17 00:00:00 2001 From: harryswift01 Date: Tue, 8 Apr 2025 09:29:42 +0100 Subject: [PATCH 2/4] Update to various arguments names to ensure consistency is maintainted: - Updated `waterEntropy` to `water_entropy` - Updated `mout` to `matrix_out` - Updated `outfile` to `output_file` - Ensured that any instance of any of these arguments have been changed throughout the codebase to match - Updated some of the test cases so that they match the new arguments names and made sure they have the correct file format to maintain consistency --- CodeEntropy/config/arg_config_manager.py | 12 +++++--- CodeEntropy/config/data_logger.py | 4 +-- CodeEntropy/main_mcc.py | 6 ++-- config.yaml | 6 ++-- .../test_arg_config_manager.py | 28 ++++++++----------- tests/test_EntropyFunctions/test_main_mcc.py | 7 ++--- 6 files changed, 31 insertions(+), 32 deletions(-) diff --git a/CodeEntropy/config/arg_config_manager.py b/CodeEntropy/config/arg_config_manager.py index cacb73a..83ba87e 100644 --- a/CodeEntropy/config/arg_config_manager.py +++ b/CodeEntropy/config/arg_config_manager.py @@ -48,18 +48,22 @@ "help": "Enable verbose output", }, "thread": {"type": int, "help": "How many multiprocess to use", "default": 1}, - "outfile": { + "output_file": { "type": str, "help": "Name of the file where the output will be written", - "default": "outfile.json", + "default": "output_file.json", }, - "mout": { + "matrix_out": { "type": str, "help": "Name of the file where certain matrices will be written", "default": None, }, "force_partitioning": {"type": float, "help": "Force partitioning", "default": 0.5}, - "waterEntropy": {"type": bool, "help": "Calculate water entropy", "default": False}, + "water_entropy": { + "type": bool, + "help": "Calculate water entropy", + "default": False, + }, } diff --git a/CodeEntropy/config/data_logger.py b/CodeEntropy/config/data_logger.py index c22e1ae..483db7d 100644 --- a/CodeEntropy/config/data_logger.py +++ b/CodeEntropy/config/data_logger.py @@ -12,7 +12,7 @@ def __init__(self): self.molecule_data = [] self.residue_data = [] - def save_dataframes_as_json(self, molecule_df, residue_df, outfile): + def save_dataframes_as_json(self, molecule_df, residue_df, output_file): """Save multiple DataFrames into a single JSON file with separate keys""" data = { "molecule_data": molecule_df.to_dict(orient="records"), @@ -20,7 +20,7 @@ def save_dataframes_as_json(self, molecule_df, residue_df, outfile): } # Write JSON data to file - with open(outfile, "w") as out: + with open(output_file, "w") as out: json.dump(data, out, indent=4) def add_results_data(self, molecule, level, type, S_molecule): diff --git a/CodeEntropy/main_mcc.py b/CodeEntropy/main_mcc.py index 3c52d37..e3cdc61 100644 --- a/CodeEntropy/main_mcc.py +++ b/CodeEntropy/main_mcc.py @@ -65,7 +65,7 @@ def main(): parser = arg_config.setup_argparse() args, unknown = parser.parse_known_args() - args.outfile = os.path.join(folder, args.outfile) + args.output_file = os.path.join(folder, args.output_file) try: # Initialize the logging system once @@ -432,7 +432,7 @@ def main(): # 'Type':['Orientational (J/mol/K)'], # 'Result': [S_orient],}) # results_df = pd.concat([results_df, new_row], ignore_index=True) - # with open(args.outfile, "a") as out: + # with open(args.output_file, "a") as out: # print(molecule, # "\t", # level, @@ -457,7 +457,7 @@ def main(): molecule, level, "Molecule Total Entropy", S_molecule ) data_logger.save_dataframes_as_json( - results_df, residue_results_df, args.outfile + results_df, residue_results_df, args.output_file ) logger.info("Molecules:") diff --git a/config.yaml b/config.yaml index 10303a9..39ae5f0 100644 --- a/config.yaml +++ b/config.yaml @@ -10,7 +10,7 @@ run1: temperature: verbose: thread: - outfile: - mout: + output_file: + matrix_output: force_partitioning: - waterEntropy: + water_entropy: diff --git a/tests/test_EntropyFunctions/test_arg_config_manager.py b/tests/test_EntropyFunctions/test_arg_config_manager.py index 992b21c..c204c79 100644 --- a/tests/test_EntropyFunctions/test_arg_config_manager.py +++ b/tests/test_EntropyFunctions/test_arg_config_manager.py @@ -62,11 +62,10 @@ def setup_file(self, mock_file): "tempra: 298.0\n " "verbose: False\n " "thread: 1\n " - "outfile: 'outfile.out'\n " - "resfile: 'res_outfile.out'\n " - "mout: null\n " + "output_file: 'output_file.json'\n " + "matrix_out: null\n " "force_partitioning: 0.5\n " - "waterEntropy: False" + "water_entropy: False" ).return_value @patch("builtins.open", new_callable=mock_open) @@ -126,11 +125,10 @@ def test_invalid_run_config_type(self): tempra=298.0, verbose=False, thread=1, - outfile="outfile.out", - resfile="res_outfile.out", - mout=None, + output_file="output_file.json", + matrix_out=None, force_partitioning=0.5, - waterEntropy=False, + water_entropy=False, ), ) def test_setup_argparse(self, mock_args): @@ -271,11 +269,10 @@ def test_merge_configs(self): tempra=None, verbose=None, thread=None, - outfile=None, - resfile=None, - mout=None, + output_file=None, + matrix_out=None, force_partitioning=None, - waterEntropy=None, + water_entropy=None, ) run_config = { "top_traj_file": ["/path/to/tpr", "/path/to/trr"], @@ -287,11 +284,10 @@ def test_merge_configs(self): "tempra": 298.0, "verbose": False, "thread": 1, - "outfile": "outfile.out", - "resfile": "res_outfile.out", - "mout": None, + "output_file": "output_file.json", + "matrix_out": None, "force_partitioning": 0.5, - "waterEntropy": False, + "water_entropy": False, } merged_args = arg_config.merge_configs(args, run_config) self.assertEqual(merged_args.top_traj_file, ["/path/to/tpr", "/path/to/trr"]) diff --git a/tests/test_EntropyFunctions/test_main_mcc.py b/tests/test_EntropyFunctions/test_main_mcc.py index 0feb7d9..828da0f 100644 --- a/tests/test_EntropyFunctions/test_main_mcc.py +++ b/tests/test_EntropyFunctions/test_main_mcc.py @@ -54,11 +54,10 @@ def setup_file(self, mock_file): "tempra: 298.0\n " "verbose: False\n " "thread: 1\n " - "outfile: 'outfile.out'\n " - "resfile: 'res_outfile.out'\n " - "mout: null\n " + "output_file: 'output_file.json'\n " + "matrix_out: null\n " "force_partitioning: 0.5\n " - "waterEntropy: False" + "water_entropy: False" ).return_value def test_CodeEntropy_imported(self): From 0e4b6c028f2b4a2615e29ecd222b2041ef9cb89a Mon Sep 17 00:00:00 2001 From: skfegan Date: Mon, 7 Apr 2025 15:52:25 +0100 Subject: [PATCH 3/4] fixing indexing issue for start and end parameters affecting timesteps --- CodeEntropy/calculations/ConformationFunctions.py | 3 ++- CodeEntropy/calculations/LevelFunctions.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CodeEntropy/calculations/ConformationFunctions.py b/CodeEntropy/calculations/ConformationFunctions.py index cd62d25..b51746a 100644 --- a/CodeEntropy/calculations/ConformationFunctions.py +++ b/CodeEntropy/calculations/ConformationFunctions.py @@ -38,13 +38,14 @@ def assign_conformation( # get the values of the angle for the dihedral # dihedral angle values have a range from -180 to 180 for timestep in data_container.trajectory[start:end:step]: + timestep_index = timestep.frame - start value = dihedral.value() # we want postive values in range 0 to 360 to make the peak assignment work # using the fact that dihedrals have circular symetry # (i.e. -15 degrees = +345 degrees) if value < 0: value += 360 - phi[timestep.frame] = value + phi[timestep_index] = value # create a histogram using numpy number_bins = int(360 / bin_width) diff --git a/CodeEntropy/calculations/LevelFunctions.py b/CodeEntropy/calculations/LevelFunctions.py index ac2d089..a837e9f 100644 --- a/CodeEntropy/calculations/LevelFunctions.py +++ b/CodeEntropy/calculations/LevelFunctions.py @@ -94,10 +94,11 @@ def get_matrices( trans_axes, rot_axes = GF.get_axes(data_container, level, bead_index) # Sort out coordinates, forces, and torques for each atom in the bead - weighted_forces[bead_index][timestep.frame] = GF.get_weighted_forces( + timestep_index = timestep.frame - start + weighted_forces[bead_index][timestep_index] = GF.get_weighted_forces( data_container, list_of_beads[bead_index], trans_axes, highest_level ) - weighted_torques[bead_index][timestep.frame] = GF.get_weighted_torques( + weighted_torques[bead_index][timestep_index] = GF.get_weighted_torques( data_container, list_of_beads[bead_index], rot_axes ) From cfaec9c6245ce6e9f48b6c4079d71595e9f81cd2 Mon Sep 17 00:00:00 2001 From: harryswift01 Date: Tue, 8 Apr 2025 13:57:53 +0100 Subject: [PATCH 4/4] Removal of `matrix_out` as this is now handled in the python logging system --- CodeEntropy/config/arg_config_manager.py | 5 ----- config.yaml | 3 +-- tests/test_EntropyFunctions/test_arg_config_manager.py | 4 ---- tests/test_EntropyFunctions/test_main_mcc.py | 1 - 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/CodeEntropy/config/arg_config_manager.py b/CodeEntropy/config/arg_config_manager.py index 83ba87e..607bf36 100644 --- a/CodeEntropy/config/arg_config_manager.py +++ b/CodeEntropy/config/arg_config_manager.py @@ -53,11 +53,6 @@ "help": "Name of the file where the output will be written", "default": "output_file.json", }, - "matrix_out": { - "type": str, - "help": "Name of the file where certain matrices will be written", - "default": None, - }, "force_partitioning": {"type": float, "help": "Force partitioning", "default": 0.5}, "water_entropy": { "type": bool, diff --git a/config.yaml b/config.yaml index 39ae5f0..30c0133 100644 --- a/config.yaml +++ b/config.yaml @@ -10,7 +10,6 @@ run1: temperature: verbose: thread: - output_file: - matrix_output: + output_file: force_partitioning: water_entropy: diff --git a/tests/test_EntropyFunctions/test_arg_config_manager.py b/tests/test_EntropyFunctions/test_arg_config_manager.py index c204c79..989e090 100644 --- a/tests/test_EntropyFunctions/test_arg_config_manager.py +++ b/tests/test_EntropyFunctions/test_arg_config_manager.py @@ -63,7 +63,6 @@ def setup_file(self, mock_file): "verbose: False\n " "thread: 1\n " "output_file: 'output_file.json'\n " - "matrix_out: null\n " "force_partitioning: 0.5\n " "water_entropy: False" ).return_value @@ -126,7 +125,6 @@ def test_invalid_run_config_type(self): verbose=False, thread=1, output_file="output_file.json", - matrix_out=None, force_partitioning=0.5, water_entropy=False, ), @@ -270,7 +268,6 @@ def test_merge_configs(self): verbose=None, thread=None, output_file=None, - matrix_out=None, force_partitioning=None, water_entropy=None, ) @@ -285,7 +282,6 @@ def test_merge_configs(self): "verbose": False, "thread": 1, "output_file": "output_file.json", - "matrix_out": None, "force_partitioning": 0.5, "water_entropy": False, } diff --git a/tests/test_EntropyFunctions/test_main_mcc.py b/tests/test_EntropyFunctions/test_main_mcc.py index 828da0f..c771685 100644 --- a/tests/test_EntropyFunctions/test_main_mcc.py +++ b/tests/test_EntropyFunctions/test_main_mcc.py @@ -55,7 +55,6 @@ def setup_file(self, mock_file): "verbose: False\n " "thread: 1\n " "output_file: 'output_file.json'\n " - "matrix_out: null\n " "force_partitioning: 0.5\n " "water_entropy: False" ).return_value