22
33import math
44from abc import abstractmethod
5+ import os
6+ import tempfile
57
68import freud
79import numpy as np
1315
1416
1517class Path :
16- def __init__ (self , N = None , coordinates = None , bond_graph = None ):
18+ def __init__ (self , N = None , coordinates = None , bond_graph = None , path_graph = None ):
19+ self .path_graph = path_graph
1720 self .bond_graph = bond_graph
1821 # Only N is defined, make empty coordinates array with size N
1922 # Use case: Random walks
@@ -35,6 +38,12 @@ def __init__(self, N=None, coordinates=None, bond_graph=None):
3538 self .generate ()
3639 if self .N is None :
3740 self .N = len (self .coordinates )
41+ if self .path_graph == "linear" :
42+ self .path_graph = BondGraph ()
43+ self .path_graph .add_node (tuple (coordinates [0 ]))
44+ for point1 , point2 in zip (self .coordinates , self .coordinates [1 :]):
45+ self .path_graph .add_node (tuple (point2 ))
46+ self .path_graph .add_edge (tuple (point1 ), tuple (point2 ))
3847
3948 @classmethod
4049 def from_coordinates (cls , coordinates , bond_graph = None ):
@@ -70,13 +79,28 @@ def neighbor_list(self, r_max, query_points, coordinates=None, box=None):
7079 return nlist
7180
7281 def to_compound (self , bead_name = "_A" , bead_mass = 1 ):
73- """Visualize a path as an mBuild Compound."""
82+ """Create an mBuild Compound using the coordinates and path_graph of a Path ."""
7483 compound = Compound ()
7584 for xyz in self .coordinates :
7685 compound .add (Compound (name = bead_name , mass = bead_mass , pos = xyz ))
77- if self .bond_graph :
78- compound .set_bond_graph (self .bond_graph )
86+ if self .path_graph :
87+ # use the path_graph to create a bond graph
88+ bond_graph = self .path_graph_to_bond_graph (compound )
89+ compound .set_bond_graph (bond_graph )
7990 return compound
91+
92+ def path_graph_to_bond_graph (self , compound ):
93+ """Take a preset path_graph and return a bond_graph with the particles of a given compound."""
94+ bond_graph = BondGraph ()
95+ for i in range (compound .n_particles ):
96+ bond_graph .add_node (i ) # needs to be the index of compound
97+ if self .path_graph :
98+ path_to_index_map = {tuple (coord ):i for i , coord in enumerate (self .coordinates )}
99+ for point1 , point2 in self .path_graph .edges :
100+ index1 = path_to_index_map [tuple (point1 )]
101+ index2 = path_to_index_map [tuple (point2 )]
102+ bond_graph .add_edge (index1 , index2 )
103+ return bond_graph
80104
81105 def apply_mapping (self ):
82106 # TODO: Finish, add logic to align orientation with path site pos and bond graph
@@ -95,6 +119,37 @@ def _path_history(self):
95119 """
96120 pass
97121
122+ def visualize (self , bead_color = "#5d8aa8" ):
123+ """Visualize in 3D space using py3Dmol of the Path as a Compound."""
124+ py3Dmol = import_ ("py3Dmol" )
125+ compound = self .to_compound ()
126+ color_scheme = {"C" : bead_color } # just use default Carbon element to set color
127+ for particle in compound .particles ():
128+ particle .name = "C"
129+ tmp_dir = tempfile .mkdtemp ()
130+ compound .save (
131+ os .path .join (tmp_dir , "tmp.mol2" ),
132+ include_ports = False ,
133+ overwrite = True ,
134+ )
135+
136+ view = py3Dmol .view ()
137+ with open (os .path .join (tmp_dir , "tmp.mol2" ), "r" ) as f :
138+ view .addModel (f .read (), "mol2" , keepH = True )
139+
140+ view .setStyle (
141+ {
142+ "stick" : {"radius" : 0.3 , "color" : "grey" },
143+ "sphere" : {
144+ "radius" : self .radius * 10 / 2 if self .radius else 1.7 / 2 , # angstroms
145+ "colorscheme" : color_scheme ,
146+ },
147+ }
148+ )
149+ view .zoomTo ()
150+
151+ return view
152+
98153
99154class HardSphereRandomWalk (Path ):
100155 def __init__ (
@@ -114,6 +169,7 @@ def __init__(
114169 trial_batch_size = 20 ,
115170 tolerance = 1e-5 ,
116171 bond_graph = None ,
172+ path_graph = None ,
117173 ):
118174 """Generates coordinates from a self avoiding random walk using
119175 fixed bond lengths, hard spheres, and minimum and maximum angles
@@ -151,6 +207,9 @@ def __init__(
151207 Tolerance used for rounding and checkig for overlaps.
152208 bond_graph : networkx.graph.Graph; optional
153209 Sets the bonding of sites along the path.
210+ path_graph : str; optional, default=None
211+ A passable string to define the bond_graph used in the Path. Options are:
212+ `linear`: each coordinate is connected to the previous coordinate to create a linear path.
154213
155214 Notes
156215 -----
@@ -184,8 +243,7 @@ def __init__(
184243 self .attempts = 0
185244 self .start_from_path_index = start_from_path_index
186245 self .start_from_path = start_from_path
187-
188- # This random walk is including a previous path
246+ self .path_graph = path_graph
189247 if start_from_path :
190248 coordinates = np .concatenate (
191249 (
@@ -209,7 +267,7 @@ def __init__(
209267 self .rng = np .random .default_rng (seed )
210268
211269 super (HardSphereRandomWalk , self ).__init__ (
212- coordinates = coordinates , N = None , bond_graph = bond_graph
270+ coordinates = coordinates , N = None , bond_graph = bond_graph , path_graph = path_graph
213271 )
214272
215273 def generate (self ):
0 commit comments