增加扩胞逻辑

This commit is contained in:
2025-12-14 17:57:42 +08:00
parent 2378a3f2a2
commit 9b36aa10ff
4 changed files with 310 additions and 153 deletions

View File

@@ -64,9 +64,10 @@ class StructureInfo:
is_binary_compound: bool = False
# 共占位详细分析(新增)
cation_has_partial_occupancy: bool = False # 目标阳离子共占位
anion_has_partial_occupancy: bool = False # 阴离子共占位
other_has_partial_occupancy: bool = False # 其他元素共占位(需扩胞)
cation_with_vacancy: bool = False # Li与空位共占位不需处理
cation_with_other_cation: bool = False # Li与其他阳离子共占位需扩胞
anion_has_partial_occupancy: bool = False # 阴离子共占位
other_has_partial_occupancy: bool = False # 其他元素共占位(需扩胞)
expansion_info: ExpansionInfo = field(default_factory=ExpansionInfo)
# 可处理性
@@ -218,14 +219,17 @@ class StructureInspector:
continue
return None
# 在 StructureInspector 类中,替换 _analyze_partial_occupancy 方法
def _analyze_partial_occupancy(self, structure: Structure, info: StructureInfo):
"""
分析共占位情况(核心逻辑
分析共占位情况(修正版
关键规则:
- 目标阳离子(Li)的共占位 → 不可处理
- 离子共占位 → 需要扩胞,但通常不处理
- 其他阳离子共占位 → 需要扩胞处理
- Li与空位共占位 → 不需要处理cation_with_vacancy
- Li与其他阳离子共占位 → 需要扩胞cation_with_other_cation
- 离子共占位 → 通常不处理
- 其他阳离子共占位 → 需要扩胞
"""
occupancy_dict = defaultdict(list) # {occupation: [site_indices]}
occupancy_elements = {} # {occupation: [elements]}
@@ -234,60 +238,118 @@ class StructureInspector:
site_species = site.species
species_string = str(site.species)
# 检查是否有多个物种占据同一位点
if len(site_species) > 1:
info.has_partial_occupancy = True
# 提取各元素及其占据率
species_occu = {} # {element: occupancy}
for sp, occu in site_species.items():
elem = sp.symbol if hasattr(sp, 'symbol') else str(sp)
elem = self._get_element_from_species_string(elem)
if elem:
species_occu[elem] = occu
# 提取各元素符号
elements_at_site = []
for sp in site_species.keys():
elem = sp.symbol if hasattr(sp, 'symbol') else str(sp)
elem = self._get_element_from_species_string(elem)
if elem:
elements_at_site.append(elem)
total_occupancy = sum(species_occu.values())
elements_at_site = list(species_occu.keys())
# 判断是否涉及目标阳离子
if self.target_cation in elements_at_site:
info.cation_has_partial_occupancy = True
# 检查是否有部分占据
has_partial = any(occu < 1.0 for occu in species_occu.values()) or len(species_occu) > 1
if not has_partial:
continue
info.has_partial_occupancy = True
# 判断Li的共占位情况
if self.target_cation in elements_at_site:
li_occu = species_occu.get(self.target_cation, 0)
other_elements = [e for e in elements_at_site if e != self.target_cation]
if not other_elements and li_occu < 1.0:
# Li与空位共占位Li占据率<1但没有其他元素
info.cation_with_vacancy = True
elif other_elements:
# Li与其他元素共占位
other_are_anions = all(e in self.target_anions for e in other_elements)
if other_are_anions:
# Li与阴离子共占位罕见标记为阴离子共占位
info.anion_has_partial_occupancy = True
else:
# Li与其他阳离子共占位 → 需要扩胞
info.cation_with_other_cation = True
# 记录需要扩胞的占据率取非Li元素的占据率
for elem in other_elements:
if elem not in self.target_anions:
occu = species_occu.get(elem, 0)
if occu > 0 and occu < 1.0:
occupancy_dict[occu].append(i)
occupancy_elements[occu] = elements_at_site
else:
# 不涉及Li的位点
# 判断是否涉及阴离子
if any(elem in self.target_anions for elem in elements_at_site):
info.anion_has_partial_occupancy = True
# 判断是否涉及其他元素(需要扩胞处理的情况)
other_elements = [e for e in elements_at_site
if e != self.target_cation and e not in self.target_anions]
if other_elements:
else:
# 其他阳离子的共占位 → 需要扩胞
info.other_has_partial_occupancy = True
# 获取占据率(取非目标阳离子的占据率)
occu = self._get_occupancy_from_species_string(
species_string,
self.target_cation_variants
)
if occu is not None and occu != 1.0:
occupancy_dict[occu].append(i)
occupancy_elements[occu] = elements_at_site
# 检查单一物种的部分占据
for specie, occupancy in site_species.items():
if occupancy < 1.0:
info.has_partial_occupancy = True
elem = specie.symbol if hasattr(specie, 'symbol') else str(specie)
elem = self._get_element_from_species_string(elem)
if elem == self.target_cation:
info.cation_has_partial_occupancy = True
elif elem in self.target_anions:
info.anion_has_partial_occupancy = True
else:
info.other_has_partial_occupancy = True
occupancy_dict[occupancy].append(i)
occupancy_elements[occupancy] = [elem]
# 获取占据率
for elem, occu in species_occu.items():
if occu > 0 and occu < 1.0:
occupancy_dict[occu].append(i)
occupancy_elements[occu] = elements_at_site
break # 只记录一次
# 计算扩胞信息
self._calculate_expansion_info(info, occupancy_dict, occupancy_elements)
def _evaluate_processability(self, info: StructureInfo):
"""评估可处理性(修正版)"""
skip_reasons = []
if not info.is_valid:
skip_reasons.append("无法解析CIF文件")
if not info.contains_target_cation:
skip_reasons.append(f"不含{self.target_cation}")
if info.anion_mode == "none":
skip_reasons.append("不含目标阴离子")
if info.is_binary_compound:
skip_reasons.append("二元化合物")
if info.has_radioactive_elements:
skip_reasons.append("含放射性元素")
# Li与空位共占位 → 不需要处理不加入skip_reasons
# info.cation_with_vacancy 不影响可处理性
# Li与其他阳离子共占位 → 需要扩胞(如果扩胞因子合理则可处理)
if info.cation_with_other_cation:
if info.expansion_info.can_expand:
info.needs_expansion = True
else:
skip_reasons.append(f"{self.target_cation}与其他阳离子共占位且{info.expansion_info.skip_reason}")
# 阴离子共占位 → 不处理
if info.anion_has_partial_occupancy:
skip_reasons.append("阴离子存在共占位")
if info.has_water_molecule:
skip_reasons.append("含水分子")
# 其他阳离子共占位不涉及Li→ 需要扩胞
if info.other_has_partial_occupancy:
if info.expansion_info.can_expand:
info.needs_expansion = True
else:
skip_reasons.append(info.expansion_info.skip_reason)
if skip_reasons:
info.can_process = False
info.skip_reason = "; ".join(skip_reasons)
else:
info.can_process = True
def _calculate_expansion_info(
self,
info: StructureInfo,