Creating initial dislocation configurations¶
Initial dislocation configurations for OpenDiS simulations can be created in various ways.
Important
Independently on how it was created, any dislocation network must be wrapped into a DisNetManager
object before it can be used within OpenDiS modules.
Reading from a file¶
A dislocation network object can be read from a legacy ParaDiS format file .data
using the ExaDisNet
built-in method read_paradis()
, e.g.:
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
pyexadis.initialize()
G = ExaDisNet()
G.read_paradis('config.data')
N = DisNetManager(G)
Using utility functions¶
Some utility functions are provided in class ExaDisNet
and in file core/exadis/python/pyexadis_utils.py
to generate basic dislocation configurations (Frank-Read source, infinite lines, etc.).
Ensemble of infinite lines or dipoles¶
Utility method generate_line_config()
can be used to generate a collection of randomly positioned infinite lines or dipoles, e.g.
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
pyexadis.initialize()
G = ExaDisNet()
G.generate_line_config(crystal, Lbox, num_lines, theta, maxseg, Rorient, seed, verbose)
N = DisNetManager(G)
where crystal
is the crystal structure, Lbox
is a simulation cell object or the cell size, num_lines
the number of lines to generate, maxseg
(optional) the maximum segment size to discretize the dislocations, Rorient
(optional) the crystal orientation matrix, seed
(optional) the seed number for the random generation. The dislocations are generated by cycling through the list of signed (+/- Burgers vectors) slip systems (1/2<110>{111} systems in fcc
and 1/2<111>{110} systems in bcc
). To create dipoles (neutral Burgers charge), num_lines
must be a multiple of 24 (=12*2). If a list of character angles theta
(optional) is provided, each dislocation will be randomly assigned one of the character angles from the list. If not provided, the character angles will be chosen such that the dislocation density is roughly equal between all slip systems.
Ensemble of prismatic loops¶
Utility method generate_prismatic_config()
can be used to generate a collection of randomly positioned prismatic (i.e. with all arms of edge character) dislocation loops, e.g.
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
pyexadis.initialize()
G = ExaDisNet()
G.generate_prismatic_config(crystal, Lbox, numsources, radius, maxseg, Rorient, seed)
N = DisNetManager(G)
where crystal
is the crystal structure, Lbox
is a simulation cell object or the cell size, numsources
the number of loops to generate, maxseg
(optional) the maximum segment size to discretize the dislocations, Rorient
(optional) the crystal orientation matrix, seed
(optional) the seed number for the random generation. The dislocation loops are generated by cycling through the list of native Burgers vectors for the crystal structure.
Individual Frank-Read source¶
Utility function insert_frank_read_src()
from pyexadis_utils
can be used to insert a Frank-Read source, e.g.:
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
from pyexadis_utils import insert_frank_read_src
pyexadis.initialize()
# Define box
Lbox = 1000.0
cell = pyexadis.Cell(Lbox)
nodes, segs = [], []
# Insert Frank-Read source
burg = 1.0/np.sqrt(2.0)*np.array([1.,1.,0.])
plane = np.array([-1.,1.,1.])
length = 0.5*Lbox
center = cell.center()
nodes, segs = insert_frank_read_src(cell, nodes, segs, burg, plane,
length, center, theta=90.0, numnodes=10)
G = ExaDisNet(cell, nodes, segs)
N = DisNetManager(G)
To insert multiple Frank-Read sources into the same configuration, one can call insert_frank_read_src()
repeatedly, e.g.
...
# Frank-Read source 1
nodes, segs = insert_frank_read_src(cell, nodes, segs, burg1, plane1,
length1, center1, theta1, numnodes1)
# Frank-Read source 2
nodes, segs = insert_frank_read_src(cell, nodes, segs, burg2, plane2,
length2, center2, theta2, numnodes2)
...
Individual infinite line¶
Utility function insert_infinite_line()
from pyexadis_utils
can be used to insert an infinite, straight dislocation line, e.g.:
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
from pyexadis_utils import insert_infinite_line
pyexadis.initialize()
nodes, segs = [], []
nodes, segs = insert_infinite_line(cell, nodes, segs, burg, plane, origin,
theta=0.0, linedir=None, maxseg=-1, trial=False)
G = ExaDisNet(cell, nodes, segs)
N = DisNetManager(G)
where
cell
is the network cell object or cell size, nodes
and segs
are the list of nodes and segments to which the line will be appended, burg
the Burgers vector of the line, plane
the habit plane normal of the line, origin
the origin position of the line. The character angle can be specified either by specifying theta
the character angle of the line in degrees, or linedir
the line direction vector. maxseg
(optional) is the maximum discretization length of the line. Parameter trial
(optional) is a flag to do a trial insertion only to test if insertion is possible (depending on the cell size and crystal orientation, insertion of an infinite line may result in an unacceptably long line under PBC). When trial=True
, the function returns the length of the trial line (if insertion is successful) or -1 (if insertion failed), instead of returning the nodes
and segs
lists.
Manual generation¶
One can create a dislocation configuration manually by specifying the lists of nodes and segments properties. Configurations can be created using both pydis
or pyexadis
data structures.
As an example, let’s assume one wants to insert a 1/2<110> screw dislocation line of length 100b lying on the (-1,1,1) plane and discretized into 3 nodes.
Using pydis¶
To create the example configuration using pydis
, one can do
from framework.disnet_manager import DisNetManager
from pydis import DisNode, DisNet, Cell
Ldis = 100.0 # dislocation length
Lbox = 2*Ldis # simulation box size
burg = 1.0/np.sqrt(2.0)*np.array([1.,1.,0.]) # Burgers vector
plane = np.array([-1.,1.,1.]) # plane normal
# Simulation cell object
cell = Cell(h=Lbox*np.eye(3), is_periodic=[True,True,True])
# List of nodes, rn = [x,y,z,constraint]
linevec = Ldis*burg # line vector
rn = np.array([[*(-0.5*linevec), DisNode.Constraints.PINNED_NODE],
[*( 0.0*linevec), DisNode.Constraints.UNCONSTRAINED],
[*( 0.5*linevec), DisNode.Constraints.PINNED_NODE]])
rn[:,0:3] += cell.center() # translate line to the center of the box
# List of segments, links = [node1,node2,burg,plane]
links = np.array([[0, 1, *burg, *plane],
[1, 2, *burg, *plane]])
G = DisNet(cell=cell, rn=rn, links=links)
N = DisNetManager(G)
Using pyexadis¶
To create the example configuration using pyexadis
, one can do
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet, NodeConstraints
pyexadis.initialize()
Ldis = 100.0 # dislocation length
Lbox = 2*Ldis # simulation box size
burg = 1.0/np.sqrt(2.0)*np.array([1.,1.,0.]) # Burgers vector
plane = np.array([-1.,1.,1.]) # plane normal
# Simulation cell object
cell = pyexadis.Cell(h=Lbox*np.eye(3), is_periodic=[True,True,True])
# List of nodes, rn = [x,y,z,constraint]
linevec = Ldis*burg # line vector
nodes = np.array([[*(-0.5*linevec), NodeConstraints.PINNED_NODE],
[*( 0.0*linevec), NodeConstraints.UNCONSTRAINED],
[*( 0.5*linevec), NodeConstraints.PINNED_NODE]])
nodes[:,0:3] += cell.center() # translate line to the center of the box
# List of segments, links = [node1,node2,burg,plane]
segs = np.array([[0, 1, *burg, *plane],
[1, 2, *burg, *plane]])
G = ExaDisNet(cell, nodes, segs)
N = DisNetManager(G)
Rotated crystal frames¶
It can be convenient or desirable to create a dislocation configuration in a user-defined rotated crystal frame, e.g. such as to align the line direction or slip plane of a given dislocation with the simulation box axes.
As an example, let’s assume one wants to insert an infinite dislocation line with line direction along the y-axis and glide plane normal along the z-axis into a FCC crystal. Since FCC plane normals are along the {111} crystallographic directions, this requires to rotate the crystal frame. This can be done as in the following example:
from framework.disnet_manager import DisNetManager
import pyexadis
from pyexadis_base import ExaDisNet
from pyexadis_utils import insert_infinite_line
pyexadis.initialize()
Lbox = 1000.0 # simulation box size
maxseg = 0.05*Lbox # line discretization
burg = 1.0/np.sqrt(2.0)*np.array([1.,1.,0.]) # Burgers vector
plane = np.array([1.,1.,1.]) # plane normal
theta = 90.0 # character angle in degrees
# Crystal orientation
plane = plane / np.linalg.norm(plane)
b = burg / np.linalg.norm(burg)
y = np.cross(plane, b)
y = y / np.linalg.norm(y)
linedir = np.cos(theta*np.pi/180.0)*b+np.sin(theta*np.pi/180.0)*y
x = np.cross(linedir, plane)
x = x / np.linalg.norm(x)
Rorient = np.array([x, linedir, plane])
burg = np.matmul(Rorient, burg)
plane = np.matmul(Rorient, plane)
linedir = -np.matmul(Rorient, linedir)
# Create the cell and insert the line
cell = pyexadis.Cell(Lbox)
nodes, segs = [], []
origin = np.array(cell.origin) + 0.5*np.sum(np.array(cell.h), axis=0)
nodes, segs = insert_infinite_line(cell, nodes, segs, burg, plane, origin,
linedir=linedir, maxseg=maxseg)
N = DisNetManager(ExaDisNet(cell, nodes, segs))
As done in the above, rotation of the burg
and plane
vectors are necessary as these vectors must always be expressed in the global frame in the segs
array.
As a consequence, when using rotated crystal frames, it is also important to specify the corresponding orientation matrix in the state
dictionary before running a simulation:
state["Rorient"] = Rorient