Ionic 2.0 Alpha版本发布了

Ionic团队宣布发布Ionic 2.0 Alpha版本,在Angular Connect会议上首次公开。该版本包含许多重大改进,如增强导航体验、增加原生功能支持、强大的主题定制能力等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Today, at the Angular Connect conference in London, we announced the first public alpha version of Ionic 2. Many months of hard work, false starts, lessons learned, and “aha!” moments have led us to this day, and we are so excited to finally take the wraps off the next generation of Ionic.

We’ve talked a lot about why we built Ionic 2, but it’s worth revisiting the story now that Ionic 2 actually exists in the wild. We started working on Ionic in the Summer of 2013, back when iOS 6 was king and Android 2.3 was still powering a significant number of devices. We had different browser APIs (lack thereof, really), and browser engines that seriously underperform what we have today. We decided to base Ionic on Angular, which ended up being a really lucky decision, but Angular 1.1 which we used back then is a far cry from new Angular 1 versions, and a generation in capability from Angular 2.

Fast forward two years, and Ionic has found widespread adoption in a diverse set of industries from developers around the world. Collectively, over 1.2M apps have been built on Ionic, a number that is increasing exponentially. With all these developers creating all these apps on Ionic, we’ve been able to learn a thing or two about how to build the best possible mobile development toolkit to help people build great apps quickly, without breaking the bank.

With all that data, we realized there were a number of crucial things we could improve in Ionic, but they would require more significant architectural changes. Angular 2 seemed like the perfect opportunity to do just that.

With Ionic 2, we’ve overhauled and added a number of important features, including:

  • Overhauled Navigation: Completely control the navigation experience of your app without being tied to the URL bar. Navigate to any page inside of any view, including modals, side menus, and other view containers, while maintaining full deeplinking capability. This will completely change how you think about your app experience.

  • Native Support: We’ve added more native functionality directly into Ionic, making it easy to take advantage of the full power of the device without hunting down external plugins and code.

  • Powerful Theming: Don’t build apps that look like stock iOS/Android/Ionic. With the new theming system, it’s easy to instantly match your brand colors and design.

  • Material Design: Full material design support for Android apps.

Not to mention new and improved components, new docs, a new animation system, dramatically improved performance, and a whole lot more.

Let’s address the elephant in the room: “What about Ionic 1? What’s going to happen to it?” First of all, we will absolutely continue supporting Ionic 1 for a long time. In fact, there are a number of improvements we’re working on, including upgrading to the next version of Angular. At the same time, we are going to work to make it easy to upgrade to Ionic 2 slowly over time, as the community also starts to adopt Angular 2. While we aren’t going to apologize for wanting to push Ionic hard into the future, we also understand that software can live for a long time, and should be supported for as long as possible.

One of the things that gets us so excited about Ionic 2 is just how much room there was to improve on Ionic 1, especially when it came to performance and native functionality. We’ve been able to really optimize how Ionic apps feel with v2, and we think it’s going to completely change what you thought the web was capable of on mobile.

To get started, visit ionic.io/2, or visit the Getting Started page. We’ve also opened up a temporary GitHub Repository for Ionic 2 (see the README for a few demos!), and we will be moving the code over to the official Ionic repo over the coming weeks. If you run into any issues or have any feedback, please file issues on that repo! Also check out Adam’s great slides from his Ionic 2 talk today, complete with demos!

We want to thank everyone from the Ionic community for your support over the last two years. None of us expected that Ionic would become the most popular cross-platform mobile development toolkit in such a short amount of time, and it’s really your passion for building apps and sharing that passion with the world that has made any of this possible.

From all of us at Ionic, thank you, and we look forward to your feedback on Ionic 2 as we all work hard to push open web technologies on mobile into the future!

