如何处理数据¶
导入数据¶
AiiDA允许用户将数据从数据库导出到归档文件,归档文件可以导入到任何其他AiiDA数据库中。如果你有一个想要导入的AiiDA导出存档,你可以使用 verdi archive import
命令(详见 参考章节 )。
注解
有关通过AiiDA档案导出和导入数据的信息,请参见 如何共享数据。
相反,如果您拥有尚未成为AiiDA导出归档的一部分的现成数据,例如文件、文件夹、表格数据、数组或任何其他类型的数据,此操作指南将向您展示如何将它们导入AiiDA。
要在AiiDA中存储任何数据,需要将其包装在 Data
节点。可验证性图这样它可以在 可验证性图 中表示。这个``Data``类有不同的变种或子类,它们适用于不同类型的数据。AiiDA提供了许多内置数据类型。你可以使用 verdi plugin 命令列出这些插件。执行 verdi plugin list aiida.data
应显示如下内容:
Registered entry points for aiida.data:
* array
* bool
* code
* dict
* float
* folder
* list
* singlefile
Info: Pass the entry point as an argument to display detailed information
如输出所示,您可以通过在命令后面附加名称来获得关于每种类型的更多信息,例如, verdi plugin list aiida.data singlefile
:
Description:
The ``singlefile`` data type is designed to store a single file in its entirety.
A ``singlefile`` node can be created from an existing file on the local filesystem in two ways.
By passing the absolute path of the file:
singlefile = SinglefileData(file='/absolute/path/to/file.txt')
or by passing a filelike object:
with open('/absolute/path/to/file.txt', 'rb') as handle:
singlefile = SinglefileData(file=handle)
The filename of the resulting file in the database will be based on the filename passed in the ``file`` argument.
This default can be overridden by passing an explicit name for the ``filename`` argument to the constructor.
如所见, singlefile
类型对应于 SinglefileData`类,被用于包装存储在本地文件系统上的单个文件。如果你有这样一个单独的文件,想将其存储在AiiDA中,你可以使用``verdi shell`
创建它:
SinglefileData = DataFactory('singlefile')
singlefile = SinglefileData(file='/absolute/path/to/file.txt')
singlefile.store()
第一步是加载与数据类型对应的类,这是通过将名称(由``verdi plugin list aiida.data``列出)传递给:DataFactory
来完成的。然后构造该类的一个实例,将感兴趣的文件作为参数传递。
注解
构造任何特定数据类型实例的确切方式取决于类型。使用``verdi plugin list aiida.data <ENTRY_POINT>``。命令获取任何特定类型的更多信息。
注意,在构造之后,您将获得一个 未存储的 节点。这意味着此时您的数据还没有存储在数据库中,您可以首先检查它并有自定义地修改它。如果您对结果满意,您可以通过调用 store()
来永久存储新数据。每个节点在创建时都分配了一个通用唯一标识符(UUID),存储后还分配了一个主键(PK),可以通过UUID和PK检索主键。您可以使用这些标识符来引用或检索节点。查找和检索以前导入的数据的方法在 如何查找数据 一节中描述。
如果 verdi plugin list
列出的类型中没有你可用的数据类型,适合你的需要,你也可以创建自己的自定义类型。详细信息请参考下一节 如何添加自定义数据类型的支持。
查找和查询数据¶
一旦您成功地完成了项目的一系列工作流,或者导入了您感兴趣的数据集,您就会希望快速找到与您的分析相关的数据。AiiDA数据库中的数据以连接的图的形式存储,可以通过:class:~aiida.orm.querybuilder.QueryBuilder 轻松地 查询 。
The QueryBuilder
lets you query your AiiDA database independently of the backend used under the hood.
Before starting to write a query, it helps to:
知道你想要查询什么。在数据库语言中,你需要告诉后端你正在寻找什么 实体 ,以及你想要*投影*它的哪个属性。例如,您可能对「算例」的标签和其所有输出的PK感兴趣。
知道你感兴趣的数据实体之间的关系。AiiDA图中的节点(顶点,即vertices)是由链接连结的(边,即edges)。一个 节点 可以作为另一个 节点 的输入或输出,也可以是始祖或者后代。
知道您希望如何过滤查询结果。
一旦你清楚了你想要什么和你如何能得到它, QueryBuilder
将为您构建一个sql查询。
有两种使用 QueryBuilder
的方法:
在 追加查询条件 的方法中,使用 QueryBuilder.append()` 方法逐步构造查询。
在 queryhelp 方法中,你构造一个字典来定义你的查询,并将它传递给
QueryBuilder
。
这两个api提供相同的功能- 追加条件的方法可能更适合交互式使用,例如,在 verdi shell
,而queryhelp方法在脚本中更常用。在本节中,我们将重点介绍追加条件方法的基础知识。有关高级查询或queryhelp的更多详细信息,请参见 高级查询部分 。
选择查询实体¶
使用 QueryBuilder
的``append()`` 方法,你可以查询你感兴趣的实体。假设您想查询数据库中的「算例」作业节点:
from aiida.orm import QueryBuilder
qb = QueryBuilder() # Instantiating instance. One instance -> one query
qb.append(CalcJobNode) # Setting first vertex of path
如果您对不同类的实例感兴趣,您也可以传递一个类的可迭代对象。但是,它们必须是相同的ORM类型(例如,必须是 Node
的子类):
qb = QueryBuilder() # Instantiating instance. One instance -> one query
qb.append([CalcJobNode, WorkChainNode]) # Setting first vertices of path, either WorkChainNode or Job.
注解
「列程」都有一个运行时:class:~aiida.engine.processes.process.Process 用以执行进程和一个 Node
其将数据存储在数据库中(详细说明请参见 相应的主题部分)。:类 QueryBuilder
允许你传递:class:~aiida.orm.nodes.node.Node 类(例如:class:~aiida.orm.nodes.process.calculation.calcjob.CalcJobNode )或:Process
类(例如:class:~aiida.engine.processes.calcjobs.calcjob.CalcJob),它将自动为查询选择正确的数据实体。使用:class:~aiida.orm.nodes.process.calculation.calcjob.CalcJobNode 或 CalcJob
将产生相同的查询结果。
结果检索¶
一旦你将你想要查询的实体 缀加 到 QueryBuilder
,下一个问题是如何得到结果。有几种方法可以从查询中获取数据:
qb = QueryBuilder() # Instantiating instance
qb.append(CalcJobNode) # Setting first vertices of path
first_row = qb.first() # Returns a list (!) of the results of the first row
all_results_d = qb.dict() # Returns all results as a list of dictionaries
all_results_l = qb.all() # Returns a list of lists
如果你正在处理一个大型数据集,你可以返回你的查询作为一个生成器:
all_res_d_gen = qb.iterdict() # Return a generator of dictionaries
# of all results
all_res_l_gen = qb.iterall() # Returns a generator of lists
这将批量检索数据,您可以在查询完全完成之前开始处理数据。例如,你可以在For循环中遍历你的查询结果:
for entry in qb.iterall():
# do something with a single entry in the query result
过滤器¶
通常您不希望查询某个类的 所有 数据实体,而是根据某些属性*过滤*结果。假设您不需要所有:class:~aiida.orm.nodes.process.calculation.calcjob.CalcJobNode ,而只有那些是 finished
状态的数据:
qb = QueryBuilder() # Initialize a QueryBuilder instance
qb.append(
CalcJobNode, # Append a CalcJobNode
filters={ # Specify the filters:
'attributes.process_state': 'finished', # the process is finished
},
)
可以对查询中的一个实体应用多个筛选器。假设你对数据库中所有已经 完成
的并且有 exit_status == 0
的计算作业感兴趣,:
qb = QueryBuilder() # Initialize a QueryBuilder instance
qb.append(
CalcJobNode, # Append a CalcJobNode
filters={ # Specify the filters:
'attributes.process_state': 'finished', # the process is finished AND
'attributes.exit_status': 0 # has exit_status == 0
},
)
如果你想查询只要满足其中一个条件的「算例」作业,你可以使用 or
操作符:
qb = QueryBuilder()
qb.append(
CalcJobNode,
filters={
'or':[
{'attributes.process_state': 'finished'},
{'attributes.exit_status': 0}
]
},
)
如果我们在上面的例子中写了``and``而不是 or
,我们将执行与前一个完全相同的查询,因为 and``是默认的行为,如果你在字典中为'``filters``参数提供几个键值对的过滤器。如果你想要所有状态为``finished``或``excepted``的计算作业,你也可以使用 ``in
操作符:
qb = QueryBuilder()
qb.append(
CalcJobNode,
filters={
'attributes.process_state': {'in': ['finished', 'excepted']}
},
)
可以通过在运算符前添加感叹号来否定过滤器。因此,要查询所有状态不为``finished`` 或 ``excepted``的计算作业:
qb = QueryBuilder()
qb.append(
CalcJobNode,
filters={
'attributes.process_state': {'!in': ['finished', 'excepted']}
},
)
注解
上述规则适用于所有操作符。例如,你可以用``!==`` 来作不等价操作,因为这是带有否定前缀的相等操作符(==
)。
所有可用运算符的完整列表可以在:ref:`高级查询部分<topics:database:advancedquery:tables:operators>`中找到。
关系查找¶
可以根据数据与数据库中另一个实体的关系来查询数据。假设您对算例作业本身不感兴趣,而是对它们创建的一个输出感兴趣。你可以对所有 CalcJobNode
建立你的初始查询,在数据库中使用输出到查询的第一步的关系:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob')
qb.append(Int, with_incoming='calcjob')
在第一个``append``调用中,我们查询所有:class:~aiida.orm.nodes.process.calculation.calcjob.CalcJobNode,并 标记 这一步与 唯一 标识符 'calcjob'
。接下来,我们寻找:CalcJobNode
’ 输出的所有 Int
节点。使用 with_incoming
关系参数。Int
节点是由 CalcJobNode
创建的并与之有一个 incoming 创建类型的链接。
在我们的查询上下文中,我们构建了一个由*顶点*(即我们要查询的实体)组成的 路径 ,这些顶点由 边 (由它们之间的关系定义)连接。你可以使用query查询所有可能的关系的完整集合,以及它们连接到的实体,更多相关指令可以在 :ref:`进阶查找章节 <topics:database:advancedquery:tables:relationships>`中找到。
注解
tag
标识符可以是任何字母数字字符串,它只是一个标签,用于在定义关系时引用查询路径上的前一个顶点。
投影¶
默认情况下,QueryBuilder
返回与查询路径的最终附加项相对应的实体实例。例如:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob')
qb.append(Int, with_incoming='calcjob')
上面的代码片段将返回所有``Int``节点,它们是 CalcJobNode
的输出。但是,你也可以通过在对应的``append()`` 调用中添加``project=’*’``来 投影 路径中的其他实体:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob', project='*')
qb.append(Int, with_incoming='calcjob')
这将返回所有,有一个 Int
输出节点的:class:`~aiida.orm.nodes.process.calculation.calcjob.CalcJob
然而,在许多情况下,我们对实体本身并不感兴趣,而是对它们的PK、UUID、 属性 或实体存储的其他一些信息感兴趣。这可以通过向``project``关键字参数提供相应的 列 来实现:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob')
qb.append(Int, with_incoming='calcjob', project='id')
在上面的例子中,执行查询返回``Int``节点的所有:class:~aiida.orm.nodes.process.calculation.calcjob.CalcJobNode 类的 主键PK ,此外,你可以通过提供一个列表来为一个顶点投射多个信息:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob')
qb.append(Int, with_incoming='calcjob', project=['id', 'attributes.value'])
对于上面的查询,qb.all()
将返回一个列表的列表,其中每个元素对应于一个实体并包含两项: Int
节点的PK及其值。最后,你可以沿着查询路径投影多个顶点的信息:
qb = QueryBuilder()
qb.append(CalcJobNode, tag='calcjob', project='*')
qb.append(Int, with_incoming='calcjob', project=['id', 'attributes.value'])
所有投影必须以数据库中实体的 列 之一开始,或者使用``’*’`` 投影实例本身。到目前为止,我们遇到的列的例子是``id``, uuid
和 attributes
。如果列是一个字典,您可以使用点号展开字典值,就像我们在前面的示例中所做的那样,以获得``attributes.value``。这还可以用于投影嵌套字典的值。
注解
请注意,为了一致性,QueryBuilder.all()
/ iterall()
总是返回列表的列表,即使您只投射单个实体的一个属性。在本例中,使用 QueryBuilder.all(flat=True)
以平面列表的形式返回查询结果。
正如前面提到的,本节只提供了对:class:~aiida.orm.querybuilder.QueryBuilder`的简要介绍。要了解更多高级查询,请参见:ref:`相应的主题部分<topics:database:advancedquery>。
组织数据¶
如何对节点进行分组¶
AiiDA的数据库非常适合自动存储您的所有数据,但有时浏览这样一个平面数据存储可能比较棘手。为了在大量数据中创建一些顺序,您可以将节点集 分组 在一起,就像您在文件系统中的文件夹中处理文件一样。在这个类比中,文件夹由 Group
表示。每个组实例可以容纳任意数量的节点,任意节点可以包含在任意数量的组中。一个典型的用例是在一个组中存储共享公共属性的所有节点。
下面我们将展示如何对组执行一组可执行的典型操作。
创建新组¶
使用命令行接口:
$ verdi group create test_group
使用python接口:
In [1]: group = Group(label='test_group')
In [2]: group.store()
Out[2]: <Group: "test_group" [type core], of user xxx@xx.com>
*列出所有可用组¶
例如:
$ verdi group list
组有不同的类型,由它们的类型字符串表示。默认情况下 verdi group list
只显示类型为 core 的组。如果你想显示另一种类型的组,请使用 -T/--type-string
选项。如果要显示所有类型的组,请使用 -a/--all-types
选项。
例如,列出类型为``core.auto`` 的组,使用:
$ verdi group list -T core.auto
类似地,我们可以使用``QueryBuilder`` 的 type_string
键来’筛选组:
In [1]: QueryBuilder().append(Group, filters={'type_string': 'core'}).all(flat=True)
Out[1]:
[<Group: "another_group" [type core], of user xxx@xx.com>,
<Group: "old_group" [type core], of user xxx@xx.com>,
<Group: "new_group" [type core], of user xxx@xx.com>]
将节点加入组¶
一旦创建了``test_group`` ,我们就可以向它添加节点。例如,要向组中添加一个``pk=1`` 的节点,我们可以使用命令行:
$ verdi group add-nodes -G test_group 1
Do you really want to add 1 nodes to Group<test_group>? [y/N]: y
或者Python接口:
In [1]: group.add_nodes(load_node(pk=1))
显示关于组的信息¶
使用命令行接口:
$ verdi group show test_group
----------------- ----------------
Group label test_group
Group type_string user
Group description <no description>
----------------- ----------------
# Nodes:
PK Type Created
---- ------ ---------------
1 Code 26D:21h:45m ago
从组中移除节点¶
使用命令行接口:
$ verdi group remove-nodes -G test_group 1
Do you really want to remove 1 nodes from Group<test_group>? [y/N]: y
使用python接口:
In [1]: group = load_group(label='test_group')
In [2]: group.remove_nodes([load_node(1)])
或者,您可能希望从组中删除 所有 节点。在命令行中你只需要添加 -c/--clear
选项到 verdi group remove-nodes ..
$ verdi group remove-nodes -c -G test_group
Do you really want to remove ALL the nodes from Group<test_group>? [y/N]:
在Python接口中,你可以使用 .clear()
方法来实现相同的目标:
In [1]: group = load_group(label='test_group')
In [2]: group.clear()
重命名组¶
使用命令行接口:
$ verdi group relabel test_group old_group
Success: Label changed to old_group
使用python接口:
In [1]: group = load_group(label='old_group')
In [2]: group.label = 'another_group'
删除组¶
使用命令行接口:
$ verdi group delete another_group
Are you sure to delete Group<another_group>? [y/N]: y
Success: Group<another_group> deleted.
默认情况下,任何与组相关的删除操作都不会影响节点本身。例如,如果您删除一个组,属于该组的节点将保留在数据库中。如果从组中删除节点,也会发生同样的情况——这些节点将保留在数据库中,但不再属于组。
如果你也想删除节点,在删除组时,使用 ``–delete-nodes``选项:
$ verdi group delete another_group --delete-nodes
将一个组拷贝为其他组¶
此操作将把原来的组的内容复制到目标组中。此外,如果目标组不存在,将自动创建它。
使用命令行接口:
$ verdi group copy source_group dest_group
Success: Nodes copied from group<source_group> to group<dest_group>
使用python接口:
In [1]: src_group = Group.objects.get(label='source_group')
In [2]: dest_group = Group(label='destination_group').store()
In [3]: dest_group.add_nodes(list(src_group.nodes))
使用组的例子¶
在本节中,我们将提供一些实际示例,说明如何使用组来组织和结构化数据库中的节点。
使用类似属性对晶体结构进行分组¶
假设,我们想把所有计算出的带隙大于 ``1.0 eV``的结构分组到一个名为``promising_structures``的组中,可以使用以下方法:
# Finding the structures with the bandgap > 1.0.
qb = QueryBuilder()
qb.append(StructureData, tag='structure', project='*') # Here we are projecting the entire structure object
qb.append(CalcJobNode, with_incoming='structure', tag='calculation')
qb.append(Dict, with_incoming='calculation', filters={'attributes.bandgap': {'>': 1.0}})
# Adding the structures in 'promising_structures' group.
group = load_group(label='promising_structures')
group.add_nodes(q.all(flat=True))
注解
任何节点只能被包含在一个组中一次,如果再次添加,它将被忽略。这意味着可以安全地多次调用add_nodes,并且只添加不属于该组的节点。
使用分组数据进行进一步处理¶
这里我们演示了如何提交所有属于名为``promising_structures``组的结构的计算:
# Querying the structures that belong to the 'promising_structures' group.
qb = QueryBuilder()
qb.append(Group, filters={'label': 'promising_structures'}, tag='group')
qb.append(StructureData, with_group='group')
# Submitting the simulations.
for structure in qb.all(flat=True):
builder = SomeWorkChain.get_builder()
builder.structure = structure
...
submit(builder)
但是要注意,我们也可以使用 group.nodes
来访问组中的节点。要达到上述相同的结果,你需要做以下事情:
group = load_group(label='promising_structures')
# Here make sure to include only structures, as group can contain any nodes.
structures = [s for s in group.nodes if isinstance(nodes, StructureData)]
for structure in structures:
builder = SomeWorkChain.get_builder()
builder.structure = structure
...
submit(builder)
要找到属性``property_a`` 值小于 1
且属于``promising_structures`` 组的所有结构,可以构建如下查询:
qb = QueryBuilder()
qb.append(Group, filters={'label': 'promising_structures'}, tag='group')
qb.append(StructureData, with_group='group', tag='structure', project='*')
qb.append(SomeWorkChain, with_incoming='structure', tag='calculation')
qb.append(Dict, with_incoming='calculation', filters={'attributes.property_a': {'<': 1}})
qb.all(flat=True)
的返回值将包含符合上述条件的所有结构。
按层级关系组织组¶
AiiDA中的组本质上是“扁平的”,即组可能只包含节点而不包含其他组。但是,使用 GroupPath
工具可以基于分隔标签构造 虚拟 组层次结构
GroupPath
的工作方式与Python的 pathlib.Path
很相似。因此路径在组标签中由正斜杠 ‘/’ 表示。
例如,我们有这样的组:
$ verdi group list
PK Label Type string User
---- ----------------- ------------- --------------
1 base1/sub_group1 core user@email.com
2 base1/sub_group2 core user@email.com
3 base2/other/sub_group3 core user@email.com
我们也可以从命令行访问它们:
$ verdi group path ls -l
Path Sub-Groups
--------- ------------
base1 2
base2 1
$ verdi group path ls base1
base1/sub_group1
base1/sub_group2
或使用python接口:
In [1]: from aiida.tools.groups import GroupPath
In [2]: path = GroupPath("base1")
In [3]: print(list(path.children))
Out[3]: [GroupPath('base1/sub_group2', cls='<class 'aiida.orm.groups.Group'>'),
GroupPath('base1/sub_group1', cls='<class 'aiida.orm.groups.Group'>')]
The GroupPath
can be constructed using indexing or “divisors”:
In [4]: path = GroupPath()
In [5]: path["base1"] == path / "base1"
Out[5]: True
使用 browse()
属性,也可以将路径构造为前面的属性。这在交互式环境中很有用,可用路径将显示在tab补全中:
In [6]: path.browse.base1.sub_group2()
Out[6]: GroupPath('base1/sub_group2', cls='<class 'aiida.orm.groups.Group'>')
检查path元素是否存在:
In [7]: "base1" in path
Out[7]: True
一个组可以是“虚拟的”,在这种情况下,它的标签并不直接与一个组相关,或者可以通过 get_group()
方法来检索这个组。
In [8]: path.is_virtual
Out[8]: True
In [9]: path.get_group() is None
Out[9]: True
In [10]: path["base1/sub_group1"].is_virtual
Out[10]: False
In [11]: path["base1/sub_group1"].get_group()
Out[11]: <Group: "base1/sub_group1" [type core], of user user@email.com>
组可以创建和销毁:
In [12]: path["base1/sub_group1"].delete_group()
In [13]: path["base1/sub_group1"].is_virtual
Out[13]: True
In [14]: path["base1/sub_group1"].get_or_create_group()
Out[14]: (<Group: "base1/sub_group1" [type core], of user user@email.com>, True)
In [15]: path["base1/sub_group1"].is_virtual
Out[15]: False
要遍历路径,请使用 children()
。对于递归遍历,使用 walk()
:
In [16]: for subpath in path.walk(return_virtual=False):
...: print(subpath)
...:
GroupPath('base1/sub_group1', cls='<class 'aiida.orm.groups.Group'>')
GroupPath('base1/sub_group2', cls='<class 'aiida.orm.groups.Group'>')
GroupPath('base2/other/sub_group3', cls='<class 'aiida.orm.groups.Group'>')
你也可以直接遍历路径的节点,可选按节点类和 构建查询器 允许的任何其他筛选方式:
In [17]: from aiida.orm import Data
In [18]: data = Data()
In [19]: data.set_extra("key", "value")
In [20]: data.store()
Out[20]: <Data: uuid: 0adb5224-585d-4fd4-99ae-20a071972ddd (pk: 1)>
In [21]: path["base1/sub_group1"].get_group().add_nodes(data)
In [21]: next(path.walk_nodes(node_class=Data, filters={"extras.key": "value"}))
Out[21]: WalkNodeResult(group_path=GroupPath('base1/sub_group1', cls='<class 'aiida.orm.groups.Group'>'),
node=<Data: uuid: 0adb5224-585d-4fd4-99ae-20a071972ddd (pk: 1)>)
最后,你也可以指定 Group
子类(如上所述):
In [22]: from aiida.orm import UpfFamily
In [23]: path2 = GroupPath(cls=UpfFamily)
In [24]: path2["base1"].get_or_create_group()
Out[24]: (<UpfFamily: "base1" [type core.upf], of user user@email.com>, True)
重要
GroupPath
实例只会识别实例化的 cls
类型的组。默认 cls
是 aiida.orm.Group
:
In [25]: orm.UpfFamily(label="a").store()
Out[25]: <UpfFamily: "a" [type core.upf], of user user@email.com>
In [26]: GroupPath("a").is_virtual
Out[26]: True
In [27]: GroupPath("a", cls=orm.UpfFamily).is_virtual
Out[27]: False
删除数据¶
默认情况下,每当您运行或提交一个新的计算时,AiiDA将在数据库中为您创建新的节点,并且永远不会替换或删除数据。但是,在某些情况下,删除不再有用的节点可能是有用的,例如测试运行或不正确/错误的数据和计算。对于这种情况,AiiDA提供了 verdi node delete
命令和 delete_nodes()
函数,从可验证性图删除节点。
警告
一旦数据被删除,就没有办法恢复它了(除非您做了备份)。
重要的是,请注意,即使您要求只删除一个节点, verdi node delete
通常会删除许多附加的链接节点,以保持可验证性图的一致状态。例如,如果您删除一个算例的输入,AiiDA也将删除计算本身(否则您将在可验证性图中有效地更改该计算的输入)。完整的一致性规则将在 这里 详细解释。
因此:总是检查 verdi node delete
的输出,以确保它所删除的内容没有超出您的预期。您还可以使用 verdi node delete
的 --dry-run
标志来查看该命令将做什么,而不执行任何实际操作。
此外,还有许多附加规则,它们不是强制性的,但可以由用户进行切换。例如 ,如果在删除计算时,您也想删除它产生的数据,您可以设置 --create-forward
(使用 --no-create-forward
将只删除计算,保留输出数据: 注意,这有效地删除了输出数据的来源信息)。这些标志的完整列表可以从帮助命令 verdi node delete -h
中获得。
from aiida.tools import delete_nodes
pks_to_be_deleted = delete_nodes(
[1, 2, 3], dry_run=True, create_forward=True, call_calc_forward=True, call_work_forward=True
)
删除计算机¶
要删除一台计算机,你可以使用 verdi computer delete
。如果在创建计算机之后,您发现出现了一个错误并想要删除它,那么这个命令非常有用。特别要注意的是,如果计算机已经被至少一个节点使用过, verdi computer delete
将无法执行。在这种情况下,您需要使用 verdi node delete
先删除相应的节点。
删除可变数据¶
AiiDA中的数据子集在存储节点之后也是可变的,用户可以方便地对数据进行标记/分组/注释。这些数据可以在任何时候安全地删除。这包括:
节点额外属性:可以使用
delete_extra()
和delete_extra_many()
方法删除。节点注释:可以使用
remove_comment()
删除这些注释。组:可以使用 :py:meth:`Group.objects.delete() ` 删除。该命令将只删除组,而不删除组中包含的节点。
完全删除AiiDA的某个配置文件¶
如果您不想有选择地删除一些节点,而是想删除整个AiiDA配置文件,请使用 verdi profile delete
命令。这个命令将删除文件存储库和数据库。
危险
除非先前备份过,否则不可能恢复已删除的配置文件!
传输数据¶
1.6.0 新版功能.
危险
这个特性仍然是测试版,它的API在不久的将来可能会改变。因此,不建议您在公共/生产工作流中依赖它。
此外,我们非常感谢对其进行反馈(请登录https://github.com/aiidateam/aiida-core/issues/4811)。
当启动一个计算作业时,AiiDA将创建一个 RemoteData
节点,其将作为输出节点附加到带有标签 remote_folder
的计算节点。由 CalcJob
插件生成的输入文件被复制到这个远程文件夹中,因为作业也是在那里执行的,代码也会在同一个远程文件夹中生成它的输出文件。因为 RemoteData
节点只显式地在远程计算机上存储文件路径,而不是它的实际内容,它的功能或多或少像一个符号链接。这意味着如果远程文件夹被删除,将无法检索其内容。因此, CalcJob
插件可以指定一些文件,这些文件应该是可 检索 的,并存储 FolderData
节点,并且它作为带有标签 retrieved_folder
的输出附加到计算节点。
尽管 检索列表 允许指定在本地检索什么输出文件,但这必须在 提交计算之前 完成。为了提供更多的灵活性来决定,即使在它终止之后,已完成的计算作业的哪些文件要存储在本地,AiiDA还附带了 TransferCalculation
插件。这个计算插件可以从远程计算机检索文件,并将它们保存在本地 FolderData
中。复制内容的规范是通过类型输入提供的
In [1]: instructions_cont = {}
... instructions_cont['retrieve_files'] = True
... instructions_cont['symlink_files'] = [
... ('node_keyname', 'source/path/filename', 'target/path/filename'),
... ]
... instructions_node = orm.Dict(dict=instructions_cont)
The 'source/path/filename'
and 'target/path/filename'
are both relative paths (to their respective folders).
The node_keyname
is a string that will be used when providing the source RemoteData
node to the calculation.
You also need to provide the computer between which the transfer will occur:
In [2]: transfer_builder = CalculationFactory('core.transfer').get_builder()
... transfer_builder.instructions = instructions_node
... transfer_builder.source_nodes = {'node_keyname': source_node}
... transfer_builder.metadata.computer = source_node.computer
这里的变量 source_node
对应于需要检索其内容的 RemoteData
节点。最后,你只是运行或提交计算,就像你做任何其他操作:
In [2]: from aiida.engine import submit
... submit(transfer_builder)
你也可以用它将本地文件复制到一个新的 RemoteData
文件夹中。为此,你首先必须调整指令,将 'retrieve_files'
设置为 False
,并使用 'local_files'
列表,而不是 'symlink_files'
:
In [1]: instructions_cont = {}
... instructions_cont['retrieve_files'] = False
... instructions_cont['local_files'] = [
... ('node_keyname', 'source/path/filename', 'target/path/filename'),
... ]
... instructions_node = orm.Dict(dict=instructions_cont)
还需要注意的是,在本例中, source_node
的类型为 FolderData
所以你必须手动选择你想要复制文件的电脑。你可以通过运行 verdi computer list
查看可用计算机,并使用如 load_computer()
下所示的标签来加载:
In [2]: transfer_builder.metadata.computer = load_computer('some-computer-label')
无论是上传还是检索,你都可以复制多个文件,方法是将它们分别添加到指令输入中的 local_files
或 symlink_files
键的列表中。通过提供多个 source_node
,每个``source_node`` 都有一个不同的 'node_keyname'
。也可以从任意数量的节点复制文件,而目标节点总是一个(因此您可以在单个调用中 “收集” 文件,但不能 “分发” 文件)。