Skip to content

Commit 09252ad

Browse files
authored
Merge pull request #202 from ICAMS/fix_cs
Fix cs
2 parents 4489abe + 589647e commit 09252ad

File tree

6 files changed

+601
-42
lines changed

6 files changed

+601
-42
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.4.6
2+
current_version = 1.4.7
33
commit = True
44
tag = True
55

calphy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from calphy.alchemy import Alchemy
55
from calphy.routines import MeltingTemp
66

7-
__version__ = "1.4.6"
7+
__version__ = "1.4.7"
88

99
def addtest(a,b):
1010
return a+b

calphy/composition_transformation.py

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,17 @@ def convert_to_pyscal(self):
172172
"""
173173
Convert a given system to pyscal and give a dict of type mappings
174174
"""
175-
aseobj = read(self.calc.lattice, format="lammps-data", style="atomic")
175+
# Create Z_of_type mapping to properly read LAMMPS data files
176+
# This ensures atoms are correctly identified by their element
177+
Z_of_type = dict(
178+
[
179+
(count + 1, element(el).atomic_number)
180+
for count, el in enumerate(self.calc.element)
181+
]
182+
)
183+
aseobj = read(
184+
self.calc.lattice, format="lammps-data", style="atomic", Z_of_type=Z_of_type
185+
)
176186
pstruct = pc.System(aseobj, format="ase")
177187

178188
# here we have to validate the input composition dict; and map it
@@ -191,7 +201,6 @@ def convert_to_pyscal(self):
191201
self.actual_species = len(self.typedict)
192202
self.new_species = len(self.output_chemical_composition) - len(self.typedict)
193203
self.maxtype = self.actual_species + 1 # + self.new_species
194-
# print(self.typedict)
195204

