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)
with
crystal
: crystal structure, e.g.'fcc'
or'bcc'
Lbox
: simulation cell object or the cell sizenum_lines
: number of lines to generatetheta
(optional): list of character angles in degreesmaxseg
(optional): maximum segment size to discretize the dislocation linesRorient
(optional): crystal orientation matrixseed
(optional): seed number for the random generationverbose
(optional): print out lines information
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, num_loops, radius, maxseg, Rorient, seed, uniform)
N = DisNetManager(G)
with
crystal
: crystal structure, e.g.'fcc'
or'bcc'
Lbox
: simulation cell object or the cell sizenum_loops
: number of loops to generateradius
: radius of the loops, or radius range [min_radius, max_radius]maxseg
(optional): maximum segment size to discretize the loopsRorient
(optional): crystal orientation matrixseed
(optional): seed number for the random generationuniform
(optional): make the spatial loop distribution close to uniform
The dislocation loops are generated by cycling through the list of native Burgers vectors for the crystal structure (6 1/2<110> Burgers vectors for fcc
and 4 1/2<111> Burgers vectors for bcc
).
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)
with
cell
: network cell object or cell sizenodes
: list of nodes to which the line will be appendedsegs
: list of segments to which the line will be appendedburg
: Burgers vector of the lineplane
: habit plane normal of the lineorigin
: position of the origin of the linetheta
: character angle of the line in degreeslinedir
: line direction vectormaxseg
(optional): maximum discretization size of the linetrial
(optional): flag to specify a trial insertion only
The character angle is specified with either theta
the character angle of the line in degrees, or linedir
the line direction vector. 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, nodes = [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, nodes = [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, segs = [node1,node2,burg,plane]
segs = np.array([[0, 1, *burg, *plane],
[1, 2, *burg, *plane]])
G = ExaDisNet(cell, nodes, segs)
N = DisNetManager(G)
Combining several networks¶
Dislocation networks coming from different sources can be combined together into a single network using utility function combine_networks()
from file pyexadis_utils
. This can be useful to easily assemble complex initial configurations, e.g.
from framework.disnet_manager import DisNetManager
from pydis import DisNet
import pyexadis
from pyexadis_base import ExaDisNet
from pyexadis_utils import combine_networks
pyexadis.initialize()
# Configuration created with pydis
G1 = DisNet(...)
N1 = DisNetManager(G1)
# Configuration created with pyexadis
G2 = ExaDisNet(...)
N2 = DisNetManager(G2)
N = combine_networks([N1, N2])
Warning
Simulation cells must be identical for all input networks in order for them to be successfully combined into a single network. The user must also ensure that the input networks are defined in the same reference frame.
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.
Attention
When using rotated crystal frames, it is required to specify the corresponding orientation matrix in the state
dictionary before running a simulation,
state["Rorient"] = Rorient
so that the code can internally retrieve Burgers vectors and plane normal vectors in the crystal frame when needed.