Skip to content

Commit 1fd5cfd

Browse files
author
Shyue Ping Ong
committed
Merge branch 'master' of github.com:materialsproject/pymatgen
2 parents b439dac + d757629 commit 1fd5cfd

31 files changed

+210
-297
lines changed

pymatgen/analysis/bond_dissociation.py

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -150,20 +150,13 @@ def fragment_and_process(self, bonds):
150150
# If we still have no good entries, something must have gone wrong with the calculations:
151151
if len(good_entries) == 0:
152152
bb = BabelMolAdaptor.from_molecule_graph(RO_frag)
153-
pbmol = bb.pybel_mol
154-
smiles = pbmol.write("smi").split()[0]
153+
pb_mol = bb.pybel_mol
154+
smiles = pb_mol.write("smi").split()[0]
155155
specie = nx.get_node_attributes(self.mol_graph.graph, "specie")
156156
print(
157-
"Missing ring opening fragment resulting from the breakage of "
158-
+ specie[bonds[0][0]]
159-
+ " "
160-
+ specie[bonds[0][1]]
161-
+ " bond "
162-
+ str(bonds[0][0])
163-
+ " "
164-
+ str(bonds[0][1])
165-
+ " which would yield a molecule with this SMILES string: "
166-
+ smiles
157+
f"Missing ring opening fragment resulting from the breakage of {specie[bonds[0][0]]} "
158+
f"{specie[bonds[0][1]]} bond {bonds[0][0]} {bonds[0][1]} which would yield a "
159+
f"molecule with this SMILES string: {smiles}"
167160
)
168161
elif len(good_entries) == 1:
169162
# If we have only one good entry, format it and add it to the list that will eventually return:
@@ -207,18 +200,18 @@ def fragment_and_process(self, bonds):
207200
# If we're missing some of either, tell the user:
208201
if len(frag1_charges_found) < len(self.expected_charges):
209202
bb = BabelMolAdaptor(frags[0].molecule)
210-
pbmol = bb.pybel_mol
211-
smiles = pbmol.write("smi").split()[0]
203+
pb_mol = bb.pybel_mol
204+
smiles = pb_mol.write("smi").split()[0]
212205
for charge in self.expected_charges:
213206
if charge not in frag1_charges_found:
214-
print("Missing charge " + str(charge) + " for fragment " + smiles)
207+
print(f"Missing charge {charge} for fragment {smiles}")
215208
if len(frag2_charges_found) < len(self.expected_charges):
216209
bb = BabelMolAdaptor(frags[1].molecule)
217-
pbmol = bb.pybel_mol
218-
smiles = pbmol.write("smi").split()[0]
210+
pb_mol = bb.pybel_mol
211+
smiles = pb_mol.write("smi").split()[0]
219212
for charge in self.expected_charges:
220213
if charge not in frag2_charges_found:
221-
print("Missing charge " + str(charge) + " for fragment " + smiles)
214+
print(f"Missing charge {charge} for fragment {smiles}")
222215
# Now we attempt to pair fragments with the right total charge, starting with only fragments with no
223216
# structural change:
224217
for frag1 in frag1_entries[0]: # 0 -> no structural change
@@ -282,21 +275,16 @@ def filter_fragment_entries(self, fragment_entries):
282275
for entry in fragment_entries:
283276
# Check and make sure that PCM dielectric is consistent with principle:
284277
if "pcm_dielectric" in self.molecule_entry:
278+
err_msg = (
279+
f"Principle molecule has a PCM dielectric of {self.molecule_entry['pcm_dielectric']}"
280+
" but a fragment entry has [[placeholder]] PCM dielectric! Please only pass fragment entries"
281+
" with PCM details consistent with the principle entry. Exiting..."
282+
)
285283
if "pcm_dielectric" not in entry:
286-
raise RuntimeError(
287-
"Principle molecule has a PCM dielectric of "
288-
+ str(self.molecule_entry["pcm_dielectric"])
289-
+ " but a fragment entry has no PCM dielectric! Please only pass fragment entries"
290-
" with PCM details consistent with the principle entry. Exiting..."
291-
)
284+
raise RuntimeError(err_msg.replace("[[placeholder]]", "no"))
292285
if entry["pcm_dielectric"] != self.molecule_entry["pcm_dielectric"]:
293-
raise RuntimeError(
294-
"Principle molecule has a PCM dielectric of "
295-
+ str(self.molecule_entry["pcm_dielectric"])
296-
+ " but a fragment entry has a different PCM dielectric! Please only pass"
297-
" fragment entries with PCM details consistent with the principle entry."
298-
" Exiting..."
299-
)
286+
raise RuntimeError(err_msg.replace("[[placeholder]]", "a different"))
287+
300288
# Build initial and final molgraphs:
301289
entry["initial_molgraph"] = MoleculeGraph.with_local_env_strategy(
302290
Molecule.from_dict(entry["initial_molecule"]), OpenBabelNN()

pymatgen/analysis/ewald.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -411,22 +411,13 @@ def eta(self):
411411
return self._eta
412412

413413
def __str__(self):
414-
if self._compute_forces:
415-
output = [
416-
"Real = " + str(self.real_space_energy),
417-
"Reciprocal = " + str(self.reciprocal_space_energy),
418-
"Point = " + str(self.point_energy),
419-
"Total = " + str(self.total_energy),
420-
"Forces:\n" + str(self.forces),
421-
]
422-
else:
423-
output = [
424-
"Real = " + str(self.real_space_energy),
425-
"Reciprocal = " + str(self.reciprocal_space_energy),
426-
"Point = " + str(self.point_energy),
427-
"Total = " + str(self.total_energy),
428-
"Forces were not computed",
429-
]
414+
output = [
415+
f"Real = {self.real_space_energy}",
416+
f"Reciprocal = {self.reciprocal_space_energy}",
417+
f"Point = {self.point_energy}",
418+
f"Total = {self.total_energy}",
419+
f"Forces:\n{self.forces}" if self._compute_forces else "Forces were not computed",
420+
]
430421
return "\n".join(output)
431422

432423
def as_dict(self, verbosity: int = 0) -> dict:

pymatgen/analysis/fragmenter.py

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,9 @@ def __init__(
105105
for level in range(depth):
106106
# If on the first level, perform one level of fragmentation on the principle molecule graph:
107107
if level == 0:
108+
alph_formula = self.mol_graph.molecule.composition.alphabetical_formula
108109
self.fragments_by_level["0"] = self._fragment_one_level(
109-
{
110-
str(self.mol_graph.molecule.composition.alphabetical_formula)
111-
+ " E"
112-
+ str(len(self.mol_graph.graph.edges())): [self.mol_graph]
113-
}
110+
{f"{alph_formula} E{len(self.mol_graph.graph.edges())}": [self.mol_graph]}
114111
)
115112
else:
116113
num_frags_prev_level = 0
@@ -183,11 +180,8 @@ def _fragment_one_level(self, old_frag_dict):
183180
if self.open_rings:
184181
fragments = [open_ring(old_frag, bond, self.opt_steps)]
185182
for fragment in fragments:
186-
new_frag_key = (
187-
str(fragment.molecule.composition.alphabetical_formula)
188-
+ " E"
189-
+ str(len(fragment.graph.edges()))
190-
)
183+
alph_formula = fragment.molecule.composition.alphabetical_formula
184+
new_frag_key = f"{alph_formula} E{len(fragment.graph.edges())}"
191185
proceed = True
192186
if (
193187
self.assume_previous_thoroughness
@@ -224,11 +218,8 @@ def _open_all_rings(self):
224218
we find. We also temporarily add the principle molecule graph to self.unique_fragments
225219
so that its rings are opened as well.
226220
"""
227-
mol_key = (
228-
str(self.mol_graph.molecule.composition.alphabetical_formula)
229-
+ " E"
230-
+ str(len(self.mol_graph.graph.edges()))
231-
)
221+
alph_formula = self.mol_graph.molecule.composition.alphabetical_formula
222+
mol_key = f"{alph_formula} E{len(self.mol_graph.graph.edges())}"
232223
self.all_unique_frag_dict[mol_key] = [self.mol_graph]
233224
new_frag_keys = {"0": []}
234225
new_frag_key_dict = {}
@@ -238,11 +229,8 @@ def _open_all_rings(self):
238229
if ring_edges != []:
239230
for bond in ring_edges[0]:
240231
new_fragment = open_ring(fragment, [bond], self.opt_steps)
241-
frag_key = (
242-
str(new_fragment.molecule.composition.alphabetical_formula)
243-
+ " E"
244-
+ str(len(new_fragment.graph.edges()))
245-
)
232+
alph_formula = new_fragment.molecule.composition.alphabetical_formula
233+
frag_key = f"{alph_formula} E{len(new_fragment.graph.edges())}"
246234
if frag_key not in self.all_unique_frag_dict:
247235
if frag_key not in new_frag_keys["0"]:
248236
new_frag_keys["0"].append(copy.deepcopy(frag_key))
@@ -276,11 +264,8 @@ def _open_all_rings(self):
276264
if ring_edges != []:
277265
for bond in ring_edges[0]:
278266
new_fragment = open_ring(fragment, [bond], self.opt_steps)
279-
frag_key = (
280-
str(new_fragment.molecule.composition.alphabetical_formula)
281-
+ " E"
282-
+ str(len(new_fragment.graph.edges()))
283-
)
267+
alph_formula = new_fragment.molecule.composition.alphabetical_formula
268+
frag_key = f"{alph_formula} E{len(new_fragment.graph.edges())}"
284269
if frag_key not in self.all_unique_frag_dict:
285270
if frag_key not in new_frag_keys[str(idx)]:
286271
new_frag_keys[str(idx)].append(copy.deepcopy(frag_key))

pymatgen/analysis/graphs.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,13 +2091,13 @@ def build_unique_fragments(self):
20912091
frag_dict = {}
20922092
for ii in range(1, len(self.molecule)):
20932093
for combination in combinations(graph.nodes, ii):
2094-
mycomp = []
2094+
comp = []
20952095
for idx in combination:
2096-
mycomp.append(str(self.molecule[idx].specie))
2097-
mycomp = "".join(sorted(mycomp))
2096+
comp.append(str(self.molecule[idx].specie))
2097+
comp = "".join(sorted(comp))
20982098
subgraph = nx.subgraph(graph, combination)
20992099
if nx.is_connected(subgraph):
2100-
mykey = mycomp + str(len(subgraph.edges()))
2100+
mykey = comp + str(len(subgraph.edges()))
21012101
if mykey not in frag_dict:
21022102
frag_dict[mykey] = [copy.deepcopy(subgraph)]
21032103
else:
@@ -2142,11 +2142,8 @@ def build_unique_fragments(self):
21422142
)
21432143
)
21442144

2145-
frag_key = (
2146-
str(unique_mol_graph_list[0].molecule.composition.alphabetical_formula)
2147-
+ " E"
2148-
+ str(len(unique_mol_graph_list[0].graph.edges()))
2149-
)
2145+
alph_formula = unique_mol_graph_list[0].molecule.composition.alphabetical_formula
2146+
frag_key = f"{alph_formula} E{len(unique_mol_graph_list[0].graph.edges())}"
21502147
unique_mol_graph_dict[frag_key] = copy.deepcopy(unique_mol_graph_list)
21512148
return unique_mol_graph_dict
21522149

pymatgen/analysis/interface_reactions.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,7 @@ def labels(self):
585585
3: 'x= 1 energy = 0 O2 -> O2'}.
586586
"""
587587
return {
588-
j: "x= " + str(round(x, 4)) + " energy in eV/atom = " + str(round(energy, 4)) + " " + str(reaction)
589-
for j, x, energy, reaction, _ in self.get_kinks()
588+
j: f"x= {x:.4} energy in eV/atom = {energy:.4} {reaction}" for j, x, energy, reaction, _ in self.get_kinks()
590589
}
591590

592591
@property
@@ -598,7 +597,7 @@ def minimum(self):
598597
Returns:
599598
Tuple (x_min, E_min).
600599
"""
601-
return min(((x, energy) for _, x, energy, _, _ in self.get_kinks()), key=lambda i: i[1])
600+
return min(((x, energy) for _, x, energy, _, _ in self.get_kinks()), key=lambda tup: tup[1])
602601

603602
@property
604603
def products(self):

pymatgen/analysis/magnetism/heisenberg.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def _get_exchange_df(self):
253253
# Get labels of unique NN interactions
254254
for k0, v0 in nn_interactions.items():
255255
for idx, j in v0.items(): # i and j indices
256-
c = str(idx) + "-" + str(j) + "-" + str(k0)
257-
c_rev = str(j) + "-" + str(idx) + "-" + str(k0)
256+
c = f"{idx}-{j}-{k0}"
257+
c_rev = f"{j}-{idx}-{k0}"
258258
if c not in columns and c_rev not in columns:
259259
columns.append(c)
260260

@@ -311,8 +311,8 @@ def _get_exchange_df(self):
311311
order = "-nnn"
312312
elif abs(dist - dists["nnnn"]) <= tol:
313313
order = "-nnnn"
314-
j_ij = str(i_index) + "-" + str(j_index) + order
315-
j_ji = str(j_index) + "-" + str(i_index) + order
314+
j_ij = f"{i_index}-{j_index}{order}"
315+
j_ji = f"{j_index}-{i_index}{order}"
316316

317317
if j_ij in ex_mat.columns:
318318
ex_row.loc[sgraph_index, j_ij] -= s_i * s_j
@@ -611,8 +611,8 @@ def _get_j_exc(self, i, j, dist):
611611
elif abs(dist - self.dists["nnnn"]) <= self.tol:
612612
order = "-nnnn"
613613

614-
j_ij = str(i_index) + "-" + str(j_index) + order
615-
j_ji = str(j_index) + "-" + str(i_index) + order
614+
j_ij = f"{i_index}-{j_index}{order}"
615+
j_ji = f"{j_index}-{i_index}{order}"
616616

617617
if j_ij in self.ex_params:
618618
j_exc = self.ex_params[j_ij]
@@ -631,7 +631,7 @@ def get_heisenberg_model(self):
631631
"""Save results of mapping to a HeisenbergModel object.
632632
633633
Returns:
634-
hmodel (HeisenbergModel): MSONable object.
634+
HeisenbergModel: MSONable object.
635635
"""
636636
# Original formula unit with nonmagnetic ions
637637
hm_formula = str(self.ordered_structures_[0].composition.reduced_formula)
@@ -981,8 +981,8 @@ def _get_j_exc(self, i, j, dist):
981981
elif abs(dist - self.dists["nnnn"]) <= self.tol:
982982
order = "-nnnn"
983983

984-
j_ij = str(i_index) + "-" + str(j_index) + order
985-
j_ji = str(j_index) + "-" + str(i_index) + order
984+
j_ij = f"{i_index}-{j_index}{order}"
985+
j_ji = f"{j_index}-{i_index}{order}"
986986

987987
if j_ij in self.ex_params:
988988
j_exc = self.ex_params[j_ij]

pymatgen/analysis/surface_analysis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def surface_energy(self, ucell_entry, ref_entries=None):
216216
# from each element with an existing ref_entry.
217217
bulk_energy, gbulk_eqn = 0, 0
218218
for el, ref in ref_entries_dict.items():
219-
N, delu = self.composition.as_dict()[el], Symbol("delu_" + str(el))
219+
N, delu = self.composition.as_dict()[el], Symbol(f"delu_{el}")
220220
if el in ucell_comp.as_dict():
221221
gbulk_eqn += ucell_reduced_comp[el] * (delu + ref.energy_per_atom)
222222
bulk_energy += N * (Symbol("delu_" + el) + ref.energy_per_atom)
File renamed without changes.

pymatgen/analysis/tests/test_phase_diagram.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from pymatgen.core.periodic_table import DummySpecies, Element
3131
from pymatgen.entries.computed_entries import ComputedEntry
3232
from pymatgen.entries.entry_tools import EntrySet
33+
from pymatgen.util.testing import PymatgenTest
3334

3435
module_dir = Path(__file__).absolute().parent
3536

@@ -93,7 +94,7 @@ def test_str(self):
9394
assert str(pde) == "PDEntry : Li1 Fe1 O2 with energy = 53.0000"
9495

9596
def test_read_csv(self):
96-
entries = EntrySet.from_csv(module_dir / "pdentries_test.csv")
97+
entries = EntrySet.from_csv(module_dir / "pd_entries_test.csv")
9798
assert entries.chemsys == {"Li", "Fe", "O"}, "Wrong elements!"
9899
assert len(entries) == 490, "Wrong number of entries!"
99100

@@ -147,9 +148,9 @@ def test_normalize(self):
147148
assert norm_entry.composition == expected_comp, "Wrong composition!"
148149

149150

150-
class PhaseDiagramTest(unittest.TestCase):
151+
class PhaseDiagramTest(PymatgenTest):
151152
def setUp(self):
152-
self.entries = EntrySet.from_csv(module_dir / "pdentries_test.csv")
153+
self.entries = EntrySet.from_csv(module_dir / "pd_entries_test.csv")
153154
self.pd = PhaseDiagram(self.entries)
154155
warnings.simplefilter("ignore")
155156

@@ -590,8 +591,10 @@ def test_to_from_dict(self):
590591
assert isinstance(pd.to_json(), str)
591592

592593
def test_read_json(self):
593-
dumpfn(self.pd, "pd.json")
594-
loadfn("pd.json")
594+
dumpfn(self.pd, f"{self.tmp_path}/pd.json")
595+
pd = loadfn(f"{self.tmp_path}/pd.json")
596+
assert isinstance(pd, PhaseDiagram)
597+
assert {*pd.as_dict()} == {*self.pd.as_dict()}
595598

596599
def test_el_refs(self):
597600
# Create an imitation of pre_computed phase diagram with el_refs keys being
@@ -611,7 +614,7 @@ def test_val_err_on_no_entries(self):
611614

612615
class GrandPotentialPhaseDiagramTest(unittest.TestCase):
613616
def setUp(self):
614-
self.entries = EntrySet.from_csv(module_dir / "pdentries_test.csv")
617+
self.entries = EntrySet.from_csv(module_dir / "pd_entries_test.csv")
615618
self.pd = GrandPotentialPhaseDiagram(self.entries, {Element("O"): -5})
616619
self.pd6 = GrandPotentialPhaseDiagram(self.entries, {Element("O"): -6})
617620

@@ -645,7 +648,7 @@ def test_str(self):
645648

646649
class CompoundPhaseDiagramTest(unittest.TestCase):
647650
def setUp(self):
648-
self.entries = EntrySet.from_csv(module_dir / "pdentries_test.csv")
651+
self.entries = EntrySet.from_csv(module_dir / "pd_entries_test.csv")
649652
self.pd = CompoundPhaseDiagram(self.entries, [Composition("Li2O"), Composition("Fe2O3")])
650653

651654
def test_stable_entries(self):
@@ -843,7 +846,7 @@ def test_formula(self):
843846

844847
class PDPlotterTest(unittest.TestCase):
845848
def setUp(self):
846-
entries = list(EntrySet.from_csv(os.path.join(module_dir, "pdentries_test.csv")))
849+
entries = list(EntrySet.from_csv(os.path.join(module_dir, "pd_entries_test.csv")))
847850

848851
elemental_entries = [e for e in entries if e.composition.elements == [Element("Li")]]
849852
self.pd_unary = PhaseDiagram(elemental_entries)

0 commit comments

Comments
 (0)