From 0c35dd6dd10dac38bba6e9c70a71826e0c901b58 Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Sun, 4 Dec 2022 19:51:38 -0500 Subject: [PATCH 01/11] create logging mode --- cv19/logger/__init__.py | 1 + cv19/logger/logger.py | 86 +++++++++++++++++++++++++++++++++++++++++ cv19/simulation.py | 45 ++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 cv19/logger/__init__.py create mode 100644 cv19/logger/logger.py diff --git a/cv19/logger/__init__.py b/cv19/logger/__init__.py new file mode 100644 index 0000000..4c98ddd --- /dev/null +++ b/cv19/logger/__init__.py @@ -0,0 +1 @@ +from .logger import * diff --git a/cv19/logger/logger.py b/cv19/logger/logger.py new file mode 100644 index 0000000..1541c9d --- /dev/null +++ b/cv19/logger/logger.py @@ -0,0 +1,86 @@ +import logging +import sys +from logging import handlers + + +class Logger(object): + ''' + Singleton Logger class. This class is only instantiated ONCE. It is to keep a consistent + criteria for the logger throughout the application if need be called upon. + It serves as the criteria for initiating logger for modules. It creates child loggers. + It's important to note these are child loggers as any changes made to the root logger + can be done. + ''' + + _instance = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + cls.debug_mode = True + cls.formatter = logging.Formatter( + "%(asctime)s — %(name)s — %(levelname)s — %(message)s" + ) + cls.log_file = "log_file.log" + + return cls._instance + + def get_console_handler(self): + '''Defines a console handler to come out on the console + Returns: + logging handler object : the console handler + ''' + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setFormatter(self.formatter) + console_handler.name = "consoleHandler" + return console_handler + + def get_file_handler(self): + '''Defines a file handler to come out on the console. + Returns: + logging handler object : the console handler + ''' + file_handler = handlers.RotatingFileHandler( + self.log_file, maxBytes=5000, backupCount=1 + ) + file_handler.setFormatter(self.formatter) + file_handler.name = "fileHandler" + return file_handler + + def add_handlers(self, logger, handler_list: list): + '''Adds handlers to the logger, checks first if handlers exist to avoid + duplication + Args: + logger: Logger to check handlers + handler_list: list of handlers to add + ''' + existing_handler_names = [] + for existing_handler in logger.handlers: + existing_handler_names.append(existing_handler.name) + + for new_handler in handler_list: + if new_handler.name not in existing_handler_names: + logger.addHandler(new_handler) + + def get_logger(self, logger_name: str): + '''Generates logger for use in the modules. + Args: + logger_name (string): name of the logger + Returns: + logger: returns logger for module + ''' + logger = logging.getLogger(logger_name) + console_handler = self.get_console_handler() + file_handler = self.get_file_handler() + self.add_handlers(logger, [console_handler, file_handler]) + logger.propagate = False + return logger + + def set_debug_mode(self, debug_mode: bool): + ''' + Function to set the root level logging to be debug level to be carried forward throughout + Args: + debug_mode (bool): debug mode initiation if true + ''' + if debug_mode: + logging.root.setLevel(logging.DEBUG) diff --git a/cv19/simulation.py b/cv19/simulation.py index dee1d8b..453a64e 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -3,6 +3,7 @@ from timeit import default_timer as timer from pathlib import Path import tomli +import logging import numpy as np import matplotlib.pyplot as plt @@ -12,6 +13,7 @@ from .population import Population from .policy import Policy from .interaction_sites import InteractionSites +from .logger import Logger class Simulation(): @@ -25,6 +27,8 @@ class Simulation(): ---------- verbose : bool A variable indicating whether to print updates with simulation information while running. + logging : bool + A variable indivating whether to log info/ warnings within the simulation. track_new_infected : :obj:`np.array` of int Holds the number of new infections for each day of the simulation. track_infected : :obj:`np.array` of int @@ -61,7 +65,7 @@ class Simulation(): A variable indicating if this object has run a simulaiton yet. """ - def __init__(self, config_file, config_dir="", verbose=False): + def __init__(self, config_file, config_dir="", verbose=False, logging=True): """ __init__ method docstring. Parameters @@ -73,6 +77,8 @@ def __init__(self, config_file, config_dir="", verbose=False): is a complete path. verbose : bool A variable indicating whether to print updates with simulation information while running. + logging : bool + A variable indicating whether to log errors/ warnings within the simulation. """ self.config_dir = config_dir @@ -83,6 +89,8 @@ def __init__(self, config_file, config_dir="", verbose=False): self.verbose = verbose # Whether or not to print daily simulation information. + self.logging = logging # Whether to log info or not + self.set_code_version() # Set the version of the code being used to run simulation. # Arrays to store the values during the simulation @@ -272,6 +280,15 @@ def run(self, fail_on_rerun=True): Variable to indicate whether the code should return an error if same object is run multiple times. """ + if self.logging: + # Starts logger for file + log = Logger().get_logger(__name__) + #log.basicConfig(filename='../notebooks/debugging.log', level=logging.INFO) + logging.root.setLevel(logging.INFO) + logging.captureWarnings(True) + log.info(f"{'':-<80}") + log.info(f"Simulation code version (from git): {self.code_id}\n") + # Check whether the simulation has already been run. if fail_on_rerun: @@ -334,21 +351,29 @@ def run(self, fail_on_rerun=True): mask_mandate = self.policy.update_mask_mandate(day=day) if mask_mandate != old_mask_mandate and self.verbose: print(f"Day: {day}, Mask Mandate: {mask_mandate}") + if self.logging: + log.info(f"Day: {day}, Mask Mandate: {mask_mandate}") old_mask_mandate = mask_mandate lockdown = self.policy.update_lockdown(day=day) if lockdown != old_lockdown_mandate and self.verbose: print(f"Day: {day}, Lockdown: {lockdown}") + if self.logging: + log.info(f"Day: {day}, Lockdown: {lockdown}") old_lockdown_mandate = lockdown testing_ON = self.policy.update_testing(day) if testing_ON != old_testing_mandate and self.verbose: print(f"Day: {day}, Testing: {testing_ON}") + if self.logging: + log.info(f"Day: {day}, Testing: {testing_ON}") old_testing_mandate = testing_ON students_go = self.policy.check_students(day=day) if students_go != old_student_mandate and self.verbose: print(f"Day: {day}, Uni Mandate: {students_go}") + if self.logging: + log.info(f"Day: {day}, Uni Mandate: {students_go}") old_student_mandate = students_go # infect random students on the day they come in @@ -466,10 +491,26 @@ def run(self, fail_on_rerun=True): print(f"{key}:{val[day]}", end=", ") print("\n") - if self.verbose: + if self.logging: time_seconds = timer() - beg_time m, s = divmod(time_seconds, 60) h, m = divmod(m, 60) + log.info(f"Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") + log.info("Simulation summary:") + log.info(f" Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") + log.info(f" {self.track_susceptible[-1]} never got it") + log.info(f" {self.track_dead[-1]} died") + log.info(f" {np.max(self.track_infected)} had it at the peak") + log.info(f" {self.track_tested[day]} were tested") + log.info(f" {np.max(self.track_quarantined)} were in quarantine at the peak") + log.info(f" {np.max(self.track_hospitalized)} at peak hospitalizations") + log.info(f" {np.max(self.track_dead[-1])} at peak deaths") + log.info(f" {self.track_vaccinated[day]} people were vaccinated") + log.info(f" {self.track_vaccinated[day]/self.nPop*100:.2f}% of population was vaccinated.") + + + if self.verbose: + print(f"{'':-<80}") print("Simulation summary:") print(f" Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") From 8545d1a9408142b4759addae789785737879ca93 Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Sun, 4 Dec 2022 20:02:54 -0500 Subject: [PATCH 02/11] only log simulation summary --- cv19/logger/logger.py | 24 ++++++++++++------------ cv19/simulation.py | 9 --------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/cv19/logger/logger.py b/cv19/logger/logger.py index 1541c9d..c844395 100644 --- a/cv19/logger/logger.py +++ b/cv19/logger/logger.py @@ -4,13 +4,13 @@ class Logger(object): - ''' + """ Singleton Logger class. This class is only instantiated ONCE. It is to keep a consistent criteria for the logger throughout the application if need be called upon. It serves as the criteria for initiating logger for modules. It creates child loggers. It's important to note these are child loggers as any changes made to the root logger can be done. - ''' + """ _instance = None @@ -26,20 +26,20 @@ def __new__(cls): return cls._instance def get_console_handler(self): - '''Defines a console handler to come out on the console + """Defines a console handler to come out on the console Returns: logging handler object : the console handler - ''' + """ console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(self.formatter) console_handler.name = "consoleHandler" return console_handler def get_file_handler(self): - '''Defines a file handler to come out on the console. + """Defines a file handler to come out on the console. Returns: logging handler object : the console handler - ''' + """ file_handler = handlers.RotatingFileHandler( self.log_file, maxBytes=5000, backupCount=1 ) @@ -48,12 +48,12 @@ def get_file_handler(self): return file_handler def add_handlers(self, logger, handler_list: list): - '''Adds handlers to the logger, checks first if handlers exist to avoid + """Adds handlers to the logger, checks first if handlers exist to avoid duplication Args: logger: Logger to check handlers handler_list: list of handlers to add - ''' + """ existing_handler_names = [] for existing_handler in logger.handlers: existing_handler_names.append(existing_handler.name) @@ -63,12 +63,12 @@ def add_handlers(self, logger, handler_list: list): logger.addHandler(new_handler) def get_logger(self, logger_name: str): - '''Generates logger for use in the modules. + """Generates logger for use in the modules. Args: logger_name (string): name of the logger Returns: logger: returns logger for module - ''' + """ logger = logging.getLogger(logger_name) console_handler = self.get_console_handler() file_handler = self.get_file_handler() @@ -77,10 +77,10 @@ def get_logger(self, logger_name: str): return logger def set_debug_mode(self, debug_mode: bool): - ''' + """ Function to set the root level logging to be debug level to be carried forward throughout Args: debug_mode (bool): debug mode initiation if true - ''' + """ if debug_mode: logging.root.setLevel(logging.DEBUG) diff --git a/cv19/simulation.py b/cv19/simulation.py index cd622ac..8a1f1c7 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -287,7 +287,6 @@ def run(self, fail_on_rerun=True): if self.logging: # Starts logger for file log = Logger().get_logger(__name__) - #log.basicConfig(filename='../notebooks/debugging.log', level=logging.INFO) logging.root.setLevel(logging.INFO) logging.captureWarnings(True) log.info(f"{'':-<80}") @@ -355,29 +354,21 @@ def run(self, fail_on_rerun=True): mask_mandate = self.policy.update_mask_mandate(day=day) if mask_mandate != old_mask_mandate and self.verbose: print(f"Day: {day}, Mask Mandate: {mask_mandate}") - if self.logging: - log.info(f"Day: {day}, Mask Mandate: {mask_mandate}") old_mask_mandate = mask_mandate lockdown = self.policy.update_lockdown(day=day) if lockdown != old_lockdown_mandate and self.verbose: print(f"Day: {day}, Lockdown: {lockdown}") - if self.logging: - log.info(f"Day: {day}, Lockdown: {lockdown}") old_lockdown_mandate = lockdown testing_ON = self.policy.update_testing(day) if testing_ON != old_testing_mandate and self.verbose: print(f"Day: {day}, Testing: {testing_ON}") - if self.logging: - log.info(f"Day: {day}, Testing: {testing_ON}") old_testing_mandate = testing_ON students_go = self.policy.check_students(day=day) if students_go != old_student_mandate and self.verbose: print(f"Day: {day}, Uni Mandate: {students_go}") - if self.logging: - log.info(f"Day: {day}, Uni Mandate: {students_go}") old_student_mandate = students_go # infect random students on the day they come in From 36ccbdedb2c42688216208798568aa1d1053a41b Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Sun, 4 Dec 2022 21:07:57 -0500 Subject: [PATCH 03/11] fix pylint errors --- cv19/logger/logger.py | 2 +- cv19/simulation.py | 47 +++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/cv19/logger/logger.py b/cv19/logger/logger.py index c844395..ce084e4 100644 --- a/cv19/logger/logger.py +++ b/cv19/logger/logger.py @@ -75,7 +75,7 @@ def get_logger(self, logger_name: str): self.add_handlers(logger, [console_handler, file_handler]) logger.propagate = False return logger - + def set_debug_mode(self, debug_mode: bool): """ Function to set the root level logging to be debug level to be carried forward throughout diff --git a/cv19/simulation.py b/cv19/simulation.py index 8a1f1c7..d6f229b 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -2,8 +2,8 @@ import subprocess from timeit import default_timer as timer from pathlib import Path -import tomli import logging +import tomli import numpy as np import matplotlib.pyplot as plt @@ -65,7 +65,7 @@ class Simulation(): A variable indicating if this object has run a simulaiton yet. """ - def __init__(self, config_file, config_dir="", verbose=False, logging=True): + def __init__(self, config_file, config_dir="", verbose=False, log=True): """ __init__ method docstring. Parameters @@ -77,7 +77,7 @@ def __init__(self, config_file, config_dir="", verbose=False, logging=True): is a complete path. verbose : bool A variable indicating whether to print updates with simulation information while running. - logging : bool + log : bool A variable indicating whether to log errors/ warnings within the simulation. """ @@ -89,7 +89,7 @@ def __init__(self, config_file, config_dir="", verbose=False, logging=True): self.verbose = verbose # Whether or not to print daily simulation information. - self.logging = logging # Whether to log info or not + self.log = log # Whether to log info or not self.set_code_version() # Set the version of the code being used to run simulation. @@ -284,14 +284,13 @@ def run(self, fail_on_rerun=True): Variable to indicate whether the code should return an error if same object is run multiple times. """ - if self.logging: + if self.log: # Starts logger for file log = Logger().get_logger(__name__) logging.root.setLevel(logging.INFO) logging.captureWarnings(True) - log.info(f"{'':-<80}") - log.info(f"Simulation code version (from git): {self.code_id}\n") - + log.info(f" %s",'-'*80) + log.info(f"Simulation code version (from git): %s", self.code_id) # Check whether the simulation has already been run. if fail_on_rerun: @@ -486,23 +485,23 @@ def run(self, fail_on_rerun=True): print(f"{key}:{val[day]}", end=", ") print("\n") - if self.logging: - time_seconds = timer() - beg_time - m, s = divmod(time_seconds, 60) - h, m = divmod(m, 60) - log.info(f"Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") - log.info("Simulation summary:") - log.info(f" Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") - log.info(f" {self.track_susceptible[-1]} never got it") - log.info(f" {self.track_dead[-1]} died") - log.info(f" {np.max(self.track_infected)} had it at the peak") - log.info(f" {self.track_tested[day]} were tested") - log.info(f" {np.max(self.track_quarantined)} were in quarantine at the peak") - log.info(f" {np.max(self.track_hospitalized)} at peak hospitalizations") - log.info(f" {np.max(self.track_dead[-1])} at peak deaths") - log.info(f" {self.track_vaccinated[day]} people were vaccinated") - log.info(f" {self.track_vaccinated[day]/self.nPop*100:.2f}% of population was vaccinated.") + time_seconds = timer() - beg_time + m, s = divmod(time_seconds, 60) + h, m = divmod(m, 60) + + if self.log: + log.info("Simulation summary:") + log.info(f" Time elapsed : %02.0f:%02.0f:%02.0f", h, m, s) + log.info(f" %i never got it", self.track_susceptible[-1]) + log.info(f" %i died", self.track_dead[-1]) + log.info(f" %i had it at the peak", np.max(self.track_infected)) + log.info(f" %i were tested", self.track_tested[day]) + log.info(f" %i were in quarantine at the peak", np.max(self.track_quarantined)) + log.info(f" %i at peak hospitalizations", np.max(self.track_hospitalized)) + log.info(f" %i at peak deaths", np.max(self.track_dead[-1])) + log.info(f" %i people were vaccinated", self.track_vaccinated[day]) + log.info(f" %0.2f percent of population was vaccinated.", self.track_vaccinated[day]/self.nPop*100) if self.verbose: From 7ee863788a6d26712cb0c8d292ac938d9cbc6aae Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Sun, 4 Dec 2022 21:18:43 -0500 Subject: [PATCH 04/11] fix pylint errors --- cv19/simulation.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cv19/simulation.py b/cv19/simulation.py index d6f229b..694ca40 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -289,8 +289,8 @@ def run(self, fail_on_rerun=True): log = Logger().get_logger(__name__) logging.root.setLevel(logging.INFO) logging.captureWarnings(True) - log.info(f" %s",'-'*80) - log.info(f"Simulation code version (from git): %s", self.code_id) + log.info(" %s", '-' * 80) + log.info("Simulation code version (from git): %s", self.code_id) # Check whether the simulation has already been run. if fail_on_rerun: @@ -492,16 +492,16 @@ def run(self, fail_on_rerun=True): if self.log: log.info("Simulation summary:") - log.info(f" Time elapsed : %02.0f:%02.0f:%02.0f", h, m, s) - log.info(f" %i never got it", self.track_susceptible[-1]) - log.info(f" %i died", self.track_dead[-1]) - log.info(f" %i had it at the peak", np.max(self.track_infected)) - log.info(f" %i were tested", self.track_tested[day]) - log.info(f" %i were in quarantine at the peak", np.max(self.track_quarantined)) - log.info(f" %i at peak hospitalizations", np.max(self.track_hospitalized)) - log.info(f" %i at peak deaths", np.max(self.track_dead[-1])) - log.info(f" %i people were vaccinated", self.track_vaccinated[day]) - log.info(f" %0.2f percent of population was vaccinated.", self.track_vaccinated[day]/self.nPop*100) + log.info(" Time elapsed : %02.0f:%02.0f:%02.0f", h, m, s) + log.info(" %i never got it", self.track_susceptible[-1]) + log.info(" %i died", self.track_dead[-1]) + log.info(" %i had it at the peak", np.max(self.track_infected)) + log.info(" %i were tested", self.track_tested[day]) + log.info(" %i were in quarantine at the peak", np.max(self.track_quarantined)) + log.info(" %i at peak hospitalizations", np.max(self.track_hospitalized)) + log.info(" %i at peak deaths", np.max(self.track_dead[-1])) + log.info(" %i people were vaccinated", self.track_vaccinated[day]) + log.info(" %0.2f percent of population was vaccinated.", self.track_vaccinated[day] / self.nPop * 100) if self.verbose: From 626640f75355a7ebea2667964248c01dca217f7a Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 15:58:52 -0500 Subject: [PATCH 05/11] updat logger --- config_files/main.toml | 3 + cv19/logger/__init__.py | 4 +- cv19/logger/logger.py | 11 +--- cv19/simulation.py | 134 ++++++++++++++-------------------------- 4 files changed, 54 insertions(+), 98 deletions(-) diff --git a/config_files/main.toml b/config_files/main.toml index f402d3c..5e5c4f1 100644 --- a/config_files/main.toml +++ b/config_files/main.toml @@ -180,3 +180,6 @@ protocol_compliance_lockdown_length_reduction = 0.5 Pfizer = 0.913 Moderna = 0.941 AZ = 0.76 + +[logging_info] +level = "INFO" \ No newline at end of file diff --git a/cv19/logger/__init__.py b/cv19/logger/__init__.py index 4c98ddd..f4b5ed1 100644 --- a/cv19/logger/__init__.py +++ b/cv19/logger/__init__.py @@ -1 +1,3 @@ -from .logger import * +from .logger import Logger + +__all__ = ['Logger'] diff --git a/cv19/logger/logger.py b/cv19/logger/logger.py index ce084e4..8e9e71d 100644 --- a/cv19/logger/logger.py +++ b/cv19/logger/logger.py @@ -41,7 +41,7 @@ def get_file_handler(self): logging handler object : the console handler """ file_handler = handlers.RotatingFileHandler( - self.log_file, maxBytes=5000, backupCount=1 + self.log_file, backupCount=1 ) file_handler.setFormatter(self.formatter) file_handler.name = "fileHandler" @@ -75,12 +75,3 @@ def get_logger(self, logger_name: str): self.add_handlers(logger, [console_handler, file_handler]) logger.propagate = False return logger - - def set_debug_mode(self, debug_mode: bool): - """ - Function to set the root level logging to be debug level to be carried forward throughout - Args: - debug_mode (bool): debug mode initiation if true - """ - if debug_mode: - logging.root.setLevel(logging.DEBUG) diff --git a/cv19/simulation.py b/cv19/simulation.py index 694ca40..c69bdc3 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -1,4 +1,3 @@ -import warnings import subprocess from timeit import default_timer as timer from pathlib import Path @@ -25,10 +24,6 @@ class Simulation(): Attributes ---------- - verbose : bool - A variable indicating whether to print updates with simulation information while running. - logging : bool - A variable indivating whether to log info/ warnings within the simulation. track_new_infected : :obj:`np.array` of int Holds the number of new infections for each day of the simulation. track_infected : :obj:`np.array` of int @@ -65,7 +60,7 @@ class Simulation(): A variable indicating if this object has run a simulaiton yet. """ - def __init__(self, config_file, config_dir="", verbose=False, log=True): + def __init__(self, config_file, config_dir=""): """ __init__ method docstring. Parameters @@ -75,10 +70,8 @@ def __init__(self, config_file, config_dir="", verbose=False, log=True): config_dir : str Path to the directory that stores the configuration file. Not required if config_file is a complete path. - verbose : bool - A variable indicating whether to print updates with simulation information while running. - log : bool - A variable indicating whether to log errors/ warnings within the simulation. + log_level : str + A variable indicating which level to log updates with simulation information while running. """ self.config_dir = config_dir @@ -87,10 +80,6 @@ def __init__(self, config_file, config_dir="", verbose=False, log=True): self.init_classes() # Have to initalize the classes after we have all of the parameters - self.verbose = verbose # Whether or not to print daily simulation information. - - self.log = log # Whether to log info or not - self.set_code_version() # Set the version of the code being used to run simulation. # Arrays to store the values during the simulation @@ -193,7 +182,7 @@ def load_disease_parameters(self, filename): return except FileNotFoundError: - warnings.warn((f"Unable to find file: {filepath} " + log.warning((f"Unable to find file: {filepath} " "assuming directory is relative to main config. " "Attempting read relative to CV19ROOT directory.")) @@ -237,12 +226,12 @@ def set_code_version(self): self.code_id = self.code_id.strip() except subprocess.CalledProcessError as e: - warnings.warn((f"Command '{' '.join(git_version_cmd)}' returned a non-zero " + log.warning((f"Command '{' '.join(git_version_cmd)}' returned a non-zero " f"exit code: {e.returncode}.")) print(e.output) except OSError: - warnings.warn("Could not set code version from git.") + log.warning("Could not set code version from git.") if self.code_id is not None: # By default, assume no local modifications. @@ -261,12 +250,12 @@ def set_code_version(self): dirty = True except subprocess.CalledProcessError as e: - warnings.warn((f"Command '{' '.join(git_dirty_cmd)}' returned a non-zero " + log.warning((f"Command '{' '.join(git_dirty_cmd)}' returned a non-zero " f"exit code: {e.returncode}.")) print(e.output) except OSError: - warnings.warn("Could not set code version from git.") + log.warning("Could not set code version from git.") if dirty: self.code_id += '-dirty' @@ -284,13 +273,20 @@ def run(self, fail_on_rerun=True): Variable to indicate whether the code should return an error if same object is run multiple times. """ - if self.log: - # Starts logger for file - log = Logger().get_logger(__name__) - logging.root.setLevel(logging.INFO) - logging.captureWarnings(True) - log.info(" %s", '-' * 80) - log.info("Simulation code version (from git): %s", self.code_id) + + log_level_info = {"DEBUG": logging.DEBUG, + "INFO": logging.INFO, + "WARNING": logging.WARNING, + "ERROR": logging.ERROR} + log_level_config = self.parameters["logging_info"]["level"] + log_level = log_level_info.get(log_level_config) + + # Starts logger for file + log = Logger().get_logger(__name__) + logging.root.setLevel(log_level) + logging.captureWarnings(True) + log.info(" %s", '-' * 70) + log.info("Starting simulation...") # Check whether the simulation has already been run. if fail_on_rerun: @@ -300,8 +296,7 @@ def run(self, fail_on_rerun=True): "fail_on_rerun argument to False.") self.check_has_run(check=False, information=information, fail=True) - if self.verbose: - print(f"Simulation code version (from git): {self.code_id}\n") + log.info(f"Simulation code version (from git): %s", self.code_id) # Get current time for measuring elapsed time of simulation. beg_time = timer() @@ -351,23 +346,23 @@ def run(self, fail_on_rerun=True): # UPDATE POLICY mask_mandate = self.policy.update_mask_mandate(day=day) - if mask_mandate != old_mask_mandate and self.verbose: - print(f"Day: {day}, Mask Mandate: {mask_mandate}") + if mask_mandate != old_mask_mandate: + log.info("Day: %i, Mask Mandate: %i", day, mask_mandate) old_mask_mandate = mask_mandate lockdown = self.policy.update_lockdown(day=day) - if lockdown != old_lockdown_mandate and self.verbose: - print(f"Day: {day}, Lockdown: {lockdown}") + if lockdown != old_lockdown_mandate: + log.info("Day: %i, Lockdown: %i", day, lockdown) old_lockdown_mandate = lockdown testing_ON = self.policy.update_testing(day) - if testing_ON != old_testing_mandate and self.verbose: - print(f"Day: {day}, Testing: {testing_ON}") + if testing_ON != old_testing_mandate: + log.info("Day: %i, Testing: %i", day, testing_ON) old_testing_mandate = testing_ON students_go = self.policy.check_students(day=day) - if students_go != old_student_mandate and self.verbose: - print(f"Day: {day}, Uni Mandate: {students_go}") + if students_go != old_student_mandate: + log.info("Day: %i, Uni Mandate: %i", day, students_go) old_student_mandate = students_go # infect random students on the day they come in @@ -466,61 +461,26 @@ def run(self, fail_on_rerun=True): self.track_time[day] = timer() - beg_time - if self.verbose: - print((f"Day: {day}, " - f"infected: {self.track_infected[day]}, " - f"recovered: {self.track_recovered[day]}, " - f"susceptible: {self.track_susceptible[day]}, " - f"dead: {self.track_dead[day]}, " - f"hospitalized: {self.track_hospitalized[day]}, " - f"ICU: {self.track_ICU[day]}, " - f"tested: {self.track_tested[day]}, " - f"total quarantined: {self.track_quarantined[day]}, " - f"infected students: {self.track_inf_students[day]}, " - f"vaccinated: {self.track_vaccinated[day]}")) - - # Print variants - print("Variants", end=": ") - for key, val in self.track_virus_types.items(): - print(f"{key}:{val[day]}", end=", ") - print("\n") + log.debug("Day: %i, infected: %i, recovered: %i, susceptible: %i, dead: %i, hospitalized: %i, ICU: %i, tested: %i,total quarantined: %i, infected students: %i, vaccinated: %i", day, self.track_infected[day], self.track_recovered[day], self.track_susceptible[day], self.track_dead[day], self.track_hospitalized[day], self.track_ICU[day], self.track_tested[day], self.track_quarantined[day], self.track_inf_students[day], self.track_vaccinated[day]) time_seconds = timer() - beg_time m, s = divmod(time_seconds, 60) h, m = divmod(m, 60) - if self.log: - - log.info("Simulation summary:") - log.info(" Time elapsed : %02.0f:%02.0f:%02.0f", h, m, s) - log.info(" %i never got it", self.track_susceptible[-1]) - log.info(" %i died", self.track_dead[-1]) - log.info(" %i had it at the peak", np.max(self.track_infected)) - log.info(" %i were tested", self.track_tested[day]) - log.info(" %i were in quarantine at the peak", np.max(self.track_quarantined)) - log.info(" %i at peak hospitalizations", np.max(self.track_hospitalized)) - log.info(" %i at peak deaths", np.max(self.track_dead[-1])) - log.info(" %i people were vaccinated", self.track_vaccinated[day]) - log.info(" %0.2f percent of population was vaccinated.", self.track_vaccinated[day] / self.nPop * 100) - - if self.verbose: - - print(f"{'':-<80}") - print("Simulation summary:") - print(f" Time elapsed: {h:02.0f}:{m:02.0f}:{s:02.0f}") - print(f" {self.track_susceptible[-1]} never got it") - print(f" {self.track_dead[-1]} died") - print(f" {np.max(self.track_infected)} had it at the peak") - print(f" {self.track_tested[day]} were tested") - print(f" {np.max(self.track_quarantined)} were in quarantine at the peak") - print(f" {np.max(self.track_hospitalized)} at peak hospitalizations") - print(f" {np.max(self.track_dead[-1])} at peak deaths") - print(" The breakdown of the variants is", end=": ") - for key, val in self.track_virus_types.items(): - print(f"{key}-{np.max(val)}", end=", ") - print("") - print(f" {self.track_vaccinated[day]} people were vaccinated") - print(f" {self.track_vaccinated[day]/self.nPop*100:.2f}% of population was vaccinated.") + log.info("Simulation summary:") + log.info(" Time elapsed : %02.0f:%02.0f:%02.0f", h, m, s) + log.info(" %i never got it", self.track_susceptible[-1]) + log.info(" %i died", self.track_dead[-1]) + log.info(" %i had it at the peak", np.max(self.track_infected)) + log.info(" %i were tested", self.track_tested[day]) + log.info(" %i were in quarantine at the peak", np.max(self.track_quarantined)) + log.info(" %i at peak hospitalizations", np.max(self.track_hospitalized)) + log.info(" %i at peak deaths", np.max(self.track_dead[-1])) + log.info("The breakdown of the variants is:") + for key, val in self.track_virus_types.items(): + log.info(" %s - %i", key, np.max(val)) + log.info(" %i people were vaccinated", self.track_vaccinated[day]) + log.info(" %0.2f percent of population was vaccinated.", self.track_vaccinated[day] / self.nPop * 100) self.has_run = True @@ -593,7 +553,7 @@ def check_has_run(self, check, information="", fail=True): if fail: raise RuntimeError(message) else: - warnings.warn(message, RuntimeWarning) + log.warning(message, RuntimeWarning) return self.has_run From cc07c802a36664e5b0379a1114d3714bda7bd0be Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 16:35:39 -0500 Subject: [PATCH 06/11] remove verbose as keyword --- cv19/parallel.py | 24 ++++++++---------------- test/test_Simulation.py | 4 ++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/cv19/parallel.py b/cv19/parallel.py index 71dd4ff..e8016dc 100644 --- a/cv19/parallel.py +++ b/cv19/parallel.py @@ -11,15 +11,13 @@ from .simulation import Simulation -def async_simulation(config_file, config_dir="", verbose=False): +def async_simulation(config_file, config_dir=""): """Does a single run of the simulation with the supplied configuration details. Parameters ---------- config_file : str Filename for the configuration file. - verbose : bool, default False - Whether to output information from each day of the simulation. Returns ------- @@ -27,12 +25,12 @@ def async_simulation(config_file, config_dir="", verbose=False): Arrays from the simulation. """ - sim = Simulation(config_file, config_dir=config_dir, verbose=verbose) + sim = Simulation(config_file, config_dir=config_dir) sim.run() return sim.get_arrays() -def run_async(num_runs, config_file, save_name=None, num_cores=-1, config_dir="", verbose=False): +def run_async(num_runs, config_file, save_name=None, num_cores=-1, config_dir=""): """Runs multiple simulations in parallel using the supplied configuration settings. Parameters @@ -46,8 +44,6 @@ def run_async(num_runs, config_file, save_name=None, num_cores=-1, config_dir="" num_cores : int, default=-1 Number of CPU cores to use when running the simulation. If -1, then use all available cores. - verbose : bool, default False - Whether to output information from each day of the simulation. Returns ------- @@ -61,7 +57,7 @@ def run_async(num_runs, config_file, save_name=None, num_cores=-1, config_dir="" # Run all of the simulations multiprocessing.freeze_support() with multiprocessing.Pool(processes=num_cores) as pool: - results = pool.starmap(async_simulation, ((config_file, config_dir, verbose) for _ in range(num_runs))) + results = pool.starmap(async_simulation, ((config_file, config_dir) for _ in range(num_runs))) df = pd.DataFrame(results) if save_name is not None: @@ -105,7 +101,7 @@ def _config_editor(config, param_name, value): x = x[param] -def tabular_mode(base_config_file, independent, dependent, num_runs=8, num_cores=8, save_name=None, verbose=False): +def tabular_mode(base_config_file, independent, dependent, num_runs=8, num_cores=8, save_name=None): """Automatically measures the impact of various public health measures on different metrics. Parameters @@ -142,8 +138,6 @@ def tabular_mode(base_config_file, independent, dependent, num_runs=8, num_cores If using a list, then the list must be exactly as long as the number of values for the independent variable, and each scenario will be saved under its corresponding filename. If None, then don't save any results. - verbose : bool, default False - Whether to output information from each day of the simulation. Returns ------- @@ -196,7 +190,7 @@ def tabular_mode(base_config_file, independent, dependent, num_runs=8, num_cores elif isinstance(save_name, str): scenario_save_name = save_name + f"{i:02}" data = run_async(num_runs, temp_config, num_cores=num_cores, - save_name=scenario_save_name, config_dir=config_dir, verbose=verbose) + save_name=scenario_save_name, config_dir=config_dir) # Processing the results to get the dependent measurements, add to results result = [f(data) for f in dep_funcs] @@ -227,7 +221,7 @@ def tabular_mode(base_config_file, independent, dependent, num_runs=8, num_cores return results -def confidence_interval(config, parameterstoplot, num_runs=8, confidence=0.80, num_cores=-1, save_name=None, verbose=False): +def confidence_interval(config, parameterstoplot, num_runs=8, confidence=0.80, num_cores=-1, save_name=None): """Plots the results of multiple simulations with confidence bands to give a better understanding of the trend of a given scenario. Displays a plot of the results. @@ -250,11 +244,9 @@ def confidence_interval(config, parameterstoplot, num_runs=8, confidence=0.80, n save_name: str or None, default None Name to save the results under. Default None, which means don't save the results. - verbose : bool, default False - Whether to output information from each day of the simulation. """ - result = run_async(num_runs, config, num_cores=num_cores, save_name=save_name, verbose=verbose) + result = run_async(num_runs, config, num_cores=num_cores, save_name=save_name) fig_ci, ax_ci = plt.subplots() z_score = st.norm.ppf(confidence) diff --git a/test/test_Simulation.py b/test/test_Simulation.py index 8158f7b..42d7db3 100755 --- a/test/test_Simulation.py +++ b/test/test_Simulation.py @@ -26,11 +26,11 @@ def setUp(self): simulation objects used for testing. """ quarantine_config_file_1 = str(Path(Path(__file__).parent, "testing_config_files/main_quarantine_1.toml").resolve()) - self.quarantine_obj_1 = Simulation(quarantine_config_file_1, verbose=False) + self.quarantine_obj_1 = Simulation(quarantine_config_file_1) self.quarantine_obj_1.run() quarantine_config_file_2 = str(Path(Path(__file__).parent, "testing_config_files/main_quarantine_2.toml").resolve()) - self.quarantine_obj_2 = Simulation(quarantine_config_file_2, verbose=False) + self.quarantine_obj_2 = Simulation(quarantine_config_file_2) self.quarantine_obj_2.run() def tearDown(self): From 0494bcbf579e8180a2242ce2f44217c43d38137c Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 16:36:15 -0500 Subject: [PATCH 07/11] fix pylint errors --- config_files/main.toml | 2 +- cv19/simulation.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config_files/main.toml b/config_files/main.toml index 5e5c4f1..d95dc7f 100644 --- a/config_files/main.toml +++ b/config_files/main.toml @@ -182,4 +182,4 @@ protocol_compliance_lockdown_length_reduction = 0.5 AZ = 0.76 [logging_info] -level = "INFO" \ No newline at end of file +level = "INFO" diff --git a/cv19/simulation.py b/cv19/simulation.py index 99f4acc..f8d0924 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -1,3 +1,4 @@ +import warnings import subprocess from timeit import default_timer as timer from pathlib import Path @@ -133,7 +134,7 @@ def load_disease_parameters(self, filename): return except FileNotFoundError: - log.warning((f"Unable to find file: {filepath} " + warnings.warn((f"Unable to find file: {filepath} " "assuming directory is relative to main config. " "Attempting read relative to CV19ROOT directory.")) @@ -177,12 +178,12 @@ def set_code_version(self): self.code_id = self.code_id.strip() except subprocess.CalledProcessError as e: - log.warning((f"Command '{' '.join(git_version_cmd)}' returned a non-zero " + warnings.warn((f"Command '{' '.join(git_version_cmd)}' returned a non-zero " f"exit code: {e.returncode}.")) print(e.output) except OSError: - log.warning("Could not set code version from git.") + warnings.warn("Could not set code version from git.") if self.code_id is not None: # By default, assume no local modifications. @@ -201,12 +202,12 @@ def set_code_version(self): dirty = True except subprocess.CalledProcessError as e: - log.warning((f"Command '{' '.join(git_dirty_cmd)}' returned a non-zero " + warnings.warn((f"Command '{' '.join(git_dirty_cmd)}' returned a non-zero " f"exit code: {e.returncode}.")) print(e.output) except OSError: - log.warning("Could not set code version from git.") + warnings.warn("Could not set code version from git.") if dirty: self.code_id += '-dirty' @@ -283,7 +284,7 @@ def run(self, fail_on_rerun=True): "fail_on_rerun argument to False.") self.check_has_run(check=False, information=information, fail=True) - log.info(f"Simulation code version (from git): %s", self.code_id) + log.info("Simulation code version (from git): %s", self.code_id) # Get current time for measuring elapsed time of simulation. beg_time = timer() @@ -560,7 +561,7 @@ def check_has_run(self, check, information="", fail=True): if fail: raise RuntimeError(message) else: - log.warning(message, RuntimeWarning) + warnings.warn(message, RuntimeWarning) return self.has_run From 954aa8b2991232120db6256c7eee5d91021a44de Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 16:51:13 -0500 Subject: [PATCH 08/11] fix long line --- cv19/simulation.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cv19/simulation.py b/cv19/simulation.py index f8d0924..3f9839b 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -420,7 +420,12 @@ def run(self, fail_on_rerun=True): self.tracking_df.at[day, "time"] = timer() - beg_time - log.debug("Day: %i, infected: %i, recovered: %i, susceptible: %i, dead: %i, hospitalized: %i, ICU: %i, tested: %i,total quarantined: %i, infected students: %i, vaccinated: %i", day, self.tracking_df.at[day, 'infected'], self.tracking_df.at[day, 'recovered'], self.tracking_df.at[day, 'susceptible'], self.tracking_df.at[day, 'dead'], self.tracking_df.at[day, 'hospitalized'], self.tracking_df.at[day, 'ICU'], self.tracking_df.at[day, 'tested'], self.tracking_df.at[day, 'quarantined'], self.tracking_df.at[day, 'inf_students'], self.tracking_df.at[day, 'vaccinated']) + log.debug("Day: %i, infected: %i, recovered: %i, susceptible: %i, dead: %i, hospitalized: %i, ICU: %i, tested: %i, total quarantined: %i, infected students: %i, vaccinated: %i", + day, self.tracking_df.at[day, 'infected'], self.tracking_df.at[day, 'recovered'], + self.tracking_df.at[day, 'susceptible'], self.tracking_df.at[day, 'dead'], + self.tracking_df.at[day, 'hospitalized'], self.tracking_df.at[day, 'ICU'], + self.tracking_df.at[day, 'tested'], self.tracking_df.at[day, 'quarantined'], + self.tracking_df.at[day, 'inf_students'], self.tracking_df.at[day, 'vaccinated']) time_seconds = timer() - beg_time m, s = divmod(time_seconds, 60) From 9a42568f27a80a3eb2686816a072ffedd8079140 Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 16:51:57 -0500 Subject: [PATCH 09/11] add logging_info to test configs --- test/testing_config_files/main_quarantine_1.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/testing_config_files/main_quarantine_1.toml b/test/testing_config_files/main_quarantine_1.toml index 8410658..7480e96 100644 --- a/test/testing_config_files/main_quarantine_1.toml +++ b/test/testing_config_files/main_quarantine_1.toml @@ -180,3 +180,6 @@ protocol_compliance_lockdown_length_reduction = 0.5 Pfizer = 0.087 Moderna = 0.059 AZ = 0.24 + +[logging_info] +level = "INFO" From ed9721c966dcdd8625d58ef1113e17145bdb3b29 Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Mon, 2 Jan 2023 17:03:59 -0500 Subject: [PATCH 10/11] add logging info to test2 and fix typo --- cv19/simulation.py | 2 -- test/testing_config_files/main_quarantine_2.toml | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cv19/simulation.py b/cv19/simulation.py index 3f9839b..e7f12e9 100644 --- a/cv19/simulation.py +++ b/cv19/simulation.py @@ -47,8 +47,6 @@ def __init__(self, config_file, config_dir=""): config_dir : str Path to the directory that stores the configuration file. Not required if config_file is a complete path. - log_level : str - A variable indicating which level to log updates with simulation information while running. """ self.config_dir = config_dir diff --git a/test/testing_config_files/main_quarantine_2.toml b/test/testing_config_files/main_quarantine_2.toml index e0e07a5..b17e74e 100644 --- a/test/testing_config_files/main_quarantine_2.toml +++ b/test/testing_config_files/main_quarantine_2.toml @@ -180,3 +180,6 @@ protocol_compliance_lockdown_length_reduction = 0.5 Pfizer = 0.087 Moderna = 0.059 AZ = 0.24 + +[logging_info] +level = "INFO" From b3f539c12666d9286b213465b772322c37c53e35 Mon Sep 17 00:00:00 2001 From: ashleymicuda Date: Sat, 21 Jan 2023 13:45:42 -0500 Subject: [PATCH 11/11] add function name --- cv19/logger/logger.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cv19/logger/logger.py b/cv19/logger/logger.py index 8e9e71d..e7cc50d 100644 --- a/cv19/logger/logger.py +++ b/cv19/logger/logger.py @@ -15,6 +15,10 @@ class Logger(object): _instance = None def __new__(cls): + """Instantiates the logger or returns same instance. + Returns: + logging handler object : the log file + """ if cls._instance is None: cls._instance = super().__new__(cls) cls.debug_mode = True @@ -26,7 +30,7 @@ def __new__(cls): return cls._instance def get_console_handler(self): - """Defines a console handler to come out on the console + """Defines a console handler to come out on the console. Returns: logging handler object : the console handler """