From 28a66d3b2f64bde42cf669a663157830d3d63388 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:12:08 -0400 Subject: [PATCH 1/7] (core) added NN id to the `Calculator`'s `updateModelAvailability` printout --- pysipfenn/core/pysipfenn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pysipfenn/core/pysipfenn.py b/pysipfenn/core/pysipfenn.py index fc23833..48dfd31 100644 --- a/pysipfenn/core/pysipfenn.py +++ b/pysipfenn/core/pysipfenn.py @@ -212,16 +212,16 @@ def updateModelAvailability(self) -> None: if all_files.__contains__(net + '.onnx'): detectedNets.append(net) try: - print(f"{Fore.GREEN}✔ {netName}{Style.RESET_ALL}") + print(f"{Fore.GREEN}✔ {net:<45} | {netName}{Style.RESET_ALL}") except UnicodeEncodeError: # Fallback to ASCII characters if Unicode encoding fails - print(f"{Fore.GREEN}+ {netName}{Style.RESET_ALL}") + print(f"{Fore.GREEN}+ {net:<45} | {netName}{Style.RESET_ALL}") else: try: - print(f"{Style.DIM}✘ {netName}{Style.RESET_ALL}") + print(f"{Style.DIM}✘ {net:<45} | {netName}{Style.RESET_ALL}") except UnicodeEncodeError: # Fallback to ASCII characters if Unicode encoding fails - print(f"{Fore.DIM}x {netName}{Style.RESET_ALL}") + print(f"{Fore.DIM}x {net:<45} | {netName}{Style.RESET_ALL}") self.network_list_available = detectedNets def downloadModels(self, network: str = 'all') -> None: From b9ed300a4ec1e69fef85ff5d5d403fda9985cc23 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:52:38 -0400 Subject: [PATCH 2/7] (core) started implementing the new `verbose`/`printOut` flags and their propagation into procedures; established `log()` function to redirect the feed --- pysipfenn/core/pysipfenn.py | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/pysipfenn/core/pysipfenn.py b/pysipfenn/core/pysipfenn.py index 48dfd31..cea0906 100644 --- a/pysipfenn/core/pysipfenn.py +++ b/pysipfenn/core/pysipfenn.py @@ -4,6 +4,7 @@ import csv import json from time import perf_counter +from datetime import datetime from typing import List, Union, Dict from importlib import resources @@ -49,8 +50,14 @@ class Calculator: autoLoad: Automatically load all available ML models based on the ``models.json`` file. This `will` require significant memory and time if they are available, so for featurization and other non-model-requiring tasks, it is recommended to set this to ``False``. Defaults to ``True``. - verbose: Print initialization messages and several other non-critical messages during runtime procedures. - Defaults to True. + verbose: Controls the verbosity of the ``Calculator`` printout messages. By default, it is set to ``True`` and + shows the level of information that shoudl be optimal for most users. Setting it to ``False`` will + make messages concise and only show critical information. To further suppress messages, use the + ``printOut`` switch. + printOut: Controls whether the ``Calculator`` should print any messages to the console. By default, it is set + to ``True``. If set to ``False``, no messages will be printed to the console, regardless of the ``verbose`` + setting, but they will be retained in the ``self.printOutLog`` attribute of the ``Calculator`` object, allowing + easy access to the messages if needed for, e.g., debugging purposes. Attributes: models: Dictionary with all model information based on the ``models.json`` file in the modelsSIPFENN @@ -65,15 +72,24 @@ class Calculator: of predictions for each structure corresponds to the order of networks in the toRun list. inputFiles: List of all input file names used during the last predictions run. The order of the list corresponds to the order of atomic structures given to models as input. + verbose: Boolean controlling the verbosity of the ``Calculator`` printout messages set during initialization. + printOut: Boolean controlling whether the ``Calculator`` should print any messages to the console set during + initialization. + printOutLog: String containing all messages logged by the ``Calculator`` object if ``printOut`` was set to ``True``. """ def __init__(self, autoLoad: bool = True, - verbose: bool = True): + verbose: bool = True, + printOut: bool = True + ): """Initializes the pySIPFENN Calculator object.""" - if verbose: - print('\n********* Initializing pySIPFENN Calculator **********') self.verbose = verbose + self.printOut = printOut + self.printOutLog = "" + + self.log('\n********* Initializing pySIPFENN Calculator **********') + # dictionary with all model information with resources.files('pysipfenn.modelsSIPFENN').joinpath('models.json').open('r') as f: if verbose: @@ -127,6 +143,24 @@ def __str__(self): printOut += f' {len(self.predictions[0])} predictions/structure\n' return printOut + def log(self, message: str) -> None: + """Logs a message to the ``self.printOut`` attribute of the ``Calculator`` object if ``self.printOutSet`` is ``False``. + Otherwise, the message is printed to the console as usual. The messages stored in the ``self.printOut`` attribute are + additonally automatically time stamped (YY-MM-DD HH:MM:SS | ) for easy tracking of the events. + + Args: + message: Message to log. + + Returns: + None + """ + if self.printOut: + print(message, flush=True) + else: + time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + self.printOutLog += f'{time} | {message}\n' + + # ********************************* PROTOTYPE HANDLING ********************************* def parsePrototypeLibrary(self, customPath: str = "default", From dbf0c33a1ee8a25207f42e069a2b521a3d337e11 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:48:00 -0400 Subject: [PATCH 3/7] (core) improved `parsePrototypeLibrary` printout behavior --- pysipfenn/core/pysipfenn.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pysipfenn/core/pysipfenn.py b/pysipfenn/core/pysipfenn.py index cea0906..a3675e4 100644 --- a/pysipfenn/core/pysipfenn.py +++ b/pysipfenn/core/pysipfenn.py @@ -164,7 +164,6 @@ def log(self, message: str) -> None: # ********************************* PROTOTYPE HANDLING ********************************* def parsePrototypeLibrary(self, customPath: str = "default", - verbose: bool = False, printCustomLibrary: bool = False) -> None: """Parses the prototype library YAML file in the ``misc`` directory, interprets them into pymatgen ``Structure`` objects, and stores them in the ``self.prototypeLibrary`` dict attribute of the ``Calculator`` object. You can use it @@ -174,8 +173,6 @@ def parsePrototypeLibrary(self, Args: customPath: Path to the prototype library YAML file. Defaults to the magic string ``"default"``, which loads the default prototype library included in the package in the ``misc`` directory. - verbose: If True, it prints the number of prototypes loaded. Defaults to ``False``, but note that ``Calculator`` - class automatically initializes with ``verbose=True``. printCustomLibrary: If True, it prints the name and POSCAR of each prototype being added to the prototype library. Has no effect if ``customPath`` is ``'default'``. Defaults to ``False``. @@ -209,12 +206,15 @@ class automatically initializes with ``verbose=True``. 'origin': prototype['origin'] } }) - if verbose: - protoLen = len(self.prototypeLibrary) - if protoLen == 0: - print(f"{Style.DIM}No prototypes were loaded into the prototype library.{Style.RESET_ALL}") + + protoLen = len(self.prototypeLibrary) + if protoLen == 0: + self.log(f"{Style.DIM}No prototypes were loaded into the prototype library.{Style.RESET_ALL}") + else: + if self.verbose: + self.log(f"Loaded {Fore.GREEN}{protoLen} prototypes {Style.RESET_ALL}into the library: {Fore.BLUE}{', '.join(natsort.natsorted(self.prototypeLibrary.keys()))}{Style.RESET_ALL}") else: - print(f"Loaded {Fore.GREEN}{protoLen} prototypes {Style.RESET_ALL}into the library.") + self.log(f"Loaded {Fore.GREEN}{protoLen} prototypes {Style.RESET_ALL}into the library.") def appendPrototypeLibrary(self, customPath: str) -> None: From 28fc259cfcc4349d33dda832fdd300a79a77e037 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:52:12 -0400 Subject: [PATCH 4/7] (core) improved `Calcualtor` initialization printout behavior --- pysipfenn/core/pysipfenn.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pysipfenn/core/pysipfenn.py b/pysipfenn/core/pysipfenn.py index a3675e4..cf6ca70 100644 --- a/pysipfenn/core/pysipfenn.py +++ b/pysipfenn/core/pysipfenn.py @@ -88,17 +88,17 @@ def __init__(self, self.printOut = printOut self.printOutLog = "" - self.log('\n********* Initializing pySIPFENN Calculator **********') + if self.verbose: + self.log('\n********* Initializing pySIPFENN Calculator **********') # dictionary with all model information with resources.files('pysipfenn.modelsSIPFENN').joinpath('models.json').open('r') as f: - if verbose: - print(f'Loading model definitions from: {Fore.BLUE}{f.name}{Style.RESET_ALL}') + self.log(f'Loading model definitions from: {Fore.BLUE}{f.name}{Style.RESET_ALL}') self.models = json.load(f) # networks list self.network_list = list(self.models.keys()) - if verbose: - print(f'Found {Fore.BLUE}{len(self.network_list)} network definitions in models.json{Style.RESET_ALL}') + if self.verbose: + self.log(f'Found {Fore.BLUE}{len(self.network_list)} network definitions in models.json{Style.RESET_ALL}') # network names self.network_list_names = [self.models[net]['name'] for net in self.network_list] self.network_list_available = [] @@ -106,13 +106,13 @@ def __init__(self, self.loadedModels = {} if autoLoad: - print(f'Loading all available models ({Fore.BLUE}autoLoad=True{Style.RESET_ALL})') + self.log(f'Loading all available models ({Fore.BLUE}autoLoad=True{Style.RESET_ALL})') self.loadModels() else: - print(f'Skipping model loading ({Fore.BLUE}autoLoad=False{Style.RESET_ALL})') + self.log(f'Skipping model loading ({Fore.BLUE}autoLoad=False{Style.RESET_ALL})') self.prototypeLibrary = {} - self.parsePrototypeLibrary(verbose=verbose) + self.parsePrototypeLibrary() self.toRun = [] self.descriptorData = [] @@ -121,8 +121,8 @@ def __init__(self, 'RSS': [] } self.inputFiles = [] - if verbose: - print(f'{Fore.GREEN}********** Successfully Initialized **********{Style.RESET_ALL}') + if self.verbose: + self.log(f'{Fore.GREEN}********** Successfully Initialized **********{Style.RESET_ALL}') def __str__(self): """Prints the status of the ``Calculator`` object.""" From e97998d4d1db6095c99807aae9da9bf9d77abb8a Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:53:19 -0400 Subject: [PATCH 5/7] (core) improved `updateModelAvailability` printout behavior --- pysipfenn/core/pysipfenn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pysipfenn/core/pysipfenn.py b/pysipfenn/core/pysipfenn.py index cf6ca70..80f106d 100644 --- a/pysipfenn/core/pysipfenn.py +++ b/pysipfenn/core/pysipfenn.py @@ -246,16 +246,16 @@ def updateModelAvailability(self) -> None: if all_files.__contains__(net + '.onnx'): detectedNets.append(net) try: - print(f"{Fore.GREEN}✔ {net:<45} | {netName}{Style.RESET_ALL}") + self.log(f"{Fore.GREEN}✔ {net:<45} | {netName}{Style.RESET_ALL}") except UnicodeEncodeError: # Fallback to ASCII characters if Unicode encoding fails - print(f"{Fore.GREEN}+ {net:<45} | {netName}{Style.RESET_ALL}") + self.log(f"{Fore.GREEN}+ {net:<45} | {netName}{Style.RESET_ALL}") else: try: - print(f"{Style.DIM}✘ {net:<45} | {netName}{Style.RESET_ALL}") + self.log(f"{Style.DIM}✘ {net:<45} | {netName}{Style.RESET_ALL}") except UnicodeEncodeError: # Fallback to ASCII characters if Unicode encoding fails - print(f"{Fore.DIM}x {net:<45} | {netName}{Style.RESET_ALL}") + self.log(f"{Fore.DIM}x {net:<45} | {netName}{Style.RESET_ALL}") self.network_list_available = detectedNets def downloadModels(self, network: str = 'all') -> None: From c04719857094fb6f51f768aea2b5812da03477b5 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:31:14 -0400 Subject: [PATCH 6/7] (core) small adjustment in test to match recent changes --- pysipfenn/tests/test_Core_prototypeLibrary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysipfenn/tests/test_Core_prototypeLibrary.py b/pysipfenn/tests/test_Core_prototypeLibrary.py index a49d0dd..231a453 100644 --- a/pysipfenn/tests/test_Core_prototypeLibrary.py +++ b/pysipfenn/tests/test_Core_prototypeLibrary.py @@ -51,7 +51,7 @@ def test_customPrototypeLoad(self): library and stay there.""" with resources.files('pysipfenn').joinpath('tests/testCaseFiles/prototypeLibrary-custom.yaml') as f: - self.c.parsePrototypeLibrary(customPath=f, verbose=True, printCustomLibrary=True) + self.c.parsePrototypeLibrary(customPath=f, printCustomLibrary=True) with self.subTest(msg="Custom prototype present with correct parse"): self.assertTrue("NicePhase" in self.c.prototypeLibrary) From 332b4a33fbf4ed774b39a9225d1a897ffed08fd4 Mon Sep 17 00:00:00 2001 From: "Adam M. Krajewski" <54290107+amkrajewski@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:34:23 -0400 Subject: [PATCH 7/7] (core) small adjustment in test to prevent Windows issues --- pysipfenn/descriptorDefinitions/KS2022_randomSolutions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysipfenn/descriptorDefinitions/KS2022_randomSolutions.py b/pysipfenn/descriptorDefinitions/KS2022_randomSolutions.py index 4306fb2..f6e483d 100755 --- a/pysipfenn/descriptorDefinitions/KS2022_randomSolutions.py +++ b/pysipfenn/descriptorDefinitions/KS2022_randomSolutions.py @@ -519,7 +519,7 @@ def profile(test: str = 'FCC', the descriptor and a dictionary containing the convergence history, or None. In either case, the descriptor will be persisted in `f'TestResult_KS2022_randomSolution_{test}_{nIterations}iter.csv'` file. """ - c = pysipfenn.Calculator(autoLoad=False) + c = pysipfenn.Calculator(autoLoad=False, printOut=False) try: s = c.prototypeLibrary[test]['structure']