Source code for mofbuilder.core.builder
from __future__ import annotations
from typing import Any, Optional
import numpy as np
import networkx as nx
from veloxchem.outputstream import OutputStream
from veloxchem.veloxchemlib import mpi_master
from veloxchem.errorhandler import assert_msg_critical
from veloxchem.molecule import Molecule
import mpi4py.MPI as MPI
import sys
import time
from ..utils.environment import get_data_path
from ..utils.fetch import fetch_pdbfile
from pathlib import Path
from .net import FrameNet
from .node import FrameNode
from .linker import FrameLinker
from .termination import FrameTermination
from .moftoplibrary import MofTopLibrary
from .optimizer import NetOptimizer
from .supercell import SupercellBuilder, EdgeGraphBuilder
from .defects import TerminationDefectGenerator
from .write import MofWriter
from ..io.pdb_reader import PdbReader
from ..md.linkerforcefield import LinkerForceFieldGenerator
from ..md.gmxfilemerge import GromacsForcefieldMerger
from ..md.solvationbuilder import SolvationBuilder
from ..visualization.viewer import Viewer
from ..md.setup import OpenmmSetup
from .framework import Framework
[docs]
class MetalOrganicFrameworkBuilder:
"""Orchestrates MOF building: load net and topology, place nodes and linkers, optimize, supercell, defects, write.
Set mof_family, node_metal, linker (xyz/molecule/SMILES), then call build() to get a Framework.
sG: scaled and rotated net graph; eG: edge graph (V + EDGE nodes, XOO on edges); superG: supercell of sG.
Attributes:
comm: MPI communicator.
rank: MPI rank of this process.
nodes: MPI size (number of processes).
ostream: Output stream for logging.
framework: Framework instance (result of build()).
mof_family: MOF family name (e.g. "HKUST-1").
node_metal: Metal type string for nodes.
dummy_atom_node: Whether to add dummy atoms to nodes.
dummy_atom_node_dict: Dict of dummy atom counts (set after node processing).
data_path: Path to database directory.
frame_nodes: FrameNode instance.
frame_linker: FrameLinker instance.
frame_terminations: FrameTermination instance.
frame_net: FrameNet instance.
mof_top_library: MofTopLibrary instance.
net_optimizer: NetOptimizer instance.
mofwriter: MofWriter instance.
defectgenerator: TerminationDefectGenerator instance.
net_spacegroup: Space group from net (set when net is loaded).
net_cell_info: Cell parameters from net.
net_unit_cell: 3x3 unit cell matrix from net.
net_unit_cell_inv: Inverse of net_unit_cell.
node_connectivity: Node connectivity from topology.
linker_connectivity: Linker connectivity (topic) from topology.
net_sorted_nodes: Sorted list of node names from net.
net_sorted_edges: Sorted list of edges from net.
net_pair_vertex_edge: Vertex-edge pairs from net.
linker_xyzfile: Path to linker XYZ file (optional).
linker_molecule: VeloxChem molecule for linker (optional).
linker_smiles: SMILES string for linker (optional).
linker_charge: Linker charge.
linker_multiplicity: Linker multiplicity.
linker_center_data: Center fragment data (set when linker is loaded).
linker_center_X_data: Center X-atom data.
linker_outer_data: Outer fragment(s) data.
linker_outer_X_data: Outer X-atom data.
linker_frag_length: Length of linker fragment.
linker_fake_edge: Whether linker is fake (zero-length) edge.
node_data: Node atom data (set when node is loaded).
node_X_data: Node X-atom data.
termination: Whether to use terminations.
termination_name: Name of termination group (e.g. 'acetate').
termination_molecule: Termination molecule (optional).
termination_data: Termination atom data.
termination_X_data: Termination X atoms.
termination_Y_data: Termination Y atoms.
constant_length: X-X bond length in Angstrom (default 1.54).
load_optimized_rotations: Path to H5 file with saved rotations (optional).
skip_rotation_optimization: If True, skip rotation optimization.
rotation_filename: Path to save optimized rotations (optional).
frame_unit_cell: 3x3 frame unit cell (set after build).
frame_cell_info: Frame cell parameters.
supercell: Supercell dimensions (nx, ny, nz).
remove_node_list: List of node indices to remove (defects).
remove_edge_list: List of edge indices to remove (defects).
_debug: If True, print extra debug messages.
"""
def __init__(
self,
comm: Optional[Any] = None,
ostream: Optional[Any] = None,
mof_family: Optional[str] = None,
) -> None:
self.comm = comm or MPI.COMM_WORLD
self.rank = self.comm.Get_rank()
self.nodes = self.comm.Get_size()
self.ostream = ostream or OutputStream(sys.stdout if self.rank ==
mpi_master() else None)
#need to be set before building the framework
self.framework = Framework(
) #will be returned as the built framework object
self.mof_family = mof_family #need to be set by user
self.node_metal = None
self.dummy_atom_node = None
self.dummy_atom_node_dict = None
self.data_path = None # todo: set default data path
self.frame_nodes = FrameNode(comm=self.comm, ostream=self.ostream)
self.frame_linker = FrameLinker(comm=self.comm, ostream=self.ostream)
self.frame_terminations = FrameTermination(comm=self.comm,
ostream=self.ostream)
self.frame_net = FrameNet(comm=self.comm, ostream=self.ostream)
self.mof_top_library = MofTopLibrary(comm=self.comm,
ostream=self.ostream)
self.net_optimizer = NetOptimizer(comm=self.comm, ostream=self.ostream)
self.mofwriter = MofWriter(comm=self.comm, ostream=self.ostream)
self.defectgenerator = TerminationDefectGenerator(comm=self.comm,
ostream=self.ostream)
#will be set when reading the net
self.net_spacegroup = None
self.net_cell_info = None
self.net_unit_cell = None
self.net_unit_cell_inv = None
self.node_connectivity = None #for the node
self.linker_connectivity = None #for the linker
self.net_sorted_nodes = None
self.net_sorted_edges = None
self.net_pair_vertex_edge = None
#need to be set by user
self.linker_xyzfile = None #can be set directly
self.linker_molecule = None #can be set directly
self.linker_smiles = None #can be set directly
self.linker_charge = None
self.linker_multiplicity = None
#will be set when reading the linker
self.linker_center_data = None
self.linker_center_X_data = None
self.linker_outer_data = None
self.linker_outer_X_data = None
self.linker_frag_length = None
self.linker_fake_edge = False
#need to be set by user when reading the node
self.node_metal = None #need to be set by user
self.dummy_atom_node = False #default no dummy atom in the node
#will be set when reading the node
self.node_data = None
self.node_X_data = None
self.dummy_atom_node_dict = None
#need to be set by user
self.termination = True # default use termination but need user to set the termination_filename
self.termination_name = 'acetate' #can be set as xyzfile or name
self.termination_molecule = None #can be set directly
self.termination_data = None
self.termination_X_data = None
self.termination_Y_data = None
#optimization
#need to be set by user
self.constant_length = 1.54 # X-X bond length in Angstrom, default 1.54A
self.load_optimized_rotations = None #h5 file with optimized rotations
self.skip_rotation_optimization = False
self.rotation_filename = None
#will be set
#framwork info will be generated
self.frame_unit_cell = None
self.frame_cell_info = None
#supercell and reconstruction of the edge graph
#need to be set by user
self.supercell = [1, 1, 1]
self.add_virtual_edge = False #for bridge type node, add virtual edge to connect the bridge nodes
self.vir_edge_range = 0.5 # in fractional coordinate should be less
self.vir_edge_max_neighbor = 2
self.supercell_custom_fbox = None
#will be set
self.eG_index_name_dict = None
self.eG_matched_vnode_xind = None
self.supercell_info = None
#defects
#need to be set by user
self.remove_indices = []
self.exchange_indices = []
self.neutral_system = True #default keep the system neutral when making defects
self.exchange_linker_pdbfile = None
self.exchange_node_pdbfile = None
self.exchange_linker_molecule = None
#terminate
self.update_node_termination = True #default update the node termination after making defects
self.clean_unsaturated_linkers = True #default cleave the unsaturated linkers after making defects
#MD preparation
self.framework_data = None #merged data for the whole framework, generated in write()
self.solvationbuilder = SolvationBuilder(comm=self.comm,
ostream=self.ostream)
self.solvents = [] #list of solvent names or xyz files
self.solvents_molecules = [] #list of solvent molecules
self.solvents_proportions = [] #list of solvent proportions
self.solvents_quantities = [] #list of solvent quantities
#will be set
self.solvated_gro_file = None
#MD simulation
#others for output and saving
self.target_directory = 'output'
self.save_files = False
self.linker_ff_name = "Linker"
self.linker_charge = None
self.linker_multiplicity = None
self.linker_reconnect_drv = 'xtb'
self.linker_reconnect_opt = True
self.provided_linker_itpfile = None #if provided, will map directly
#debug
self._debug = False
#specific settings
self.linker_frag_length_search_range = [] #in Angstrom, [min, max]
#MLP energy minimization
self.mlp_type = 'mace' #default MLP type
self.mlp_model_path = None #path to the MLP model file
#Graph will be generated
self.G = None #original net graph from cif file
self.sG = None #scaled and rotated G
self.superG = None #supercell of sG
self.eG = None #edge graph with only edge and V node, and XOO atoms linked to the edge
self.cleaved_eG = None #edge graph after cleaving the extra edges
[docs]
def list_available_mof_families(self):
if self.data_path is None:
self.data_path = get_data_path()
self.mof_top_library._debug = self._debug
self.mof_top_library.data_path = self.data_path
self.mof_top_library.list_mof_families()
[docs]
def list_available_metals(self, mof_family: Optional[str] = None) -> None:
"""Print available metals for the given (or current) MOF family from the topology library."""
if self.data_path is None:
self.data_path = get_data_path()
if mof_family is None:
mof_family = self.mof_family
self.mof_top_library._debug = self._debug
self.mof_top_library.data_path = self.data_path
self.mof_top_library.list_available_metals(mof_family=mof_family)
[docs]
def list_available_terminations(self):
if self.data_path is None:
self.data_path = get_data_path()
self.ostream.print_title("Available Terminations:")
if Path(self.data_path, 'terminations_itps').is_dir():
for term_file in Path(self.data_path,
'terminations_itps').rglob('*.itp'):
if Path(self.data_path, 'terminations_database',
term_file.stem + '.pdb').is_file():
self.ostream.print_info(f" - {term_file.stem}")
self.ostream.flush()
else:
self.ostream.print_warning("No terminations found.")
self.ostream.flush()
[docs]
def list_available_solvents(self):
if self.data_path is None:
self.data_path = get_data_path()
self.ostream.print_title("Available Solvents:")
if Path(self.data_path, 'solvents_database').is_dir():
for solv_file in Path(self.data_path,
'solvents_database').rglob('*.itp'):
self.ostream.print_info(f" - {solv_file.stem}")
self.ostream.flush()
else:
self.ostream.print_warning("No solvents found.")
self.ostream.flush()
def _read_net(self):
if self.data_path is None:
self.data_path = get_data_path()
self.mof_top_library._debug = self._debug
self.mof_top_library.data_path = self.data_path
self.frame_net.cif_file = self.mof_top_library.fetch(
mof_family=self.mof_family)
assert_msg_critical(
self.frame_net.cif_file is not None,
"Template cif file is not set in mof_top_library.")
self.frame_net.edge_length_range = self.linker_frag_length_search_range
self.frame_net.create_net()
#check if the max_degree of the net matches the node_connectivity
assert_msg_critical(
self.frame_net.max_degree ==
self.mof_top_library.node_connectivity,
"Max degree of the net does not match the node connectivity.")
self.node_connectivity = self.frame_net.max_degree
self.net_spacegroup = self.frame_net.cifreader.spacegroup
self.net_cell_info = self.frame_net.cell_info
self.G = self.frame_net.G.copy()
self.net_unit_cell = self.frame_net.unit_cell
self.net_unit_cell_inv = self.frame_net.unit_cell_inv
self.linker_connectivity = self.frame_net.linker_connectivity
self.net_sorted_nodes = self.frame_net.sorted_nodes
self.net_sorted_edges = self.frame_net.sorted_edges
self.net_pair_vertex_edge = self.frame_net.pair_vertex_edge
def _read_linker(self):
self.frame_linker.linker_connectivity = self.linker_connectivity
if self.save_files: #TODO: check if the target directory is set
if self.linker_xyzfile is not None:
self.frame_linker.filename = self.linker_xyzfile
else:
self.frame_linker.filename = "Linker"
self.frame_linker.target_directory = self.target_directory
self.frame_linker.save_files = self.save_files
if self.linker_molecule is not None:
self.frame_linker.create(molecule=self.linker_molecule)
elif self.linker_smiles is not None:
mol = Molecule.read_smiles(self.linker_smiles)
self.frame_linker.create(molecule=mol)
elif self.linker_xyzfile is not None:
self.frame_linker.filename = self.linker_xyzfile
self.frame_linker.create()
#pass linker data
self.linker_center_data = self.frame_linker.linker_center_data
self.linker_center_X_data = self.frame_linker.linker_center_X_data
if len(self.frame_linker.linker_center_X_data) == 1:
#is a point linker, prolong a norm point and get two points. can just +1 at col 5 for x
dup_point = np.hstack(
(self.linker_center_data[:, 0:5],
self.linker_center_data[:, 5:8].astype(float) + [1.0, 0, 0],
self.linker_center_data[:, 8:]))
self.linker_center_data = np.vstack(
(self.linker_center_data, dup_point))
self.linker_center_X_data = self.linker_center_data
self.linker_center_data[:, 1] = "Fr"
if self.frame_linker.linker_connectivity > 2:
#RECENTER COM of outer data
linker_com = np.mean(
self.frame_linker.linker_outer_X_data[:, 5:8].astype(float),
axis=0)
self.linker_outer_data = np.hstack(
(self.frame_linker.linker_outer_data[:, 0:5],
self.frame_linker.linker_outer_data[:, 5:8].astype(float) -
linker_com, self.frame_linker.linker_outer_data[:, 8:]))
self.linker_outer_X_data = np.hstack(
(self.frame_linker.linker_outer_X_data[:, 0:5],
self.frame_linker.linker_outer_X_data[:, 5:8].astype(float) -
linker_com, self.frame_linker.linker_outer_X_data[:, 8:]))
if len(self.frame_linker.linker_outer_X_data) == 1:
#is a point linker, duplicate the data
dup_point = np.hstack(
(self.linker_outer_data[:, 0:5],
self.linker_outer_data[:, 5:8].astype(float) +
[1.0, 0, 0], self.linker_outer_data[:, 8:]))
self.linker_outer_data = np.vstack(
(self.linker_outer_data, dup_point))
self.linker_outer_X_data = self.linker_outer_data
self.linker_outer_data[:, 1] = "Fr"
self.linker_frag_length = np.linalg.norm(
self.linker_outer_X_data[0, 5:8].astype(float) -
self.linker_outer_X_data[1, 5:8].astype(float))
else:
self.linker_frag_length = np.linalg.norm(
self.linker_center_X_data[0, 5:8].astype(float) -
self.linker_center_X_data[1, 5:8].astype(float))
if self.frame_linker.fake_edge:
self.linker_frag_length = 0.0
self.linker_fake_edge = self.frame_linker.fake_edge
def _read_node(self):
assert_msg_critical(self.node_connectivity is not None,
"node_connectivity is not set")
assert_msg_critical(self.node_metal is not None,
"node_metal_type is not set")
nodes_database_path = Path(self.data_path, "nodes_database")
keywords = [str(self.node_connectivity) + "c", self.node_metal]
nokeywords = ["dummy"]
selected_node_pdb_filename = fetch_pdbfile(nodes_database_path,
keywords, nokeywords,
self.ostream)[0]
self.frame_nodes.filename = Path(nodes_database_path,
selected_node_pdb_filename)
self.frame_nodes.node_metal_type = self.node_metal
self.frame_nodes.dummy_node = self.dummy_atom_node
self.frame_nodes.create()
#pass node data
self.node_data = self.frame_nodes.node_data
self.node_X_data = self.frame_nodes.node_X_data
self.dummy_atom_node_dict = self.frame_nodes.dummy_node_split_dict
def _read_termination(self):
if not self.termination:
return
#try to get a valid termination file
if self.termination_name is None:
self.ostream.print_info(
"Termination is set to True but termination_name is None. Skipping termination."
)
self.termination = False
return
#termination_name can be a file path or a name in the termination database
#check if the termination_name is a valid file path
if not (Path(self.termination_name).is_file()):
#check if the termination is a name in the termination database
if self._debug:
self.ostream.print_info(
f"Termination file {self.termination_name} is not a valid file path. Searching in termination database."
)
self.ostream.flush()
keywords = [self.termination_name]
nokeywords = []
terminations_database_path = Path(self.data_path,
"terminations_database")
selected_termination_pdb_filename = fetch_pdbfile(
terminations_database_path, keywords, nokeywords,
self.ostream)[0]
assert_msg_critical(
selected_termination_pdb_filename is not None,
f"Termination file {self.termination_name} does not exist in the termination database."
)
self.termination_name = str(
Path(terminations_database_path,
selected_termination_pdb_filename))
if self._debug:
self.ostream.print_info(
f"Using termination file: {self.termination_name}")
self.ostream.flush()
self.frame_terminations.filename = self.termination_name
self.frame_terminations.create()
#pass termination data
self.termination_data = self.frame_terminations.termination_data
self.termination_X_data = self.frame_terminations.termination_X_data #X for -X-YY in -C-OO
self.termination_Y_data = self.frame_terminations.termination_Y_data #Y for -X-YY in -C-OO
[docs]
def load_framework(self):
self._read_net()
self._read_linker()
self._read_node()
self._read_termination()
if self._debug:
self.ostream.print_info(f"Framework components read:")
self.ostream.print_info(
f"Net: {self.mof_family}, spacegroup: {self.net_spacegroup}, cell: {self.net_cell_info}"
)
self.ostream.print_info(
f"Node: {self.frame_nodes.filename} with metal type {self.node_metal}"
)
self.ostream.print_info(
f"Linker: {self.frame_linker.linker_connectivity}")
if self.termination:
self.ostream.print_info(
f"Termination: {self.termination_name}")
else:
self.ostream.print_info(f"Termination: None")
self.ostream.print_info("Finished reading framework components.")
self.ostream.flush()
[docs]
def optimize_framework(self):
self.net_optimizer._debug = self._debug
self.net_optimizer.skip_rotation_optimization = self.skip_rotation_optimization
self.net_optimizer.rotation_filename = self.rotation_filename #file to save the optimized rotations
self.net_optimizer.load_optimized_rotations = self.load_optimized_rotations #h5 file with optimized rotations to load
self.net_optimizer.G = self.G.copy()
self.net_optimizer.cell_info = self.net_cell_info
self.net_optimizer.V_data = self.frame_nodes.node_data
self.net_optimizer.V_X_data = self.frame_nodes.node_X_data
if self.frame_net.linker_connectivity > 2:
self.net_optimizer.EC_data = self.frame_linker.linker_center_data
self.net_optimizer.EC_X_data = self.frame_linker.linker_center_X_data
self.net_optimizer.E_data = self.linker_outer_data
self.net_optimizer.E_X_data = self.linker_outer_X_data
else:
self.net_optimizer.E_data = self.frame_linker.linker_center_data
self.net_optimizer.E_X_data = self.frame_linker.linker_center_X_data
self.net_optimizer.EC_data = None
self.net_optimizer.EC_X_data = None
self.net_optimizer.constant_length = self.constant_length
self.net_optimizer.sorted_nodes = self.frame_net.sorted_nodes
self.net_optimizer.sorted_edges = self.frame_net.sorted_edges
self.net_optimizer.linker_frag_length = self.linker_frag_length
self.net_optimizer.fake_edge = self.linker_fake_edge
self.ostream.print_separator()
self.ostream.print_info(
"Start to optimize the node rotations and cell parameters")
self.ostream.flush()
self.net_optimizer.rotation_and_cell_optimization()
self.ostream.print_info("--------------------------------")
self.ostream.print_info(
"Finished optimizing the node rotations and cell parameters")
self.ostream.print_separator()
self.net_optimizer._debug = self._debug
self.net_optimizer.place_edge_in_net()
#here we can get the unit cell with nodes and edges placed
self.sG = self.net_optimizer.sG.copy() #scaled and rotated G
self.frame_cell_info = self.net_optimizer.optimized_cell_info
self.frame_unit_cell = self.net_optimizer.sc_unit_cell
# save_xyz("scale_optimized_nodesstructure.xyz", scaled_rotated_node_positions)
[docs]
def make_supercell(self):
self.supercellbuilder = SupercellBuilder(comm=self.comm,
ostream=self.ostream)
self.supercellbuilder.sG = self.net_optimizer.sG
self.supercellbuilder.cell_info = self.net_optimizer.optimized_cell_info
self.supercellbuilder.supercell = self.supercell
self.supercellbuilder.linker_connectivity = self.linker_connectivity
#virtual edge settings for bridge type nodes
self.supercellbuilder.add_virtual_edge = self.add_virtual_edge
self.supercellbuilder.vir_edge_range = self.vir_edge_range
self.supercellbuilder.vir_edge_max_neighbor = self.vir_edge_max_neighbor
#self.supercellbuilder._debug = self._debug
self.supercellbuilder.build_supercellGraph()
self.superG = self.supercellbuilder.superG
self.supercell_info = self.supercellbuilder.superG_cell_info
#convert to edge graph
self.edgegraphbuilder = EdgeGraphBuilder(comm=self.comm,
ostream=self.ostream)
if self._debug:
self.ostream.print_info(
f"superG has {len(self.supercellbuilder.superG.nodes())} nodes and {len(self.supercellbuilder.superG.edges())} edges"
)
self.edgegraphbuilder.superG = self.supercellbuilder.superG
self.edgegraphbuilder.linker_connectivity = self.linker_connectivity
self.edgegraphbuilder.linker_frag_length = self.linker_frag_length
self.edgegraphbuilder.node_connectivity = self.node_connectivity + self.vir_edge_max_neighbor if self.add_virtual_edge else self.node_connectivity
self.edgegraphbuilder.custom_fbox = self.supercell_custom_fbox
self.edgegraphbuilder.sc_unit_cell = self.net_optimizer.sc_unit_cell
self.edgegraphbuilder.supercell = self.supercell
#self.edgegraphbuilder._debug = self._debug
self.edgegraphbuilder.build_edgeG_from_superG()
self.eG = self.edgegraphbuilder.eG.copy()
self.eG_index_name_dict = self.edgegraphbuilder.eG_index_name_dict
self.eG_matched_vnode_xind = self.edgegraphbuilder.matched_vnode_xind
self.cleaved_eG = self.edgegraphbuilder.cleaved_eG.copy()
if self._debug:
self.ostream.print_info(
f"eG has {len(self.edgegraphbuilder.eG.nodes())} nodes and {len(self.edgegraphbuilder.eG.edges())} edges"
)
self.ostream.print_info(
f"cleaved_eG has {len(self.edgegraphbuilder.cleaved_eG.nodes())} nodes and {len(self.edgegraphbuilder.cleaved_eG.edges())} edges"
)
self.ostream.flush()
[docs]
def build(self) -> Framework:
"""Load net and topology, place nodes/linkers, optimize rotations and cell, build supercell (and defects). Returns self.framework."""
self.load_framework()
self.optimize_framework()
self.make_supercell()
#save the information to self.framework to pass the object information
self.framework.data_path = self.data_path
self.framework.target_directory = self.target_directory
self.framework.mof_family = self.mof_family
self.framework.node_metal = self.node_metal
self.framework.dummy_atom_node = self.dummy_atom_node
self.framework.net_spacegroup = self.net_spacegroup
self.framework.net_cell_info = self.net_cell_info
self.framework.net_unit_cell = self.net_unit_cell
self.framework.node_connectivity = self.node_connectivity
self.framework.linker_connectivity = self.linker_connectivity
self.framework.linker_fragment_length = self.linker_frag_length
self.framework.node_data = self.node_data
self.framework.dummy_atom_node_dict = self.dummy_atom_node_dict
self.framework.termination_data = self.termination_data
self.framework.frame_unit_cell = self.frame_unit_cell
self.framework.frame_cell_info = self.frame_cell_info
self.framework.graph = self.eG.copy()
self.framework.cleaved_graph = self.cleaved_eG.copy()
self.framework.graph_index_name_dict = self.eG_index_name_dict
self.framework.graph_matched_vnode_xind = self.eG_matched_vnode_xind
self.framework.supercell = self.supercell
self.framework.supercell_info = self.supercell_info
self.framework.termination = self.termination
self.framework.add_virtual_edge = self.add_virtual_edge
self.framework.virtual_edge_max_neighbor = self.vir_edge_max_neighbor
self.framework.sc_unit_cell = self.net_optimizer.sc_unit_cell
self.framework.sc_unit_cell_inv = self.net_optimizer.sc_unit_cell_inv
self.framework.termination_X_data = self.termination_X_data
self.framework.termination_Y_data = self.termination_Y_data
self.framework.termination_name = self.termination_name
self.framework.src_linker_molecule = self.frame_linker.molecule
self.framework.clean_unsaturated_linkers = self.clean_unsaturated_linkers
self.framework.update_node_termination = self.update_node_termination
self.framework.unsaturated_linkers = self.edgegraphbuilder.unsaturated_linkers
self.framework.unsaturated_nodes = self.edgegraphbuilder.unsaturated_nodes
self.framework.saved_unsaturated_linker = self.edgegraphbuilder.unsaturated_linkers
self.framework.matched_vnode_xind = self.edgegraphbuilder.matched_vnode_xind
self.framework.xoo_dict = self.edgegraphbuilder.xoo_dict
self.defectgenerator.termination_data = self.termination_data
self.defectgenerator.termination_X_data = self.termination_X_data
self.defectgenerator.termination_Y_data = self.termination_Y_data
self.defectgenerator.cleaved_eG = self.cleaved_eG.copy()
self.defectgenerator.linker_connectivity = self.linker_connectivity
self.defectgenerator.node_connectivity = self.node_connectivity + self.vir_edge_max_neighbor if self.add_virtual_edge else self.node_connectivity
self.defectgenerator.eG_index_name_dict = self.edgegraphbuilder.eG_index_name_dict
self.defectgenerator.eG_matched_vnode_xind = self.edgegraphbuilder.matched_vnode_xind
self.defectgenerator.sc_unit_cell = self.net_optimizer.sc_unit_cell
self.defectgenerator.sc_unit_cell_inv = self.net_optimizer.sc_unit_cell_inv
self.defectgenerator.clean_unsaturated_linkers = self.clean_unsaturated_linkers
self.defectgenerator.update_node_termination = self.update_node_termination
self.defectgenerator.saved_unsaturated_linker = self.edgegraphbuilder.unsaturated_linkers
self.defectgenerator.matched_vnode_xind = self.edgegraphbuilder.matched_vnode_xind
self.defectgenerator.xoo_dict = self.edgegraphbuilder.xoo_dict
self.defectgenerator.use_termination = self.termination
self.defectgenerator.unsaturated_linkers = self.edgegraphbuilder.unsaturated_linkers
self.defectgenerator.unsaturated_nodes = self.edgegraphbuilder.unsaturated_nodes
#remove
terminated_G = self.defectgenerator.remove_items_or_terminate(
res_idx2rm=[], cleaved_eG=self.cleaved_eG.copy())
#update the framework
self.framework.graph = terminated_G.copy()
self.framework.matched_vnode_xind = self.defectgenerator.updated_matched_vnode_xind
self.framework.unsaturated_linkers = self.defectgenerator.unsaturated_linkers
self.framework.unsaturated_nodes = self.defectgenerator.updated_unsaturated_nodes
#exceptions for linker forcefield generation
self.framework.linker_fake_edge = self.linker_fake_edge
self.framework._debug = self._debug
#pass
self.framework.get_merged_data()
#pass MLP settings to framework
self.framework.mlp_type = self.mlp_type
self.framework.mlp_model_path = self.mlp_model_path
return self.framework