196205
def get_composition_transformation(self):
197206
"""
@@ -215,26 +224,28 @@ def get_composition_transformation(self):
215224
self.to_remove = to_remove
216225
self.to_add = to_add
217226

218-
def get_random_index_of_species(self, species):
227+
def get_random_index_of_species(self, species_name):
219228
"""
220-
Get a random index of a given species
229+
Get a random index of a given species by element name
221230
"""
222-
ids = [count for count, x in enumerate(self.atom_type) if x == species]
231+
ids = [count for count, x in enumerate(self.atom_species) if x == species_name]
223232
return ids[np.random.randint(0, len(ids))]
224233

225234
def mark_atoms(self):
226235
for i in range(self.natoms):
227236
self.atom_mark.append(False)
228237

238+
# Use species (element symbols) instead of numeric types
239+
self.atom_species = self.pyscal_structure.atoms.species
229240
self.atom_type = self.pyscal_structure.atoms.types
230-
self.mappings = [f"{x}-{x}" for x in self.atom_type]
241+
self.mappings = [f"{x}-{x}" for x in self.atom_species]
231242

232243
def update_mark_atoms(self):
233244
self.marked_atoms = []
234245
for key, val in self.to_remove.items():
235-
# print(f"Element {key}, count {val}")
246+
# key is the element name (e.g., "Mg")
236247
for i in range(100000):
237-
rint = self.get_random_index_of_species(self.typedict[key])
248+
rint = self.get_random_index_of_species(key)
238249
if rint not in self.marked_atoms:
239250
self.atom_mark[rint] = True
240251
self.marked_atoms.append(rint)
@@ -257,22 +268,20 @@ def update_typedicts(self):
257268

258269
def compute_possible_mappings(self):
259270
self.possible_mappings = []
260-
# Now make a list of possible mappings
271+
# Now make a list of possible mappings using element names
261272
for key1, val1 in self.to_remove.items():
262273
for key2, val2 in self.to_add.items():
263274
mapping = f"{key1}-{key2}"
264275
if mapping not in self.restrictions:
265-
self.possible_mappings.append(
266-
f"{self.typedict[key1]}-{self.typedict[key2]}"
267-
)
276+
self.possible_mappings.append(mapping)
268277

269278
def update_mappings(self):
270279
marked_atoms = self.marked_atoms.copy()
271280
for key, val in self.to_add.items():
272281
# now get all
273282

274283
# we to see if we can get val number of atoms from marked ones
275-
if val < len(marked_atoms):
284+
if val > len(marked_atoms):
276285
raise ValueError(
277286
f"Not enough atoms to choose {val} from {len(marked_atoms)} not possible"
278287
)
@@ -284,8 +293,8 @@ def update_mappings(self):
284293
to_del = []
285294
for x in range(len(self.marked_atoms)):
286295
random_choice = np.random.choice(marked_atoms)
287-
# find corresponding mappiong
288-
mapping = f"{self.atom_type[random_choice]}-{self.typedict[key]}"
296+
# find corresponding mapping using species name
297+
mapping = f"{self.atom_species[random_choice]}-{key}"
289298
if mapping in self.possible_mappings:
290299
# this is a valid choice
291300
self.mappings[random_choice] = mapping
@@ -314,12 +323,8 @@ def update_mappings(self):
314323
mapsplit = mapping.split("-")
315324
if not mapsplit[0] == mapsplit[1]:
316325
transformation_dict = {}
317-
transformation_dict["primary_element"] = self.reversetypedict[
318-
int(mapsplit[0])
319-
]
320-
transformation_dict["secondary_element"] = self.reversetypedict[
321-
int(mapsplit[1])
322-
]
326+
transformation_dict["primary_element"] = mapsplit[0]
327+
transformation_dict["secondary_element"] = mapsplit[1]
323328
transformation_dict["count"] = self.unique_mapping_counts[count]
324329
self.transformation_list.append(transformation_dict)
325330

@@ -333,25 +338,34 @@ def prepare_pair_lists(self):
333338
self.pair_list_new = []
334339
for mapping in self.unique_mappings:
335340
map_split = mapping.split("-")
336-
# conserved atom
341+
# conserved atom - mappings now use element names directly
337342
if map_split[0] == map_split[1]:
338-
self.pair_list_old.append(self.reversetypedict[int(map_split[0])])
339-
self.pair_list_new.append(self.reversetypedict[int(map_split[0])])
343+
self.pair_list_old.append(map_split[0])
344+
self.pair_list_new.append(map_split[0])
340345
else:
341-
self.pair_list_old.append(self.reversetypedict[int(map_split[0])])
342-
self.pair_list_new.append(self.reversetypedict[int(map_split[1])])
346+
self.pair_list_old.append(map_split[0])
347+
self.pair_list_new.append(map_split[1])
348+
349+
# Special case: 100% transformation with only 1 mapping
350+
# LAMMPS expects elements for all atom types in the system
351+
# Example: Al→Mg only, but system has 2 types → need ['Al', 'Al'] and ['Mg', 'Mg']
352+
n_elements = len(self.calc.element)
353+
if len(self.unique_mappings) == 1 and n_elements > 1:
354+
# Duplicate the single mapping to match number of element types
355+
for _ in range(n_elements - 1):
356+
self.pair_list_old.append(self.pair_list_old[0])
357+
self.pair_list_new.append(self.pair_list_new[0])
358+
343359
self.new_atomtype = np.array(range(len(self.unique_mappings))) + 1
344360
self.mappingdict = dict(zip(self.unique_mappings, self.new_atomtype))
345361

346362
def update_types(self):
363+
# Update atom_type based on mapping to new types
347364
for x in range(len(self.atom_type)):
348365
self.atom_type[x] = self.mappingdict[self.mappings[x]]
349366

350-
# smartify these loops
351-
# npyscal = len(self.pyscal_structure.atoms.types)
367+
# Update pyscal structure types
352368
self.pyscal_structure.atoms.types = self.atom_type
353-
# for count in range(npyscal)):
354-
# self.pyscal_structure.atoms.types[count] = self.atom_type[count]
355369

356370
def iselement(self, symbol):
357371
try:
@@ -392,7 +406,7 @@ def update_pair_coeff(self, pair_coeff):
392406
# If element_group matches our pair_list_old, replace with pair_list_new
393407
# Otherwise replace with pair_list_old (for the old/reference command)
394408
if element_group == self.pair_list_old or set(element_group) == set(
395-
self.element
409+
self.calc.element
396410
):
397411
# This needs special handling - we'll mark position for later
398412
result_parts.append("__ELEMENTS__")
@@ -432,12 +446,15 @@ def update_pair_coeff(self, pair_coeff):
432446

433447
def get_swap_types(self):
434448
"""
435-
Get swapping types
449+
Get swapping types for configurational entropy calculation.
450+
451+
Returns types that share the same initial element but have different
452+
transformation paths (e.g., Al→Al vs Al→Mg).
436453
"""
437454
swap_list = []
438455
for mapping in self.unique_mappings:
439456
map_split = mapping.split("-")
440-
# conserved atom
457+
# conserved atom - skip
441458
if map_split[0] == map_split[1]:
442459
pass
443460
else:
@@ -446,12 +463,19 @@ def get_swap_types(self):
446463
first_map = f"{first_type}-{first_type}"
447464
second_map = mapping
448465

449-
# get the numbers from dict
450-
first_swap_type = self.mappingdict[first_map]
451-
second_swap_type = self.mappingdict[second_map]
466+
# Check if conserved mapping exists
467+
if first_map in self.mappingdict:
468+
# get the numbers from dict
469+
first_swap_type = self.mappingdict[first_map]
470+
second_swap_type = self.mappingdict[second_map]
471+
swap_list.append([first_swap_type, second_swap_type])
472+
else:
473+
# 100% transformation case - no conserved atoms of this type
474+
# Only the transforming type exists
475+
second_swap_type = self.mappingdict[second_map]
476+
swap_list.append([second_swap_type])
452477

453-
swap_list.append([first_swap_type, second_swap_type])
454-
return swap_list[0]
478+
return swap_list[0] if swap_list else []
455479

456480
def write_structure(self, outfilename):
457481
# create some species dict

calphy/input.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from ase.io import read, write
5050
import shutil
5151

52-
__version__ = "1.4.6"
52+
__version__ = "1.4.7"
5353

5454

5555
def _check_equal(val):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
packages=find_packages(include=['calphy', 'calphy.*']),
5454
test_suite='tests',
5555
url='https://github.com/ICAMS/calphy',
56-
version='1.4.6',
56+
version='1.4.7',
5757
zip_safe=False,
5858
entry_points={
5959
'console_scripts': [

0 commit comments

Comments
 (0)