这是本文档旧的修订版!
因为插件是包含在 Python 模块中的,所以它们应存在于自己的目录中。我们将研究一个读取 XYZ 文件的插件作为示例。它的目录结构如下:
XYZFilters/ __init__.py XYZLabFloor.py XYZFileRawReader.py
init.py
文件是一个特殊文件,用于告诉 Python 该文件夹是一个模块。它还包含导入模块时执行的代码。对于插件,此文件还需要包含一些信息用用以告知 QuantumATK 关于它自身。
XYZFilters
附加组件中的 init.py
文件包含以下代码:
1 import datetime 2 import XYZLabFloor 3 4 __addon_description__ = "Plugins for importing and exporting XYZ configurations." 5 __addon_version__ = "1.0" 6 __addon_date__ = datetime.date(year=2015, month=8, day=6) 7 8 __plugins__ = [XYZLabFloor.XYZLabFloor] 9 10 def reloadPlugins(): 11 reload(XYZLabFloor)
此代码给出了附加组件的说明,分配版本号和上次更新的日期。它还定义了附加组件提供的插件列表。本例中,有一个 XYZLabFloor.py
文件,包含了一个名为 XYZLabFloor
的插件类。此外,还提供了一个名为 reloadPlugins
的函数,以便在源代码文件发生更改时,QuantumATK 可以重新加载插件。
我们现在来看一下包含插件类的 XYZLabFloor.py
文件的结构。在文件的顶部,我们导入了编写插件所需的模块和类:
1 import os 2 3 from API import LabFloorImporterPlugin 4 from API import LabFloorItem 5 from NL.CommonConcepts.Configurations.MoleculeConfiguration import MoleculeConfiguration 6 from NL.CommonConcepts.PeriodicTable import SYMBOL_TO_ELEMENT 7 from NL.CommonConcepts.PhysicalQuantity import Angstrom 8 from NL.ComputerScienceUtilities import Exceptions 9 10 from XYZFileRawReader import XYZFileRawReader
接下来我们需要定义插件类。插件必须从 QuantumATK 定义的特定类中继承。在这种情况下,我们将定义一个从 LabFloorImporterPlugin
继承的类:
13 class XYZLabFloor(LabFloorImporterPlugin):
这种类型的插件必须定义两种方式。第一种方式是 scan
。该方法的作用是确定插件是否处理特定文件,如果是的话,则确定该文件包含哪种类型的 LabFloor 对象。它会将项目列表返回给 LabFloor。第二种方式是 load
,负责解析文件并将对象加载到内存中。
对于我们的 XYZLabFloor
插件,scan 法定义如下:
18 def scan(self, filename): 19 """ 20 Scans a file to check if it is supported by the plugin 21 22 @param filename : The path to be scanned. 23 @type : string 24 25 @return A list of LabFloorItems 26 """ 27 # Setup a resulting vector. 28 result = [] 29 30 # Determine extension 31 basename = os.path.basename(filename) 32 no_extension_name, extension = os.path.splitext(basename) 33 34 # Return empty string if extension isn't ".xyz" 35 if extension != '.xyz': 36 return result 37 38 # Try to load configuration 39 try: 40 reader = XYZFileRawReader(filename) 41 except Exception: 42 return result 43 44 for molecule_idx in xrange(reader.numOfMolecules()): 45 46 # Read the comment for this molecule. 47 comment = reader.comment(molecule=molecule_idx) 48 49 # Create and add LabFloorItem to list 50 if reader.numOfMolecules() == 1: 51 title = no_extension_name 52 else: 53 title = no_extension_name + " (" + str(molecule_idx) + ")" 54 55 # Create labfloor item. 56 item = LabFloorItem(MoleculeConfiguration, 57 title=title, 58 tool_tip=comment, 59 molecule_idx=molecule_idx) 60 61 # Add to result list. 62 result.append(item) 63 64 # Return the result list. 65 return result
该代码通过首先测试文件名中是否含有 “xyz” 的扩展名,然后尝试实际解析文件来检测文件是否为有效的 XYZ 文件。如果文件不是有效的 XYZ 文件,则返回空列表。如果它是有效文件,则读入文件中包含的每个分子,并为每个分子创建 LabFloorItem
。
LabFloorItem
是一个 LabFloor 上表示项目的分类。它包含对象的类型,在本例中,它是 MoleculeConfiguration
以及标题和工具提示(当鼠标光标悬停在项目上时可见的文本)。有关该项目的额外信息也可以作为关键参数传递。正如我们将在下面看到的,这些参数将传递给 load 方式。
当用户与项目交互时,QuantumATK 会调用 load 方式。例如,当使用 viewer 可视化结构或将其导入 builder 时会发生这种情况。Load 法的定义为:
67 def load(self, filename, molecule_idx=0): 68 """ 69 Load the desired object in memory. 70 71 @param filename : The path of the XYZ-file. 72 @type : string 73 74 @return Desired object (MoleculeConfiguration) 75 """ 76 # Read the file 77 reader = XYZFileRawReader(filename) 78 79 # Lists of elements and positions. 80 elements = [] 81 positions = [] 82 83 # Loop over atoms. 84 for atom in reader.atomList(molecule=molecule_idx): 85 elements.append(SYMBOL_TO_ELEMENT[atom["element"]]) 86 positions.append(atom["coords"]*Angstrom) 87 88 # Create configuration. 89 configuration = MoleculeConfiguration( 90 elements=elements, 91 cartesian_coordinates=positions) 92 93 return configuration
该方式读取文件内容并提取所要求分子的元素和位置。该方法被传递了要读取分子的索引(信息存储在 scan
式中创建的 LabFloorItem
中)并创建了一个 MoleculeConfiguration。MoleculeConfiguration 类是 QuantumATK 中表示分子的方式。对于周期系统,有一个相应的 BulkConfiguration 类,用于存储晶格矢量以及坐标和元素。
此附加组件的完整源代码可在此处下载 ↓ source code。