import sys import io import numpy as np import matplotlib.pyplot as plt from pymatgen.io.vasp import Vasprun from pymatgen.core.structure import Structure from scipy.spatial import cKDTree import matplotlib as mpl import warnings import os import argparse import multiprocessing from functools import partial import time import logging from collections import defaultdict # 设置编码为 UTF-8 以支持特殊字符 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') # 配置日志记录 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("rdf_analysis.log", encoding='utf-8'), logging.StreamHandler() ] ) # 忽略可能的警告 warnings.filterwarnings("ignore", category=UserWarning) # 专业绘图设置 plt.style.use('seaborn-v0_8-whitegrid') mpl.rcParams.update({ 'font.family': 'serif', 'font.serif': ['Times New Roman', 'DejaVu Serif'], 'font.size': 12, 'axes.labelsize': 14, 'axes.titlesize': 16, 'xtick.labelsize': 12, 'ytick.labelsize': 12, 'figure.dpi': 600, 'savefig.dpi': 600, 'figure.figsize': (8, 6), 'lines.linewidth': 2.0, 'legend.fontsize': 10, 'legend.framealpha': 0.8, 'mathtext.default': 'regular', 'axes.linewidth': 1.5, 'xtick.major.width': 1.5, 'ytick.major.width': 1.5, 'xtick.major.size': 5, 'ytick.major.size': 5, }) def identify_atom_types(struct): """ 识别磷酸氧(Op)和所有氢原子(H) :param struct: 结构对象 :return: 包含Op和H索引的字典 """ phosphate_oxygens = [] all_hydrogens = [] # 识别所有氢原子 for i, site in enumerate(struct): if site.species_string == "H": all_hydrogens.append(i) # 识别磷酸氧:与P原子距离小于1.6A的氧原子 for i, site in enumerate(struct): if site.species_string == "P": # 获取P原子周围1.6A内的氧原子 neighbors = struct.get_neighbors(site, r=1.6) for neighbor in neighbors: if neighbor[0].species_string == "O": phosphate_oxygens.append(neighbor[0].index) # 去重 phosphate_oxygens = list(set(phosphate_oxygens)) logging.info(f"Identified {len(phosphate_oxygens)} phosphate oxygens and {len(all_hydrogens)} hydrogen atoms") return { "phosphate_oxygens": phosphate_oxygens, "all_hydrogens": all_hydrogens } def process_frame(struct, center_sel, target_sel, r_max, exclude_bonds, bond_threshold): """处理单帧结构计算RDF""" try: atom_types = identify_atom_types(struct) centers = center_sel(atom_types) targets = target_sel(atom_types) # 处理空原子类型情况 if len(centers) == 0 or len(targets) == 0: logging.warning(f"No centers or targets found in frame") return { "distances": np.array([], dtype=np.float64), "n_centers": 0, "n_targets": 0, "volume": struct.volume } center_coords = np.array([struct[i].coords for i in centers]) target_coords = np.array([struct[i].coords for i in targets]) lattice = struct.lattice kdtree = cKDTree(target_coords, boxsize=lattice.abc) # 动态确定邻居数量 k_val = min(50, len(targets)) if k_val == 0: return { "distances": np.array([], dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } try: distances, indices = kdtree.query(center_coords, k=k_val, distance_upper_bound=r_max) except Exception as e: logging.error(f"KDTree query error: {str(e)}") return { "distances": np.array([], dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } # 处理查询结果 valid_distances = [] for i in range(distances.shape[0]): center_idx = centers[i] for j in range(distances.shape[1]): dist = distances[i, j] if dist > r_max or np.isinf(dist): continue target_idx = targets[indices[i, j]] # 排除化学键 if exclude_bonds: actual_dist = struct.get_distance(center_idx, target_idx) if actual_dist < bond_threshold: continue valid_distances.append(dist) return { "distances": np.array(valid_distances, dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } except Exception as e: logging.error(f"Error processing frame: {str(e)}") return { "distances": np.array([], dtype=np.float64), "n_centers": 0, "n_targets": 0, "volume": struct.volume } def calculate_rdf(structures, center_sel, target_sel, r_max=8.0, bin_width=0.05, exclude_bonds=True, bond_threshold=1.3, workers=1): """ 计算径向分布函数 :param workers: 并行工作进程数 """ bins = np.arange(0, r_max, bin_width) hist = np.zeros(len(bins) - 1) total_centers = 0 total_targets = 0 total_volume = 0 func = partial(process_frame, center_sel=center_sel, target_sel=target_sel, r_max=r_max, exclude_bonds=exclude_bonds, bond_threshold=bond_threshold) # 使用多进程池 with multiprocessing.Pool(processes=workers) as pool: results = [] try: for res in pool.imap_unordered(func, structures): results.append(res) except Exception as e: logging.error(f"Error in parallel processing: {str(e)}") # 处理结果 n_frames = 0 for res in results: if res is None: continue n_frames += 1 valid_distances = res["distances"] n_centers = res["n_centers"] n_targets = res["n_targets"] volume = res["volume"] if len(valid_distances) > 0: hist += np.histogram(valid_distances, bins=bins)[0] total_centers += n_centers total_targets += n_targets total_volume += volume if n_frames == 0: r = bins[:-1] + bin_width/2 return r, np.zeros_like(r) avg_density = total_targets / total_volume if total_volume > 0 else 0 r = bins[:-1] + bin_width/2 rdf = np.zeros_like(r) for i in range(len(hist)): r_lower = bins[i] r_upper = bins[i+1] shell_vol = 4/3 * np.pi * (r_upper**3 - r_lower**3) expected_count = shell_vol * avg_density * total_centers if expected_count > 1e-10: rdf[i] = hist[i] / expected_count else: rdf[i] = 0 return r, rdf # 选择器函数 def selector_phosphate_oxygens(atom_types): return atom_types["phosphate_oxygens"] def selector_all_hydrogens(atom_types): return atom_types["all_hydrogens"] def save_rdf_data(r, rdf, output_dir, system_name): """保存RDF数据到文本文件""" os.makedirs(output_dir, exist_ok=True) filename = os.path.join(output_dir, f"{system_name}_Op_H_RDF.txt") try: with open(filename, 'w', encoding='utf-8') as f: # 使用A代替Å,避免编码问题 f.write("# Distance (A)\tg(r)\n") for i in range(len(r)): f.write(f"{r[i]:.4f}\t{rdf[i]:.6f}\n") logging.info(f"Saved RDF data to: {filename}") return True except Exception as e: logging.error(f"Error saving RDF data: {str(e)}") return False def plot_single_rdf(r, rdf, output_dir, system_name): """绘制并保存单个RDF图""" try: fig, ax = plt.subplots(figsize=(8, 6)) # 绘制RDF ax.plot(r, rdf, 'b-', linewidth=2.0, label=f'{system_name} Op-H RDF') # 标记氢键区域 ax.axvspan(1.0, 2.0, alpha=0.1, color='green', label='H-bond Region') ax.text(1.3, np.max(rdf)*0.8, 'H-bond Region', fontsize=12) # 设置坐标轴 - 使用A代替Å ax.set_xlim(0, 6.0) ax.set_ylim(0, np.max(rdf)*1.2) ax.set_xlabel('Radial Distance (A)', fontweight='bold') # 使用A代替Å ax.set_ylabel('g(r)', fontweight='bold') ax.set_title(f'{system_name}: Phosphate Oxygen - Hydrogen RDF', fontsize=16, pad=15) # 添加网格和图例 ax.grid(True, linestyle='--', alpha=0.5) ax.legend(loc='best', framealpha=0.8) # 保存图片 plt.tight_layout() filename = os.path.join(output_dir, f"{system_name}_Op_H_RDF.tiff") plt.savefig(filename, bbox_inches='tight', dpi=600, format='tiff') plt.close() logging.info(f"Saved RDF plot to: {filename}") return True except Exception as e: logging.error(f"Error plotting RDF for {system_name}: {str(e)}") return False def plot_combined_rdf(all_rdf_data, output_dir): """绘制并保存合并的RDF图""" try: fig, ax = plt.subplots(figsize=(10, 8)) # 颜色和线型设置 colors = ['b', 'r', 'g', 'm', 'c', 'y', 'k'] line_styles = ['-', '--', '-.', ':'] # 绘制所有体系的RDF曲线 for i, (system_name, (r, rdf)) in enumerate(all_rdf_data.items()): color = colors[i % len(colors)] line_style = line_styles[(i // len(colors)) % len(line_styles)] ax.plot(r, rdf, color=color, linestyle=line_style, linewidth=2.0, label=system_name) # 标记氢键区域 ax.axvspan(1.0, 2.0, alpha=0.1, color='green', label='H-bond Region') ax.text(1.3, np.max([np.max(rdf) for _, (_, rdf) in all_rdf_data.items()])*0.8, 'H-bond Region', fontsize=12) # 设置坐标轴 ax.set_xlim(0, 6.0) ax.set_ylim(0, np.max([np.max(rdf) for _, (_, rdf) in all_rdf_data.items()])*1.2) ax.set_xlabel('Radial Distance (A)', fontweight='bold') ax.set_ylabel('g(r)', fontweight='bold') ax.set_title('Phosphate Oxygen - Hydrogen RDF Comparison', fontsize=16, pad=15) # 添加网格和图例 ax.grid(True, linestyle='--', alpha=0.5) ax.legend(loc='best', framealpha=0.8) # 保存图片 plt.tight_layout() filename = os.path.join(output_dir, "combined_Op_H_RDF.tiff") plt.savefig(filename, bbox_inches='tight', dpi=600, format='tiff') plt.close() logging.info(f"Saved combined RDF plot to: {filename}") return True except Exception as e: logging.error(f"Error plotting combined RDF: {str(e)}") return False def load_vasprun_safe(filename): """安全加载Vasprun文件,处理编码问题""" try: # 尝试使用pymatgen的标准方法 return Vasprun(filename, ionic_step_skip=5) except Exception as e: logging.warning(f"Standard loading failed for {filename}: {str(e)}. Trying alternative method...") try: # 尝试显式指定编码 return Vasprun(filename, ionic_step_skip=5, parse_dos=False, parse_eigen=False) except Exception as e2: logging.error(f"Alternative loading failed for {filename}: {str(e2)}") return None def process_single_file(input_file, workers, output_dir): """处理单个VASP结果文件""" system_name = os.path.splitext(os.path.basename(input_file))[0] logging.info(f"Processing {input_file} with {workers} workers...") try: # 安全加载VASP结果 vr = load_vasprun_safe(input_file) if vr is None: logging.error(f"Failed to load VASP results from {input_file}") return None, None structures = vr.structures logging.info(f"Loaded {len(structures)} frames for {system_name}") # 计算Op-H RDF r, rdf = calculate_rdf( structures, selector_phosphate_oxygens, selector_all_hydrogens, r_max=8.0, bin_width=0.05, exclude_bonds=True, bond_threshold=1.3, workers=workers ) # 保存数据 save_success = save_rdf_data(r, rdf, output_dir, system_name) # 绘制单个图表 plot_success = plot_single_rdf(r, rdf, output_dir, system_name) if save_success and plot_success: logging.info(f"Completed processing for {system_name}") else: logging.warning(f"Processing for {system_name} completed with errors") return system_name, (r, rdf) except Exception as e: logging.error(f"Error processing {input_file}: {str(e)}") return None, None def main(input_files, workers=1): """主函数,处理多个文件""" start_time = time.time() # 创建输出目录 output_dir = "RDF_Results" os.makedirs(output_dir, exist_ok=True) # 存储所有体系的RDF数据 all_rdf_data = {} # 处理每个输入文件 for input_file in input_files: system_name, rdf_data = process_single_file(input_file, workers, output_dir) if rdf_data: all_rdf_data[system_name] = rdf_data # 绘制合并的RDF图 if len(all_rdf_data) > 1: plot_combined_rdf(all_rdf_data, output_dir) elapsed = time.time() - start_time logging.info(f"Completed all processing in {elapsed:.2f} seconds") if __name__ == "__main__": # 设置命令行参数 parser = argparse.ArgumentParser(description='Calculate Op-H RDF for multiple VASP simulations') parser.add_argument('input_files', type=str, nargs='+', help='Input vasprun.xml files (e.g., vasprun1.xml vasprun2.xml ...)') parser.add_argument('--workers', type=int, default=multiprocessing.cpu_count(), help=f'Number of parallel workers per file (default: {multiprocessing.cpu_count()})') args = parser.parse_args() logging.info(f"Starting Op-H RDF analysis for {len(args.input_files)} files with {args.workers} workers per file...") main(args.input_files, workers=args.workers) 这个代码中计算Op-H的RDF时候是不是自动去除了小于1.3的部分?
07-13
import numpy as np import matplotlib.pyplot as plt from pymatgen.io.vasp import Vasprun from pymatgen.core.structure import Structure from scipy.signal import savgol_filter from scipy.spatial import cKDTree from tqdm import tqdm import matplotlib as mpl import warnings from collections import defaultdict import os import csv import argparse import multiprocessing from functools import partial import time import dill # 忽略可能的警告 warnings.filterwarnings("ignore", category=UserWarning) # 专业绘图设置 - 符合Journal of Chemical Physics要求 plt.style.use('seaborn-v0_8-whitegrid') mpl.rcParams.update({ 'font.family': 'serif', 'font.serif': ['Times New Roman', 'DejaVu Serif'], 'font.size': 12, 'axes.labelsize': 14, 'axes.titlesize': 16, 'xtick.labelsize': 12, 'ytick.labelsize': 12, 'figure.dpi': 600, # 提高分辨率 'savefig.dpi': 600, 'figure.figsize': (8, 6), # 期刊常用尺寸 'lines.linewidth': 2.0, 'legend.fontsize': 10, 'legend.framealpha': 0.8, 'mathtext.default': 'regular', 'axes.linewidth': 1.5, # 加粗坐标轴线 'xtick.major.width': 1.5, 'ytick.major.width': 1.5, 'xtick.major.size': 5, 'ytick.major.size': 5, }) # 1. 增强的原子类型识别函数 - 逐帧识别 def identify_atom_types(struct): """识别所有关键原子类型并排除自身化学键""" # 磷酸氧分类 p_oxygens = {"P=O": [], "P-O": [], "P-OH": []} phosphate_hydrogens = [] # 仅P-OH基团中的H原子 # 水合氢离子识别 hydronium_oxygens = [] hydronium_hydrogens = [] # H₃O⁺中的H原子 # 普通水分子 water_oxygens = [] water_hydrogens = [] # 普通水中的H原子 # 氟离子 fluoride_atoms = [i for i, site in enumerate(struct) if site.species_string == "F"] # 铝离子 aluminum_atoms = [i for i, site in enumerate(struct) if site.species_string == "Al"] # 创建快速邻居查找表 neighbor_cache = defaultdict(list) for i, site in enumerate(struct): if site.species_string == "O": neighbors = struct.get_neighbors(site, r=1.3) h_neighbors = [n[0] for n in neighbors if n[0].species_string == "H"] neighbor_cache[i] = h_neighbors # 识别水合氢离子 (H₃O⁺) if len(h_neighbors) == 3: hydronium_oxygens.append(i) for h_site in h_neighbors: hydronium_hydrogens.append(h_site.index) # 识别磷酸基团 for site in struct: if site.species_string == "P": neighbors = struct.get_neighbors(site, r=2.0) # 扩大搜索半径 # 筛选氧原子邻居 o_neighbors = [(n[0], n[1]) for n in neighbors if n[0].species_string == "O"] if len(o_neighbors) < 4: # 如果找不到4个氧原子,使用旧方法 for neighbor in o_neighbors: nn_site = neighbor[0] if neighbor[1] < 1.55: p_oxygens["P=O"].append(nn_site.index) else: if any(n[0].species_string == "H" for n in struct.get_neighbors(nn_site, r=1.3)): p_oxygens["P-OH"].append(nn_site.index) else: p_oxygens["P-O"].append(nn_site.index) continue # 按距离排序 o_neighbors.sort(key=lambda x: x[1]) # 最近的氧原子为P=O p_double_o = o_neighbors[0][0] p_oxygens["P=O"].append(p_double_o.index) # 其他三个氧原子 for i in range(1, 4): o_site = o_neighbors[i][0] # 检查氧原子上是否有氢 if neighbor_cache.get(o_site.index, []): p_oxygens["P-OH"].append(o_site.index) else: p_oxygens["P-O"].append(o_site.index) # 识别P-OH基团中的H原子 (磷酸中的H) for o_idx in p_oxygens["P-OH"]: # 获取与P-OH氧相连的H原子 h_neighbors = neighbor_cache.get(o_idx, []) for h_site in h_neighbors: if h_site.species_string == "H": phosphate_hydrogens.append(h_site.index) # 识别普通水分子 (排除磷酸氧和水合氢离子) for i, site in enumerate(struct): if site.species_string == "O" and i not in hydronium_oxygens: is_phosphate_oxygen = False for cat in p_oxygens.values(): if i in cat: is_phosphate_oxygen = True break if not is_phosphate_oxygen: water_oxygens.append(i) # 识别普通水分子中的H原子 (水中的H) for o_idx in water_oxygens: h_neighbors = neighbor_cache.get(o_idx, []) for h_site in h_neighbors: if h_site.species_string == "H": water_hydrogens.append(h_site.index) return { "phosphate_oxygens": p_oxygens, "phosphate_hydrogens": phosphate_hydrogens, "water_oxygens": water_oxygens, "water_hydrogens": water_hydrogens, "hydronium_oxygens": hydronium_oxygens, "hydronium_hydrogens": hydronium_hydrogens, "fluoride_atoms": fluoride_atoms, "aluminum_atoms": aluminum_atoms } # 2. RDF计算函数 - 修复负值问题和序列化问题 def process_frame(struct, center_sel, target_sel, r_max, exclude_bonds, bond_threshold): """处理单帧结构计算,完全处理空原子类型情况""" # 每帧重新识别原子类型(关键!) atom_types = identify_atom_types(struct) # 获取中心原子和目标原子 centers = center_sel(atom_types) targets = target_sel(atom_types) # 处理空原子类型情况 - 第一重保护 if len(centers) == 0 or len(targets) == 0: return { "distances": np.array([], dtype=np.float64), "n_centers": 0, "n_targets": 0, "volume": struct.volume } center_coords = np.array([struct[i].coords for i in centers]) target_coords = np.array([struct[i].coords for i in targets]) lattice = struct.lattice kdtree = cKDTree(target_coords, boxsize=lattice.abc) # 动态确定邻居数量 - 不超过目标原子数 k_val = min(50, len(targets)) # 处理目标原子数量为0的情况 - 第二重保护 if k_val == 0: return { "distances": np.array([], dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } # 执行查询并确保结果统一格式 try: query_result = kdtree.query(center_coords, k=k_val, distance_upper_bound=r_max) except Exception as e: # 异常处理 - 返回空结果 print(f"KDTree query error: {str(e)}") return { "distances": np.array([], dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } # 统一处理不同维度的返回结果 if k_val == 1: # 处理单邻居情况 if isinstance(query_result, tuple): distances, indices = query_result else: distances = query_result indices = np.zeros_like(distances, dtype=int) # 确保数组格式 distances = np.atleast_1d(distances) indices = np.atleast_1d(indices) else: # 多邻居情况 distances, indices = query_result # 确保二维数组格式 if distances.ndim == 1: distances = distances.reshape(-1, 1) indices = indices.reshape(-1, 1) valid_distances = [] for i in range(distances.shape[0]): center_idx = centers[i] for j in range(distances.shape[1]): dist = distances[i, j] # 跳过超出范围的距离 if dist > r_max or np.isinf(dist): continue target_idx = targets[indices[i, j]] # 排除化学键 if exclude_bonds: actual_dist = struct.get_distance(center_idx, target_idx) if actual_dist < bond_threshold: continue valid_distances.append(dist) return { "distances": np.array(valid_distances, dtype=np.float64), "n_centers": len(centers), "n_targets": len(targets), "volume": struct.volume } def calculate_rdf_parallel(structures, center_sel, target_sel, r_max=8.0, bin_width=0.05, exclude_bonds=True, bond_threshold=1.3, workers=1): """ 并行计算径向分布函数 :param workers: 并行工作进程数 """ bins = np.arange(0, r_max, bin_width) hist = np.zeros(len(bins) - 1) total_centers = 0 total_targets = 0 total_volume = 0 # 准备参数 - 使用dill解决序列化问题 dill.settings['recurse'] = True func = partial(process_frame, center_sel=center_sel, target_sel=target_sel, r_max=r_max, exclude_bonds=exclude_bonds, bond_threshold=bond_threshold) # 使用多进程池 with multiprocessing.Pool(processes=workers) as pool: results = [] # 使用imap_unordered提高效率 for res in tqdm(pool.imap_unordered(func, structures), total=len(structures), desc="Calculating RDF"): results.append(res) # 处理结果 - 特别注意空结果处理 n_frames = 0 for res in results: if res is None: continue n_frames += 1 valid_distances = res["distances"] n_centers = res["n_centers"] n_targets = res["n_targets"] volume = res["volume"] # 累加计数 if len(valid_distances) > 0: hist += np.histogram(valid_distances, bins=bins)[0] total_centers += n_centers total_targets += n_targets total_volume += volume # 修正归一化 - 解决负值问题 if n_frames == 0: # 没有有效帧时返回空结果 r = bins[:-1] + bin_width/2 return r, np.zeros_like(r), {"position": None, "value": None} avg_density = total_targets / total_volume if total_volume > 0 else 0 r = bins[:-1] + bin_width/2 rdf = np.zeros_like(r) for i in range(len(hist)): r_lower = bins[i] r_upper = bins[i+1] shell_vol = 4/3 * np.pi * (r_upper**3 - r_lower**3) expected_count = shell_vol * avg_density * total_centers # 避免除以零 if expected_count > 1e-10: rdf[i] = hist[i] / expected_count else: rdf[i] = 0 # 更稳健的平滑处理 - 避免边界效应 if len(rdf) > 10: window_length = min(15, len(rdf)//2*2+1) polyorder = min(5, window_length-1) rdf_smoothed = savgol_filter(rdf, window_length=window_length, polyorder=polyorder, mode='mirror') else: rdf_smoothed = rdf # 计算主要峰值 peak_info = {} mask = (r >= 1.5) & (r <= 3.0) if np.any(mask) and np.any(rdf_smoothed[mask] > 0): peak_idx = np.argmax(rdf_smoothed[mask]) peak_pos = r[mask][peak_idx] peak_val = rdf_smoothed[mask][peak_idx] peak_info = {"position": peak_pos, "value": peak_val} else: peak_info = {"position": None, "value": None} return r, rdf_smoothed, peak_info # 3. 定义精细化的选择器函数(避免lambda序列化问题) def selector_phosphate_P_double_O(atom_types): return atom_types["phosphate_oxygens"]["P=O"] def selector_phosphate_P_OH(atom_types): return atom_types["phosphate_oxygens"]["P-OH"] def selector_phosphate_P_O(atom_types): return atom_types["phosphate_oxygens"]["P-O"] def selector_phosphate_hydrogens(atom_types): return atom_types["phosphate_hydrogens"] def selector_water_only_hydrogens(atom_types): """仅选择水分子中的氢原子""" return atom_types["water_hydrogens"] def selector_hydronium_only_hydrogens(atom_types): """仅选择水合氢离子中的氢原子""" return atom_types["hydronium_hydrogens"] def selector_water_only_oxygens(atom_types): """仅选择水分子中的氧原子""" return atom_types["water_oxygens"] def selector_hydronium_only_oxygens(atom_types): """仅选择水合氢离子中的氧原子""" return atom_types["hydronium_oxygens"] def selector_fluoride_atoms(atom_types): return atom_types["fluoride_atoms"] def selector_aluminum_atoms(atom_types): return atom_types["aluminum_atoms"] def selector_all_phosphate_oxygens(atom_types): return (atom_types["phosphate_oxygens"]["P=O"] + atom_types["phosphate_oxygens"]["P-O"] + atom_types["phosphate_oxygens"]["P-OH"]) # 4. 根据您的要求定义六张图的RDF分组配置 def get_rdf_groups(): """返回六张图的RDF分组配置(完全符合您的需求)""" return { # 图1: Al的配位情况 "Al_Coordination": [ (selector_aluminum_atoms, selector_fluoride_atoms, "Al-F", "blue"), (selector_aluminum_atoms, selector_water_only_oxygens, "Al-Ow", "green"), (selector_aluminum_atoms, selector_all_phosphate_oxygens, "Al-Op", "red") ], # 图2: F与H形成的氢键 "F_Hydrogen_Bonding": [ (selector_fluoride_atoms, selector_water_only_hydrogens, "F-Hw", "lightblue"), (selector_fluoride_atoms, selector_hydronium_only_hydrogens, "F-Hh", "blue"), (selector_fluoride_atoms, selector_phosphate_hydrogens, "F-Hp", "darkblue") ], # 图3: 磷酸作为受体与周围环境的氢键(区分氧类型) "Phosphate_Acceptor": [ (selector_phosphate_P_double_O, selector_water_only_hydrogens, "P=O···Hw", "orange"), (selector_phosphate_P_double_O, selector_hydronium_only_hydrogens, "P=O···Hh", "red"), (selector_phosphate_P_O, selector_water_only_hydrogens, "P-O···Hw", "lightgreen"), (selector_phosphate_P_O, selector_hydronium_only_hydrogens, "P-O···Hh", "green"), (selector_phosphate_P_OH, selector_water_only_hydrogens, "P-OH···Hw", "lightblue"), (selector_phosphate_P_OH, selector_hydronium_only_hydrogens, "P-OH···Hh", "blue") ], # 图4: 磷酸-水-水合氢离子交叉氢键(排除同种类型) "Cross_Species_HBonding": [ (selector_phosphate_hydrogens, selector_water_only_oxygens, "Hp···Ow", "pink"), (selector_phosphate_hydrogens, selector_hydronium_only_oxygens, "Hp···Oh", "purple"), (selector_water_only_hydrogens, selector_all_phosphate_oxygens, "Hw···Op", "lightgreen"), (selector_water_only_hydrogens, selector_hydronium_only_oxygens, "Hw···Oh", "green"), (selector_hydronium_only_hydrogens, selector_water_only_oxygens, "Hh···Ow", "lightblue"), (selector_hydronium_only_hydrogens, selector_all_phosphate_oxygens, "Hh···Op", "blue") ], # 图5: 同类型分子内/间氢键(区分磷酸氧类型) "Same_Species_HBonding": [ (selector_phosphate_hydrogens, selector_phosphate_P_double_O, "Hp···P=O", "red"), (selector_phosphate_hydrogens, selector_phosphate_P_O, "Hp···P-O", "orange"), (selector_phosphate_hydrogens, selector_phosphate_P_OH, "Hp···P-OH", "yellow"), (selector_water_only_hydrogens, selector_water_only_oxygens, "Hw···Ow", "lightblue"), (selector_hydronium_only_hydrogens, selector_hydronium_only_oxygens, "Hh···Oh", "blue") ], # 图6: O-O聚集分析(Op不区分类型) "O_O_Aggregation": [ (selector_all_phosphate_oxygens, selector_water_only_oxygens, "Op-Ow", "blue"), (selector_all_phosphate_oxygens, selector_hydronium_only_oxygens, "Op-Oh", "green"), (selector_all_phosphate_oxygens, selector_all_phosphate_oxygens, "Op-Op", "red"), (selector_water_only_oxygens, selector_hydronium_only_oxygens, "Ow-Oh", "purple"), (selector_water_only_oxygens, selector_water_only_oxygens, "Ow-Ow", "cyan"), (selector_hydronium_only_oxygens, selector_hydronium_only_oxygens, "Oh-Oh", "magenta") ] } # 5. 主程序 - 优化并行处理 def main(workers=1): # 定义要处理的体系 vasprun_files = { "System1": "vasprun1.xml", "System2": "vasprun2.xml", "System3": "vasprun3.xml", "System4": "vasprun4.xml" } # 获取RDF分组配置 rdf_groups = get_rdf_groups() # 标题映射(根据您的要求) title_map = { "Al_Coordination": "Al Coordination Environment", "F_Hydrogen_Bonding": "F-H Hydrogen Bonding", "Phosphate_Acceptor": "Phosphate as H-bond Acceptor", "Cross_Species_HBonding": "Cross H-bonding between Different Species", "Same_Species_HBonding": "Intra- and Inter-molecular H-bonding", "O_O_Aggregation": "O-O Aggregation Analysis" } # 存储所有数据 all_system_data = {} group_y_max = {group_name: 0 for group_name in list(rdf_groups.keys())} group_x_max = { "Al_Coordination": (1.5, 3.5), "F_Hydrogen_Bonding": (1.0, 3.0), "Phosphate_Acceptor": (1.0, 3.0), "Cross_Species_HBonding": (1.0, 3.0), "Same_Species_HBonding": (1.0, 3.0), "O_O_Aggregation": (2.0, 6.0) } # 创建输出目录 os.makedirs("RDF_Plots", exist_ok=True) # 计算所有体系的所有RDF数据 for system_name, vasprun_file in vasprun_files.items(): print(f"\n{'='*50}") print(f"Processing {system_name}: {vasprun_file} with {workers} workers") print(f"{'='*50}") start_time = time.time() try: # 加载VASP结果 vr = Vasprun(vasprun_file, ionic_step_skip=5) structures = vr.structures print(f"Loaded {len(structures)} frames") # 存储体系数据 system_data = { "rdf_results": {}, "peak_infos": {} } # 计算所有RDF分组 for group_name, pairs in rdf_groups.items(): system_data["rdf_results"][group_name] = {} system_data["peak_infos"][group_name] = {} group_y_max_current = 0 for center_sel, target_sel, label, color in pairs: print(f"\nCalculating RDF for: {label}") try: r, rdf, peak_info = calculate_rdf_parallel( structures, center_sel, target_sel, r_max=10.0, exclude_bonds=True, bond_threshold=1.3, workers=workers ) system_data["rdf_results"][group_name][label] = (r, rdf, color) system_data["peak_infos"][group_name][label] = peak_info if len(rdf) > 0: current_max = np.max(rdf) if current_max > group_y_max_current: group_y_max_current = current_max if peak_info["position"] is not None: print(f" Peak for {label}: {peak_info['position']:.3f} Å (g(r) = {peak_info['value']:.2f})") else: print(f" No significant peak found for {label} in 1.5-3.0 Å range") except Exception as e: print(f"Error calculating RDF for {label}: {str(e)}") system_data["rdf_results"][group_name][label] = (np.array([]), np.array([]), color) system_data["peak_infos"][group_name][label] = {"position": None, "value": None} if group_y_max_current > group_y_max[group_name]: group_y_max[group_name] = group_y_max_current all_system_data[system_name] = system_data elapsed = time.time() - start_time print(f"\nCompleted processing for {system_name} in {elapsed:.2f} seconds") except Exception as e: print(f"Error processing {system_name}: {str(e)}") # 为每个分组添加余量 for group_name in group_y_max: group_y_max[group_name] = max(group_y_max[group_name] * 1.15, 3.0) # 确保最小值 # 第二步:生成符合期刊要求的图表 for system_name, system_data in all_system_data.items(): print(f"\nGenerating publication-quality plots for {system_name}") for group_name, group_data in system_data["rdf_results"].items(): fig, ax = plt.subplots(figsize=(8, 6)) # 设置坐标轴范围 xlim = group_x_max.get(group_name, (0, 6.0)) ylim = (0, group_y_max[group_name]) for label, (r, rdf, color) in group_data.items(): if len(r) > 0 and len(rdf) > 0: ax.plot(r, rdf, color=color, label=label, linewidth=2.0) ax.set_xlim(xlim) ax.set_ylim(ylim) # 期刊格式标签 ax.set_xlabel('Radial Distance (Å)', fontweight='bold') ax.set_ylabel('g(r)', fontweight='bold') # 添加体系名称到标题 ax.set_title(f"{system_name}: {title_map[group_name]}", fontsize=16, pad=15) # 精简图例 ncol = 3 if group_name == "Same_Species_HBonding" else 1 # 图5使用三列图例 ax.legend(ncol=ncol, loc='best', framealpha=0.8, fontsize=10) # 添加氢键区域标记(除O-O聚集图外) if group_name != "O_O_Aggregation": ax.axvspan(1.5, 2.5, alpha=0.1, color='green', zorder=0) ax.text(1.7, ylim[1]*0.85, 'H-bond Region', fontsize=10) # 添加网格 ax.grid(True, linestyle='--', alpha=0.5) # 保存高分辨率图片 plt.tight_layout() filename = os.path.join("RDF_Plots", f"RDF_{system_name}_{group_name}.tiff") plt.savefig(filename, bbox_inches='tight', dpi=600, format='tiff') print(f"Saved publication plot: {filename}") plt.close() # 保存Origin兼容数据 save_origin_data(system_name, system_data) print("\nAll RDF analysis completed successfully!") def save_origin_data(system_name, system_data): """保存Origin兼容格式数据""" os.makedirs("Origin_Data", exist_ok=True) system_dir = os.path.join("Origin_Data", system_name) os.makedirs(system_dir, exist_ok=True) # 保存峰值信息 peak_info_path = os.path.join(system_dir, f"Peak_Positions_{system_name}.csv") with open(peak_info_path, 'w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(["Group", "Interaction", "Peak Position (A)", "g(r) Value"]) for group_name, peaks in system_data["peak_infos"].items(): for label, info in peaks.items(): if info["position"] is not None: writer.writerow([group_name, label, f"{info['position']:.3f}", f"{info['value']:.3f}"]) else: writer.writerow([group_name, label, "N/A", "N/A"]) print(f"Saved peak positions: {peak_info_path}") # 保存RDF数据 for group_name, group_results in system_data["rdf_results"].items(): group_dir = os.path.join(system_dir, group_name) os.makedirs(group_dir, exist_ok=True) for label, (r, rdf, color) in group_results.items(): if len(r) > 0 and len(rdf) > 0: safe_label = label.replace(" ", "_").replace("/", "_").replace("=", "_") safe_label = safe_label.replace("(", "").replace(")", "").replace("$", "") filename = f"RDF_{system_name}_{group_name}_{safe_label}.csv" filepath = os.path.join(group_dir, filename) with open(filepath, 'w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(["Distance (A)", "g(r)"]) for i in range(len(r)): writer.writerow([f"{r[i]:.6f}", f"{rdf[i]:.6f}"]) print(f"Saved Origin data: {filename}") if __name__ == "__main__": # 设置命令行参数 parser = argparse.ArgumentParser(description='Calculate RDF for VASP simulations') parser.add_argument('--workers', type=int, default=multiprocessing.cpu_count(), help=f'Number of parallel workers (default: {multiprocessing.cpu_count()})') args = parser.parse_args() print(f"Starting RDF analysis with {args.workers} workers...") main(workers=args.workers) 以上代码实现了湿法磷酸中水和水合氢离子以及磷酸之间的RDF计算,它是一个包含质子转移过程的部分。我们在这里将沿用这个框架来实现相同指令可执行的文件。我将对内容和识别逻辑进行修改,我们在这里只识别P,在识别P之后搜寻周围的O,如果P-O之间的距离小于1.8埃,则将该O视为Op。然后我们将Op作为中心原子,体系中的所有H(是整个体系中的所有H)作为目标原子计算RDF,输出文本和图。
07-12
资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 行列式是线性代数的核心概念,在求解线性方程组、分析矩阵特性以及几何计算中都极为关键。本教程将讲解如何用C++实现行列式的计算,重点在于如何输出分数形式的结果。 行列式定义如下:对于n阶方阵A=(a_ij),其行列式由主对角线元素的乘积,按行或列的奇偶性赋予正负号后求和得到,记作det(A)。例如,2×2矩阵的行列式为det(A)=a11×a22-a12×a21,而更高阶矩阵的行列式可通过Laplace展开或Sarrus规则递归计算。 在C++中实现行列式计算时,首先需定义矩阵类或结构体,用二维数组存储矩阵元素,并实现初始化、加法、乘法、转置等操作。为支持分数形式输出,需引入分数类,包含分子和分母两个整数,并提供与整数、浮点数的转换以及加、减、乘、除等运算。C++中可借助std::pair表示分数,或自定义结构体并重载运算符。 计算行列式的函数实现上,3×3及以下矩阵可直接按定义计算,更大矩阵可采用Laplace展开或高斯 - 约旦消元法。Laplace展开是沿某行或列展开,将矩阵分解为多个小矩阵的行列式乘积,再递归计算。在处理分数输出时,需注意避免无限循环和除零错误,如在分数运算前先约简,确保分子分母互质,且所有计算基于整数进行,最后再转为浮点数,以避免浮点数误差。 为提升代码可读性和可维护性,建议采用面向对象编程,将矩阵类和分数类封装,每个类有明确功能和接口,便于后续扩展如矩阵求逆、计算特征值等功能。 总结C++实现行列式计算的关键步骤:一是定义矩阵类和分数类;二是实现矩阵基本操作;三是设计行列式计算函数;四是用分数类处理精确计算;五是编写测试用例验证程序正确性。通过这些步骤,可构建一个高效准确的行列式计算程序,支持分数形式计算,为C++编程和线性代数应用奠定基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值