From 18fb74a516df588dd95e21f91a5a19bf9a7a65da Mon Sep 17 00:00:00 2001 From: anaik Date: Tue, 6 Jun 2023 14:15:16 +0200 Subject: [PATCH 01/15] first commit for extending lobsterenv for coop/cobi --- pymatgen/io/lobster/lobsterenv.py | 76 ++++++++++++------ pymatgen/io/lobster/tests/test_lobsterenv.py | 45 ++++++++--- .../environments/ICOBILIST.lobster.mp_470.gz | Bin 0 -> 91655 bytes test_files/cohp/environments/POSCAR.mp_470.gz | Bin 0 -> 151 bytes 4 files changed, 85 insertions(+), 36 deletions(-) create mode 100755 test_files/cohp/environments/ICOBILIST.lobster.mp_470.gz create mode 100755 test_files/cohp/environments/POSCAR.mp_470.gz diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index cd801efcdc5..c21770e9629 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -44,6 +44,7 @@ class LobsterNeighbors(NearNeighbors): def __init__( self, are_coops=False, + are_cobis=False, filename_ICOHP=None, valences=None, limits=None, @@ -64,11 +65,11 @@ def __init__( """ Args: - are_coops: (bool) if True, the file is a ICOOPLIST.lobster and not a ICOHPLIST.lobster; only tested for - ICOHPLIST.lobster so far - filename_ICOHP: (str) Path to ICOHPLIST.lobster + are_coops: (bool) if True, the file is a ICOOPLIST.lobster and not a ICOHPLIST.lobster; + are_cobis: (Bool) if True, the file is a ICOBILIST.lobster and not a ICOHPLIST.lobster + filename_ICOHP: (str) Path to ICOHPLIST.lobster/ICOOPLIST.lobster/ICOBILIST.lobster valences: (list of integers/floats) gives valence/charge for each element - limits: limit to decide which ICOHPs should be considered + limits: list of limits [lower, upper] to decide which ICOHPs/ICOBI/ICOOP should be considered structure: (Structure Object) typically constructed by: Structure.from_file("POSCAR") (Structure object from pymatgen.core.structure) additional_condition: Additional condition that decides which kind of bonds will be considered @@ -82,7 +83,7 @@ def __init__( only_bonds_to: (list of str) will only consider bonds to certain elements (e.g. ["O"] for oxygen) perc_strength_ICOHP: if no limits are given, this will decide which icohps will still be considered ( relative to - the strongest ICOHP) + the strongest ICOHP/ICOOP/ICOBI) valences_from_charges: if True and path to CHARGE.lobster is provided, will use Lobster charges ( Mulliken) instead of valences filename_CHARGE: (str) Path to Charge.lobster @@ -97,13 +98,14 @@ def __init__( id_blist_sg2: (str) Identity of data in filename_blist_sg2, e.g., "icoop" or "icobi" """ - self.ICOHP = Icohplist(are_coops=are_coops, filename=filename_ICOHP) + self.ICOHP = Icohplist(are_coops=are_coops, are_cobis=are_cobis, filename=filename_ICOHP) self.Icohpcollection = self.ICOHP.icohpcollection self.structure = structure self.limits = limits self.only_bonds_to = only_bonds_to self.adapt_extremum_to_add_cond = adapt_extremum_to_add_cond self.are_coops = are_coops + self.are_cobis = are_cobis self.add_additional_data_sg = add_additional_data_sg self.filename_blist_sg1 = filename_blist_sg1 self.filename_blist_sg2 = filename_blist_sg2 @@ -141,9 +143,6 @@ def __init__( are_cobis=are_cobis_id2, ) - if are_coops: - raise ValueError("Algorithm only works correctly for ICOHPLIST.lobster") - # will check if the additional condition is correctly delivered if additional_condition in range(0, 7): self.additional_condition = additional_condition @@ -355,7 +354,8 @@ def get_light_structure_environment(self, only_cation_environments=False, only_i def get_info_icohps_to_neighbors(self, isites=None, onlycation_isites=True): """ - this method Return information of cohps of neighbors + this method Return information of cohps/coops/icobis of neighbors depending on input bond list file + (could be ICOOPLIST.lobster/ICOHPLIST.lobster/ICOBILIST.lobster) Args: isites: list of site ids, if isite==None, all isites will be used to add the icohps of the neighbors @@ -363,8 +363,8 @@ def get_info_icohps_to_neighbors(self, isites=None, onlycation_isites=True): Returns: - sum of icohps of neighbors to certain sites [given by the id in structure], number of bonds to this site, - labels (from ICOHPLIST) for + sum of icohps/icoops/icobis of neighbors to certain sites [given by the id in structure], number of bonds to this site, + labels (from ICOHPLIST/ICOOPLIST/ICOBILIST) for these bonds [the latter is useful for plotting summed COHP plots], list of the central isite for each label @@ -1134,10 +1134,10 @@ def _get_limit_from_extremum( Args: icohpcollection: icohpcollection object - percentage: will determine which ICOHPs will be considered (only 0.15 from the maximum value) + percentage: will determine which ICOHPs/ICOOP/ICOBI will be considered (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - Returns: [-100000, min(max_icohp*0.15,-0.1)] + Returns: [-100000, min(max_icohp*0.15,-0.1)] / [max_icohp*0.15,100000] """ # TODO: make it work for COOPs if not adapt_extremum_to_add_cond or additional_condition == 0: @@ -1154,7 +1154,10 @@ def _get_limit_from_extremum( if (val1 < 0.0 < val2) or (val2 < 0.0 < val1): list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage elif additional_condition == 2: # NO_ELEMENT_TO_SAME_ELEMENT_BONDS @@ -1162,7 +1165,11 @@ def _get_limit_from_extremum( for value in icohpcollection._icohplist.values(): if value._atom1.rstrip("0123456789") != value._atom2.rstrip("0123456789"): list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage + + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage elif additional_condition == 3: # ONLY_ANION_CATION_BONDS_AND_NO_ELEMENT_TO_SAME_ELEMENT_BONDS = 3 @@ -1179,13 +1186,23 @@ def _get_limit_from_extremum( and value._atom1.rstrip("0123456789") != value._atom2.rstrip("0123456789") ): list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage + + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage + elif additional_condition == 4: list_icohps = [] for value in icohpcollection._icohplist.values(): if value._atom1.rstrip("0123456789") == "O" or value._atom2.rstrip("0123456789") == "O": list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage + + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage + elif additional_condition == 5: # DO_NOT_CONSIDER_ANION_CATION_BONDS=5 list_icohps = [] @@ -1197,7 +1214,11 @@ def _get_limit_from_extremum( if (val1 > 0.0 and val2 > 0.0) or (val1 < 0.0 and val2 < 0.0): list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage + + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage elif additional_condition == 6: # ONLY_CATION_CATION_BONDS=6 @@ -1210,13 +1231,18 @@ def _get_limit_from_extremum( if val1 > 0.0 and val2 > 0.0: list_icohps.append(value.summed_icohp) - extremum_based = min(list_icohps) * percentage - # if not self.are_coops: - max_here = min(extremum_based, -0.1) - return -100000, max_here - # else: - # return extremum_based, 100000 + if not self.are_coops and not self.are_cobis: + extremum_based = min(list_icohps) * percentage + else: + extremum_based = max(list_icohps) * percentage + + if not self.are_coops and not self.are_cobis: + max_here = min(extremum_based, -0.1) + return -100000, max_here + if self.are_coops or self.are_cobis: + max_here = extremum_based + return max_here, 100000 class LobsterLightStructureEnvironments(LightStructureEnvironments): diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index 6972a3bb925..c6e18e380c2 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -124,6 +124,20 @@ def setUp(self): structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_353.gz")), additional_condition=6, ) + # coop / cobi + self.chemenvlobster1_coop_NaCl = LobsterNeighbors( + are_coops=True, + filename_ICOHP=os.path.join(test_dir_env, "ICOOPLIST.lobster.NaCl.gz"), + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), + additional_condition=1, + ) + + self.chemenvlobster1_cobi_mp470 = LobsterNeighbors( + are_coops=True, + filename_ICOHP=os.path.join(test_dir_env, "ICOBILIST.lobster.mp_470.gz"), + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_470.gz")), + additional_condition=1, + ) # TODO: use charge instead of valence self.chemenvlobster1_charges = LobsterNeighbors( @@ -217,17 +231,6 @@ def setUp(self): adapt_extremum_to_add_cond=True, ) - def test_use_of_coop(self): - with pytest.raises(ValueError): - _ = LobsterNeighbors( - are_coops=True, - filename_ICOHP=os.path.join(test_dir_env, "ICOHPLIST.lobster.mp_353.gz"), - structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_353.gz")), - valences_from_charges=True, - filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp-353.gz"), - additional_condition=1, - ) - def test_cation_anion_mode_without_ions(self): with pytest.raises(ValueError) as exc: _ = LobsterNeighbors( @@ -444,6 +447,26 @@ def test_get_nn_info(self): == 2 ) + assert ( + len( + self.chemenvlobster1_coop_NaCl.get_nn( + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), + n=0, + ) + ) + == 6 + ) + + assert ( + len( + self.chemenvlobster1_cobi_mp470.get_nn( + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_470.gz")), + n=3, + ) + ) + == 3 + ) + # NO_ELEMENT_TO_SAME_ELEMENT_BONDS = 2 assert ( len( diff --git a/test_files/cohp/environments/ICOBILIST.lobster.mp_470.gz b/test_files/cohp/environments/ICOBILIST.lobster.mp_470.gz new file mode 100755 index 0000000000000000000000000000000000000000..8f6a116d2146288cd10295ca6adbb4cac0f5f19e GIT binary patch literal 91655 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 F001hYL_h!l literal 0 HcmV?d00001 From eec956cb8bdb39b4dbae9a7aa5f4927165390207 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:19:51 +0000 Subject: [PATCH 02/15] pre-commit auto-fixes --- pymatgen/io/lobster/lobsterenv.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index c21770e9629..191ebb2c778 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1243,6 +1243,7 @@ def _get_limit_from_extremum( if self.are_coops or self.are_cobis: max_here = extremum_based return max_here, 100000 + return None class LobsterLightStructureEnvironments(LightStructureEnvironments): From 2ea8793a086b90b2b721cf92d030dc3120b3503c Mon Sep 17 00:00:00 2001 From: anaik Date: Tue, 6 Jun 2023 16:32:34 +0200 Subject: [PATCH 03/15] hardcoded limit set as parameter --- pymatgen/io/lobster/lobsterenv.py | 29 +++++++++++++++----- pymatgen/io/lobster/tests/test_lobsterenv.py | 1 + 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index c21770e9629..5dd80d08aef 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -52,6 +52,7 @@ def __init__( additional_condition=0, only_bonds_to=None, perc_strength_ICOHP=0.15, + noise_cutoff=0.1, valences_from_charges=False, filename_CHARGE=None, which_charge="Mulliken", @@ -109,6 +110,7 @@ def __init__( self.add_additional_data_sg = add_additional_data_sg self.filename_blist_sg1 = filename_blist_sg1 self.filename_blist_sg2 = filename_blist_sg2 + self.noise_cutoff = noise_cutoff allowed_arguments = ["icoop", "icobi"] if id_blist_sg1.lower() not in allowed_arguments or id_blist_sg2.lower() not in allowed_arguments: @@ -363,7 +365,8 @@ def get_info_icohps_to_neighbors(self, isites=None, onlycation_isites=True): Returns: - sum of icohps/icoops/icobis of neighbors to certain sites [given by the id in structure], number of bonds to this site, + sum of icohps/icoops/icobis of neighbors to certain sites [given by the id in structure], + number of bonds to this site, labels (from ICOHPLIST/ICOOPLIST/ICOBILIST) for these bonds [the latter is useful for plotting summed COHP plots], @@ -431,7 +434,7 @@ def plot_cohps_of_neighbors( # include COHPPlotter and plot a sum of these COHPs # might include option to add Spin channels # implement only_bonds_to - cp = CohpPlotter() + cp = CohpPlotter(are_cobis=self.are_cobis, are_coops=self.are_coops) plotlabel, summed_cohp = self.get_info_cohps_to_neighbors( path_to_COHPCAR, @@ -493,7 +496,13 @@ def get_info_cohps_to_neighbors( self.structure.to(filename=path, fmt="POSCAR") if not hasattr(self, "completecohp"): - self.completecohp = CompleteCohp.from_file(fmt="LOBSTER", filename=path_to_COHPCAR, structure_file=path) + self.completecohp = CompleteCohp.from_file( + fmt="LOBSTER", + filename=path_to_COHPCAR, + structure_file=path, + are_coops=self.are_coops, + are_cobis=self.are_cobis, + ) # will check that the number of bonds in ICOHPLIST and COHPCAR are identical # further checks could be implemented @@ -1238,11 +1247,17 @@ def _get_limit_from_extremum( extremum_based = max(list_icohps) * percentage if not self.are_coops and not self.are_cobis: - max_here = min(extremum_based, -0.1) - return -100000, max_here + if self.noise_cutoff is not None: + max_here = min(extremum_based, -self.noise_cutoff) + else: + max_here = extremum_based + return -float("inf"), max_here if self.are_coops or self.are_cobis: - max_here = extremum_based - return max_here, 100000 + if self.noise_cutoff is not None: + min_here = max(extremum_based, self.noise_cutoff) + else: + min_here = extremum_based + return min_here, float("inf") class LobsterLightStructureEnvironments(LightStructureEnvironments): diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index c6e18e380c2..11646450a91 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -130,6 +130,7 @@ def setUp(self): filename_ICOHP=os.path.join(test_dir_env, "ICOOPLIST.lobster.NaCl.gz"), structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), additional_condition=1, + noise_cutoff=None, ) self.chemenvlobster1_cobi_mp470 = LobsterNeighbors( From 66a7444bf4b05bcfceab8bb666c9425975679c6e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 14:40:23 +0000 Subject: [PATCH 04/15] pre-commit auto-fixes --- pymatgen/io/lobster/lobsterenv.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 037ca2709c5..e68c4106f52 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1247,16 +1247,10 @@ def _get_limit_from_extremum( extremum_based = max(list_icohps) * percentage if not self.are_coops and not self.are_cobis: - if self.noise_cutoff is not None: - max_here = min(extremum_based, -self.noise_cutoff) - else: - max_here = extremum_based + max_here = min(extremum_based, -self.noise_cutoff) if self.noise_cutoff is not None else extremum_based return -float("inf"), max_here if self.are_coops or self.are_cobis: - if self.noise_cutoff is not None: - min_here = max(extremum_based, self.noise_cutoff) - else: - min_here = extremum_based + min_here = max(extremum_based, self.noise_cutoff) if self.noise_cutoff is not None else extremum_based return min_here, float("inf") return None From e12ad53cef41669b40ed3254e74ef6acffdada38 Mon Sep 17 00:00:00 2001 From: anaik Date: Tue, 6 Jun 2023 16:50:28 +0200 Subject: [PATCH 05/15] update docstring of _get_limit_from_extremum --- pymatgen/io/lobster/lobsterenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 037ca2709c5..e3a84d711e0 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1146,7 +1146,7 @@ def _get_limit_from_extremum( percentage: will determine which ICOHPs/ICOOP/ICOBI will be considered (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - Returns: [-100000, min(max_icohp*0.15,-0.1)] / [max_icohp*0.15,100000] + Returns: [-inf, min(max_icohp*0.15,noise_cutoff)] / [min(max_icohp*0.15, noise_cutoff),inf] """ # TODO: make it work for COOPs if not adapt_extremum_to_add_cond or additional_condition == 0: From 52925bb5c5e1523c2ab2c02671456172d0a72621 Mon Sep 17 00:00:00 2001 From: anaik Date: Tue, 6 Jun 2023 16:52:16 +0200 Subject: [PATCH 06/15] fix typo in docstring --- pymatgen/io/lobster/lobsterenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 8aefd812744..f6c154b57f6 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1146,7 +1146,7 @@ def _get_limit_from_extremum( percentage: will determine which ICOHPs/ICOOP/ICOBI will be considered (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - Returns: [-inf, min(max_icohp*0.15,noise_cutoff)] / [min(max_icohp*0.15, noise_cutoff),inf] + Returns: [-inf, min(max_icohp*0.15,noise_cutoff)] / [max(max_icohp*0.15, noise_cutoff),inf] """ # TODO: make it work for COOPs if not adapt_extremum_to_add_cond or additional_condition == 0: From 456ecc7cd5802caf9dbabe6f558242f1ec8594fa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 07:43:40 +0000 Subject: [PATCH 07/15] pre-commit auto-fixes --- pymatgen/io/lobster/lobsterenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 186c42f2c7c..5729819a29c 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1135,7 +1135,7 @@ def _get_limit_from_extremum( percentage: will determine which ICOHPs/ICOOP/ICOBI will be considered (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - + Returns: [-inf, min(max_icohp*0.15,noise_cutoff)] / [max(max_icohp*0.15, noise_cutoff),inf] """ # TODO: make it work for COOPs/COBIs From dc3edb0fefff8ea5fe9df3a4174e209c9c2d6bd7 Mon Sep 17 00:00:00 2001 From: anaik Date: Fri, 30 Jun 2023 11:45:29 +0200 Subject: [PATCH 08/15] add tests for noisecutoff, update docstring --- pymatgen/io/lobster/lobsterenv.py | 2 +- pymatgen/io/lobster/tests/test_lobsterenv.py | 38 ++++++++++++++++++ .../environments/CHARGE.lobster.mp_632319.gz | Bin 0 -> 164 bytes .../ICOHPLIST.lobster.mp_632319.gz | Bin 0 -> 6048 bytes .../cohp/environments/POSCAR.mp_632319.gz | Bin 0 -> 106 bytes 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100755 test_files/cohp/environments/CHARGE.lobster.mp_632319.gz create mode 100755 test_files/cohp/environments/ICOHPLIST.lobster.mp_632319.gz create mode 100755 test_files/cohp/environments/POSCAR.mp_632319.gz diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 3683e2cb943..3e164138e0c 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1147,7 +1147,7 @@ def _get_limit_from_extremum( adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - Returns: [-inf, min(max_icohp*0.15,noise_cutoff)] / [max(max_icohp*0.15, noise_cutoff),inf] + Returns: [-inf, min(max_icohp*0.15,-noise_cutoff)] / [max(max_icohp*0.15, noise_cutoff),inf] """ # TODO: make it work for COOPs/COBIs if not adapt_extremum_to_add_cond or additional_condition == 0: diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index 88cfb7dd529..6c5938723d2 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -150,6 +150,26 @@ def setUp(self): filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp-353.gz"), additional_condition=1, ) + self.chemenvlobster1_charges_noisecutoff = LobsterNeighbors( + are_coops=False, + filename_ICOHP=os.path.join(test_dir_env, "ICOHPLIST.lobster.mp_632319.gz"), + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_632319.gz")), + valences_from_charges=True, + filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp_632319.gz"), + additional_condition=1, + perc_strength_ICOHP=0.05, + noise_cutoff=0.1, + ) + self.chemenvlobster1_charges_wo_noisecutoff = LobsterNeighbors( + are_coops=False, + filename_ICOHP=os.path.join(test_dir_env, "ICOHPLIST.lobster.mp_632319.gz"), + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_632319.gz")), + valences_from_charges=True, + filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp_632319.gz"), + additional_condition=1, + perc_strength_ICOHP=0.05, + noise_cutoff=None, + ) self.chemenvlobster1_charges_loewdin = LobsterNeighbors( are_coops=False, filename_ICOHP=os.path.join(test_dir_env, "ICOHPLIST.lobster.mp_353.gz"), @@ -332,6 +352,24 @@ def test_get_nn_info(self): ) == 2 ) + assert ( + len( + self.chemenvlobster1_charges_noisecutoff.get_nn( + structure=self.chemenvlobster1_charges_noisecutoff.structure, + n=1, + ) + ) + == 0 + ) + assert ( + len( + self.chemenvlobster1_charges_wo_noisecutoff.get_nn( + structure=self.chemenvlobster1_charges_wo_noisecutoff.structure, + n=1, + ) + ) + == 8 + ) # NO_ELEMENT_TO_SAME_ELEMENT_BONDS = 2 assert ( len( diff --git a/test_files/cohp/environments/CHARGE.lobster.mp_632319.gz b/test_files/cohp/environments/CHARGE.lobster.mp_632319.gz new file mode 100755 index 0000000000000000000000000000000000000000..2e8b3834b52ff3e91da03cf9d6c32a544baf420b GIT binary patch literal 164 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 M{gaKq|0FH-U-Bvb)c^nh literal 0 HcmV?d00001 diff --git a/test_files/cohp/environments/POSCAR.mp_632319.gz b/test_files/cohp/environments/POSCAR.mp_632319.gz new file mode 100755 index 0000000000000000000000000000000000000000..7bbc6a50c774929974bedc1e1c9e2bac5b9be86d GIT binary patch literal 106 zcmV-w0G0nAiwFqAov&j8|4>g;LqSpib1pVi@G#^u)HC2xP*5<|voN(VGcdP=0Slm@ zf`Og^8o(~fg;OoD=5mo>8+LQKoQoAaxC|8xxl%HVQj<$aH4%%bb1}paQ>@B~6!qW& M08gR^ Date: Fri, 30 Jun 2023 09:46:48 +0000 Subject: [PATCH 09/15] pre-commit auto-fixes --- pymatgen/io/lobster/tests/test_lobsterenv.py | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index 6c5938723d2..56db22349f7 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -353,22 +353,22 @@ def test_get_nn_info(self): == 2 ) assert ( - len( - self.chemenvlobster1_charges_noisecutoff.get_nn( - structure=self.chemenvlobster1_charges_noisecutoff.structure, - n=1, - ) + len( + self.chemenvlobster1_charges_noisecutoff.get_nn( + structure=self.chemenvlobster1_charges_noisecutoff.structure, + n=1, ) - == 0 + ) + == 0 ) assert ( - len( - self.chemenvlobster1_charges_wo_noisecutoff.get_nn( - structure=self.chemenvlobster1_charges_wo_noisecutoff.structure, - n=1, - ) + len( + self.chemenvlobster1_charges_wo_noisecutoff.get_nn( + structure=self.chemenvlobster1_charges_wo_noisecutoff.structure, + n=1, ) - == 8 + ) + == 8 ) # NO_ELEMENT_TO_SAME_ELEMENT_BONDS = 2 assert ( From 4310eece236757e20f29354add7e5f98b4609a51 Mon Sep 17 00:00:00 2001 From: anaik Date: Fri, 30 Jun 2023 12:33:29 +0200 Subject: [PATCH 10/15] update doc strings --- pymatgen/io/lobster/lobsterenv.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 3e164138e0c..bd67366054a 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -78,13 +78,13 @@ def __init__( """ Args: - filename_ICOHP: (str) Path to ICOHPLIST.lobster/ICOOPLIST.lobster/ICOBILIST.lobster + filename_ICOHP: (str) Path to ICOHPLIST.lobster or ICOOPLIST.lobster or ICOBILIST.lobster structure: (Structure) typically constructed by Structure.from_file("POSCAR") are_coops: (bool) if True, the file is a ICOOPLIST.lobster and not a ICOHPLIST.lobster; only tested for ICOHPLIST.lobster so far are_cobis: (bool) if True, the file is a ICOBILIST.lobster and not a ICOHPLIST.lobster valences: (list[int | float]): gives valence/charge for each element - limits (tuple[float, float] | None): limit to decide which ICOHPs should be considered + limits (tuple[float, float] | None): limit to decide which ICOHPs (ICOOP or ICOBI) should be considered additional_condition (int): Additional condition that decides which kind of bonds will be considered NO_ADDITIONAL_CONDITION = 0 ONLY_ANION_CATION_BONDS = 1 @@ -96,7 +96,7 @@ def __init__( only_bonds_to: (list[str]) will only consider bonds to certain elements (e.g. ["O"] for oxygen) perc_strength_ICOHP: if no limits are given, this will decide which icohps will still be considered ( relative to - the strongest ICOHP/ICOOP/ICOBI) + the strongest ICOHP (ICOOP or ICOBI) noise_cutoff: if provided hardcodes the lower limit of icohps considered valences_from_charges: if True and path to CHARGE.lobster is provided, will use Lobster charges ( Mulliken) instead of valences @@ -367,7 +367,7 @@ def get_info_icohps_to_neighbors(self, isites=None, onlycation_isites=True): """ This method returns information on the icohps of neighbors for certain sites as identified by their site id. This is useful for plotting the relevant cohps of a site in the structure. - (could be ICOOPLIST.lobster/ICOHPLIST.lobster/ICOBILIST.lobster) + (could be ICOOPLIST.lobster or ICOHPLIST.lobster or ICOBILIST.lobster) Args: isites: list of site ids. If isite==None, all isites will be used to add the icohps of the neighbors @@ -418,7 +418,7 @@ def plot_cohps_of_neighbors( integrated=False, ): """ - Will plot summed cohps (please be careful in the spin polarized case (plots might overlap (exactly!)). + Will plot summed cohps or cobis or coops (please be careful in the spin polarized case (plots might overlap (exactly!)). Args: isites: list of site ids, if isite==[], all isites will be used to add the icohps of the neighbors @@ -432,7 +432,7 @@ def plot_cohps_of_neighbors( integrated: bool, if true will show integrated cohp instead of cohp Returns: - plt of the cohps + plt of the cohps or coops or cobis """ # include COHPPlotter and plot a sum of these COHPs # might include option to add Spin channels @@ -468,19 +468,19 @@ def get_info_cohps_to_neighbors( summed_spin_channels=False, ): """ - Return info about the cohps as a summed cohp object and a label + Return info about the cohps (coops or cobis) as a summed cohp object and a label from all sites mentioned in isites with neighbors. Args: - path_to_COHPCAR: str, path to COHPCAR + path_to_COHPCAR: str, path to COHPCAR or COOPCAR or COBICAR isites: list of int that indicate the number of the site only_bonds_to: list of str, e.g. ["O"] to only show cohps of anything to oxygen onlycation_isites: if isites=None, only cation sites will be returned per_bond: will normalize per bond summed_spin_channels: will sum all spin channels - Returns: label for cohp (str), CompleteCohp object which describes all cohps of the sites as given by isites - and the other parameters + Returns: label for cohp (str), CompleteCohp object which describes all cohps (coops or cobis) of the sites + as given by isites and the other parameters """ # TODO: add options for orbital-resolved cohps ( @@ -1143,7 +1143,7 @@ def _get_limit_from_extremum( Args: icohpcollection: icohpcollection object - percentage: will determine which ICOHPs/ICOOP/ICOBI will be considered (only 0.15 from the maximum value) + percentage: will determine which ICOHPs or ICOOP or ICOBI will be considered (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant From 382a02cdf9519d08cf3cae6f15a778aaf4f9eee8 Mon Sep 17 00:00:00 2001 From: anaik Date: Fri, 30 Jun 2023 12:41:30 +0200 Subject: [PATCH 11/15] fix linting --- pymatgen/io/lobster/lobsterenv.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index bd67366054a..b18e29472a6 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -418,7 +418,8 @@ def plot_cohps_of_neighbors( integrated=False, ): """ - Will plot summed cohps or cobis or coops (please be careful in the spin polarized case (plots might overlap (exactly!)). + Will plot summed cohps or cobis or coops + (please be careful in the spin polarized case (plots might overlap (exactly!)). Args: isites: list of site ids, if isite==[], all isites will be used to add the icohps of the neighbors @@ -1143,7 +1144,8 @@ def _get_limit_from_extremum( Args: icohpcollection: icohpcollection object - percentage: will determine which ICOHPs or ICOOP or ICOBI will be considered (only 0.15 from the maximum value) + percentage: will determine which ICOHPs or ICOOP or ICOBI will be considered + (only 0.15 from the maximum value) adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant From 8b2c702087ca86c730fb4d919db0de1cd875f6dc Mon Sep 17 00:00:00 2001 From: anaik Date: Fri, 30 Jun 2023 13:20:52 +0200 Subject: [PATCH 12/15] update doc string --- pymatgen/io/lobster/lobsterenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index b18e29472a6..bd3fd01f410 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1149,7 +1149,7 @@ def _get_limit_from_extremum( adapt_extremum_to_add_cond: should the extrumum be adapted to the additional condition additional_condition: additional condition to determine which bonds are relevant - Returns: [-inf, min(max_icohp*0.15,-noise_cutoff)] / [max(max_icohp*0.15, noise_cutoff),inf] + Returns: [-inf, min(strongest_icohp*0.15,-noise_cutoff)] / [max(strongest_icohp*0.15, noise_cutoff),inf] """ # TODO: make it work for COOPs/COBIs if not adapt_extremum_to_add_cond or additional_condition == 0: From f3869fbf78c45b124f3f68cc73b0284313193775 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:38:42 +0000 Subject: [PATCH 13/15] pre-commit auto-fixes --- pymatgen/io/lobster/tests/test_lobsterenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index 1da806bf856..0704ad77f5f 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -263,7 +263,7 @@ def test_use_of_coop(self): filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp-353.gz"), additional_condition=1, ) - + def test_cation_anion_mode_without_ions(self): with pytest.raises( ValueError, match="Valences cannot be assigned, additional_conditions 1, 3, 5 and 6 will not work" From b2edafd7a398b0dbcfe66a9e41fbd99d9e5c470d Mon Sep 17 00:00:00 2001 From: anaik Date: Wed, 12 Jul 2023 17:28:26 +0200 Subject: [PATCH 14/15] add method to adapt extremum values --- pymatgen/io/lobster/lobsterenv.py | 48 ++++++++++---------- pymatgen/io/lobster/tests/test_lobsterenv.py | 29 +++++++----- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index bd3fd01f410..0ff8c923d53 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1131,6 +1131,22 @@ def _determine_unit_cell(site): return unitcell + def _adapt_extremum_to_add_cond(self, list_icohps, percentage): + """ + Convinicence method for returning the extremum of the given icohps or icoops or icobis list + + Args: + list_icohps: can be a list of icohps or icobis or icobis + + Returns: min value of input list of icohps / max value of input list of icobis or icobis + """ + + which_extr = min if not self.are_coops and not self.are_cobis else max + extremum_based = which_extr(list_icohps) * percentage + + return extremum_based + + def _get_limit_from_extremum( self, icohpcollection, @@ -1151,7 +1167,7 @@ def _get_limit_from_extremum( Returns: [-inf, min(strongest_icohp*0.15,-noise_cutoff)] / [max(strongest_icohp*0.15, noise_cutoff),inf] """ - # TODO: make it work for COOPs/COBIs + if not adapt_extremum_to_add_cond or additional_condition == 0: extremum_based = icohpcollection.extremum_icohpvalue(summed_spin_channels=True) * percentage elif additional_condition == 1: @@ -1166,10 +1182,7 @@ def _get_limit_from_extremum( if (val1 < 0.0 < val2) or (val2 < 0.0 < val1): list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) elif additional_condition == 2: # NO_ELEMENT_TO_SAME_ELEMENT_BONDS @@ -1178,10 +1191,7 @@ def _get_limit_from_extremum( if value._atom1.rstrip("0123456789") != value._atom2.rstrip("0123456789"): list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) elif additional_condition == 3: # ONLY_ANION_CATION_BONDS_AND_NO_ELEMENT_TO_SAME_ELEMENT_BONDS = 3 @@ -1199,10 +1209,7 @@ def _get_limit_from_extremum( ): list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) elif additional_condition == 4: list_icohps = [] @@ -1210,10 +1217,7 @@ def _get_limit_from_extremum( if value._atom1.rstrip("0123456789") == "O" or value._atom2.rstrip("0123456789") == "O": list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) elif additional_condition == 5: # DO_NOT_CONSIDER_ANION_CATION_BONDS=5 @@ -1227,10 +1231,7 @@ def _get_limit_from_extremum( if (val1 > 0.0 and val2 > 0.0) or (val1 < 0.0 and val2 < 0.0): list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) elif additional_condition == 6: # ONLY_CATION_CATION_BONDS=6 @@ -1244,10 +1245,7 @@ def _get_limit_from_extremum( if val1 > 0.0 and val2 > 0.0: list_icohps.append(value.summed_icohp) - if not self.are_coops and not self.are_cobis: - extremum_based = min(list_icohps) * percentage - else: - extremum_based = max(list_icohps) * percentage + extremum_based = self._adapt_extremum_to_add_cond(list_icohps, percentage) if not self.are_coops and not self.are_cobis: max_here = min(extremum_based, -self.noise_cutoff) if self.noise_cutoff is not None else extremum_based diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index 0704ad77f5f..fff1c116758 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -134,6 +134,14 @@ def setUp(self): noise_cutoff=None, ) + self.chemenvlobster1_cobi_NaCl = LobsterNeighbors( + are_coops=True, + filename_ICOHP=os.path.join(test_dir_env, "ICOBILIST.lobster.NaCl.gz"), + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), + additional_condition=1, + noise_cutoff=None, + ) + self.chemenvlobster1_cobi_mp470 = LobsterNeighbors( are_coops=True, filename_ICOHP=os.path.join(test_dir_env, "ICOBILIST.lobster.mp_470.gz"), @@ -253,17 +261,6 @@ def setUp(self): adapt_extremum_to_add_cond=True, ) - def test_use_of_coop(self): - with pytest.raises(ValueError, match="Algorithm only works correctly for ICOHPLIST.lobster"): - _ = LobsterNeighbors( - are_coops=True, - filename_ICOHP=os.path.join(test_dir_env, "ICOHPLIST.lobster.mp_353.gz"), - structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.mp_353.gz")), - valences_from_charges=True, - filename_CHARGE=os.path.join(test_dir_env, "CHARGE.lobster.mp-353.gz"), - additional_condition=1, - ) - def test_cation_anion_mode_without_ions(self): with pytest.raises( ValueError, match="Valences cannot be assigned, additional_conditions 1, 3, 5 and 6 will not work" @@ -516,6 +513,16 @@ def test_get_nn_info(self): == 6 ) + assert ( + len( + self.chemenvlobster1_cobi_NaCl.get_nn( + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), + n=0, + ) + ) + == 6 + ) + assert ( len( self.chemenvlobster1_cobi_mp470.get_nn( From fe48b37635ffddee8b571d9384e6b7a15fad2dfb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:29:52 +0000 Subject: [PATCH 15/15] pre-commit auto-fixes --- pymatgen/io/lobster/lobsterenv.py | 5 +---- pymatgen/io/lobster/tests/test_lobsterenv.py | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pymatgen/io/lobster/lobsterenv.py b/pymatgen/io/lobster/lobsterenv.py index 0ff8c923d53..d3b201286e2 100644 --- a/pymatgen/io/lobster/lobsterenv.py +++ b/pymatgen/io/lobster/lobsterenv.py @@ -1142,10 +1142,7 @@ def _adapt_extremum_to_add_cond(self, list_icohps, percentage): """ which_extr = min if not self.are_coops and not self.are_cobis else max - extremum_based = which_extr(list_icohps) * percentage - - return extremum_based - + return which_extr(list_icohps) * percentage def _get_limit_from_extremum( self, diff --git a/pymatgen/io/lobster/tests/test_lobsterenv.py b/pymatgen/io/lobster/tests/test_lobsterenv.py index fff1c116758..43654869693 100644 --- a/pymatgen/io/lobster/tests/test_lobsterenv.py +++ b/pymatgen/io/lobster/tests/test_lobsterenv.py @@ -514,13 +514,13 @@ def test_get_nn_info(self): ) assert ( - len( - self.chemenvlobster1_cobi_NaCl.get_nn( - structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), - n=0, - ) + len( + self.chemenvlobster1_cobi_NaCl.get_nn( + structure=Structure.from_file(os.path.join(test_dir_env, "POSCAR.NaCl.gz")), + n=0, ) - == 6 + ) + == 6 ) assert (