Troubleshooting
This page covers a few issues that may occur when using CrystalNets.jl. If your problem is not mentioned here, you can open an issue.
How can I silence warnings or remove exports?
- From the module: see
CrystalNets.toggle_warning
andCrystalNets.toggle_export
- From the executable: use the
--no-warn
and--no-export
flags.
For exports, each export_...
keyword argument to Options
can be individually set to false
or ""
to silence this particular export. See also the paragraph on export options.
How can I check that the detected topology corresponds to my input?
This is the focus of the Visualization tutorial.
How can I choose a particular clustering algorithm?
Pass the appropriate option from Clustering
to the clusterings
keyword argument of Options
, or use the -c
flag from the executable. For example, to compute the topology of UiO-66 with the Points-of-Extension (PE) clustering algorithm, do
julia> path_to_uio66 = joinpath(dirname(dirname(pathof(CrystalNets))), "test", "cif", "UiO-66.cif");
julia> determine_topology(path_to_uio66; structure=StructureType.MOF, clusterings=[Clustering.PE])
PE: ubt
The clusterings
keyword argument accepts a list of Clustering
s you can check multiple clusterings at once while factoring useless computations. For example:
julia> determine_topology(path_to_uio66; structure=StructureType.MOF, clusterings=[Clustering.Standard, Clustering.Auto])
Standard: xbi
AllNodes, SingleNodes: fcu
Note that Auto
is equivalent to both AllNodes
and SingleNodes
when the StructureType
is set to MOF
.
See below for the reason why the Standard
topology is xbi and not ToposPro's "3,4,8T15".
CrystalNets.jl incorrectly detects bonds or reports a periodic structure as "non-periodic"
You can use the Visualization tutorial to identify which bonds are incorrectly detected or missing.
Check that the input file is clean: if an atom is represented in multiple possible positions for instance (as is common in CIF files), CrystalNets.jl could mistake them as multiple atoms, which may break some heuristics of the bond-detection algorithm. Solvent residues may also be incorrectly bonded in some circumstances and should be removed. The ignore_atoms
keyword argument in the [Options
] may be useful in this regard.
You may want to provide a different structure
keyword argument in the Options
taken among the possible instances of StructureType
. These can modify the default heuristics for bond-guessing: for example, using structure=StructureType.MOF
gives metals a larger radius for the purpose of guessing bonds.
There are several customizable heuristics for bond-guessing available among the Options
. Of particular interest are cutoff_coeff
, ignore_homoatomic_bonds
and several of the options in the "Miscellaneous" section.
If nothing works, the last solution consists in providing an input file with explicit bonds set, and use the bonding=Input
keyword argument to Options
.
The topology has a name given by ToposPro but CrystalNets.jl yields "UNKNOWN ..."
In CrystalNets.jl, a net is identified if the graph of the crystal is isomorphic to the net. This correspondence is exact and the algorithm can only fail in case of unstable nets, which are reported as such. To do so, CrystalNets.jl actually solves the more complex graph canonicalization problem which consists in finding a "genome" (a sequence of numbers) provably unique for each net and such that two isomorphic nets have the same genome. Each genome is then associated with a name. See this article for more information on the implementation in the program Systre, from which CrystalNets.jl is derived.
ToposPro does not exactly solve the periodic graph isomorphism problem: instead, it identifies the graph of a crystal as a known net if both share a number of properties (coordination sequences up to a certain point, point symbols and vertex symbols, see this article). This is usually an excellent approximation, but it is mathematically unsound as there may exist two non-isormorphic nets sharing these three properties. In particular, this means that there cannot be a unique topological genome defined for these "nets" recognized by ToposPro. As a consequence, they cannot be used by CrystalNets.jl.
Why is the topology computed with Standard different from ToposPro's standard?
While both algorithms usually align, the result may not be the same in all cases because they are not defined in the same way.
Most often, the difference will come from either:
- an oxygen atom having three (or more) bonds becomes a vertex for ToposPro but is removed by CrystalNets.jl. To solve this, use
split_O_vertex=false
in theOptions
. - a paddle-wheel pattern is grouped into a single cluster by CrystalNets.jl but not by ToposPro. To solve this, use
detect_paddlewheels=false
in theOptions
.
How can I do a database topology analysis with CrystalNets.jl?
The built-in way to do this consists in using the determine_topology_dataset
function, or guess_topology_dataset
in some cases. These functions expect the path of a directory containing CIF files within (possibly in subdirectories).
How can I directly access the genome of my structure instead of its name?
The result of determine_topology
is either a TopologicalGenome
or a Vector{Tuple{Vector{Int},TopologyResult}}
, depending on whether the input contains multiple interpenetrating subnets or not. In the second case, extract the relevant TopologyResult
.
A TopologyResult
can store the result for different clustering options, so the topological genome should be chosen by extracting the relevant result. For example:
julia> path_to_im19 = joinpath(dirname(dirname(pathof(CrystalNets))), "test", "cif", "IM-19.cif");
julia> result = determine_topology(path_to_im19; structure=StructureType.MOF)
AllNodes: rna
SingleNodes: bpq
julia> typeof(result)
TopologyResult
julia> genome_allnodes = result[Clustering.AllNodes]
rna
julia> typeof(genome_allnodes)
TopologicalGenome
In case where all clusterings lead to the same genome, it can simply be accessed by calling first(result)
.
Having obtained a TopologicalGenome
, the topological genome itself can accessed by converting it to a PeriodicGraph
:
julia> genome = PeriodicGraph(genome_allnodes)
PeriodicGraph3D(6, PeriodicEdge3D[(1, 2, (0,0,0)), (1, 3, (0,0,0)), (1, 4, (0,0,0)), (1, 4, (0,0,1)), (1, 5, (0,0,0)), (1, 6, (0,0,0)), (2, 4, (0,0,1)), (2, 6, (-1,0,0)), (3, 4, (0,0,1)), (3, 5, (0,-1,0)), (4, 5, (0,0,0)), (4, 6, (0,0,0))])
The string representation of the genome is simply string(genome)
:
julia> string(genome)
"3 1 2 0 0 0 1 3 0 0 0 1 4 0 0 0 1 4 0 0 1 1 5 0 0 0 1 6 0 0 0 2 4 0 0 1 2 6 -1 0 0 3 4 0 0 1 3 5 0 -1 0 4 5 0 0 0 4 6 0 0 0"