Code architecture and data structures¶
Overview¶
ExaDiS is implemented based on a modular design in which each functionality can be viewed as an independent module. This design is essential to make the code extensible and enable its coupling with various other modules within the OpenDiS framework.
ExaDiS core backend is written in modern C++ and built based on the Kokkos framework. This allows to maintain a unique version of the source code that is largely agnostic of the target hardware: the same source code can be compiled for a wide variety of systems and hardwares, e.g. for serial CPU machines, using OpenMP, or for GPU machines using cuda or hip architectures, for instance.
ExaDiS classes and functions are implemented with high-performance and high-parallelism kernel execution in mind. Yet, the code is designed to abstract away as much complexity as possible, so as to lower the entry barrier for developing new functionalities. For prototyping or first implementation pass, ExaDiS also provides convenient helper functions and data structures that are easier to manipulate than Kokkos-based implementations. An illustration of this is the Topology
class implementation, where class TopologySerial
implements the split-multi-node procedure in a serial fashion on the host (CPU), while TopologyParallel
is an implementation of the same split-multi-node procedure but executed with highly-parallel kernels on the device (GPU).
Project structure¶
Here is a brief description of the directory structure of the ExaDiS code:
cmake/
: cmake related files, including pre-defined build system optionsexamples/
: examples of scripts and simulationseach example is numbered and placed in a dedicated subfolder
kokkos/
: directory containing the Kokkos submodulepython/
: files related to the python binding implementationpybind11/
directory containing the pybind11 submoduleexadis_pybind.cpp
: implementation of the C++ classes / functions bindingpyexadis_base.py
: interface enabling the use of pyexadis within OpenDiSpyexadis_utils.py
: pyexadis utility functions
src/
: C++ source and header files (*.cpp
,*.h
)base class files and common functions are at the root of the
src
directoryindividual module implementations are placed in subfolders
collision_types/
: implementation of collision modulesforce_types/
: implementation of force modulesintegrator_types/
: implementation of integrator modulesmobility_types/
: implementation of mobility modulesneighbor_types/
: implementation of neighbor modulestopology_types/
: implementation of topology modules
tests/
: files for testing and debuggingbenchmark/
: benchmark tests to evaluate the performance of the codedebug.h
: debug utility functionstest_exadis.cpp
: simple ExaDiS test simulations
Dislocation network and data structures¶
Dislocation networks in ExaDiS are stored using two major classes, SerialDisNet
and DeviceDisNet
. Class DisNetManager
is used as a container to synchronize dislocation networks between the two classes for use in the different execution spaces (host CPU / device GPU).
SerialDisNet class¶
SerialDisNet
is a STL-based class that allows to easily create, manipulate, and modify dislocation networks on the host: a SerialDisNet
instance is marked for a Kokkos::Serial
execution space associated with a Kokkos::HostSpace
memory space. The SerialDisNet
class implements all low-level topological operations, e.g. split_seg()
, split_node()
, and merge_nodes()
methods. It is designed to create initial dislocation networks and perform topological operations on existing networks.
Constructors¶
SerialDisNet()
: instantiate an empty dislocation networkSerialDisNet(double Lbox)
: instantiate an empty dislocation network within a cubic cell of sideLbox
SerialDisNet(const Cell& cell)
: instantiate an empty dislocation network within a cellCell
Properties¶
Cell cell
: dislocation network cellstd::vector<DisNode> nodes
: array of nodesstd::vector<DisSeg> segs
: array of segmentsstd::vector<Conn> conn
: array of node connectivityint Nnodes_local
: number of local nodesint Nsegs_local
: number of local segments
Methods¶
int number_of_nodes()
: returns the number of nodes in the networkint number_of_segs()
: returns the number of segments in the networkNodeTag get_new_tag()
: returns a new available node tagvoid free_tag(NodeTag& tag)
: release an existing node tagvoid update_ptr()
: updates pointers to the nodes, segments and connectivity data as STL arrays may be reallocated under-the-hood, e.g. due to resize during topology changesDisNode* get_nodes()
: returns a pointer to the nodes array dataDisSeg* get_segs()
returns a pointer to the segments array dataConn* get_conn()
returns a pointer to the connectivity array datavoid add_node(const Vec3& pos)
: add a node by specifying its positionpos
void add_node(const Vec3& pos, int constraint)
: add a node by specifying its positionpos
and its constraintconstraint
void add_node(const NodeTag& tag, const Vec3& pos)
: add a node by specifying its tagtag
and positionpos
void add_node(const NodeTag& tag, const Vec3& pos, int constraint)
: add a node by specifying its tagtag
, positionpos
, and its constraintconstraint
void add_seg(int n1, int n2, const Vec3& b)
: add a segment with Burgers vectorb
connecting node at indexn1
with node at indexn2
void add_seg(int n1, int n2, const Vec3& b, const Vec3& p)
: add a segment with Burgers vectorb
and plane nornalp
connecting node at indexn1
with node at indexn2
int find_connection(int n1, int n2)
: finds in the node connectivity array ofn1
if there exists a connection (segment) to node at indexn2
void generate_connectivity()
: generate the connectivity array for all nodesdouble seg_length(int i)
: returns the length of segmenti
bool constrained_node(int i)
: returns if nodei
is a constrained nodebool discretization_node(int i)
: returns if nodei
is a discretization nodevoid update_node_plastic_strain(int i, const Vec3& pold, const Vec3& pnew, Mat33& dEp)
: update the plastic strain tensordEp
with the increment of moving nodei
from positionpold
to positionpnew
int split_seg(int i, const Vec3& pos, bool update_conn=true)
: splits segmenti
by inserting a new node at positionpos
and returns the index of the new nodeint split_node(int i, std::vector<int> arms)
: splits nodei
into a new node that contains the subset of arms indicesarms
, and returns the index of the new nodebool merge_nodes(int n1, int n2, Mat33& dEp)
: merges nodesn1
andn2
into noden1
, updates the corresponding plastic strain tensordEp
, and returns whether the merge succeededbool merge_nodes_position(int n1, int n2, const Vec3 &pos, Mat33& dEp)
: merges nodesn1
andn2
into noden1
at positionpos
, updates the corresponding plastic strain tensordEp
, and returns whether the merge succeededvoid remove_segs(std::vector<int> seglist)
: removes all segments with indices specified inseglist
from the networkvoid remove_nodes(std::vector<int> nodelist)
: removes all nodes with indices specified innodelist
from the networkvoid purge_network()
: purge the network from unconnected nodes and zero Burgers vectors segmentsstd::vector<std::vector<int> > physical_links()
: decompose the network into a set of dislocation links connecting physical network nodesdouble dislocation_density(double burgmag)
: computes the dislocation density in units of 1/m^2 given the Burgers vector scaling factorburgmag
void write_data(std::string filename)
: write the dislocation network into a file using the legacy ParaDiS.data
formatSaveNode save_node(int i)
: save a dislocation node and all its connectionsvoid restore_node(SaveNode& saved_node)
: restore a dislocation node and all its connections from a save nodesaved_node
DeviceDisNet class¶
DeviceDisNet
is a class that uses Kokkos views to store and access dislocation nodes, segments and connections for device execution (GPU): a DeviceDisNet
instance is marked for a Kokkos::DefaultExecutionSpace
execution space associated with corresponding default memory space. These will default to the highest available execution/memory spaces available at compile time (e.g. device spaces when compiling for GPU). As of now, the DeviceDisNet
class does not implement topological operations.
Constructor¶
DeviceDisNet(const Cell& cell)
: instantiates an empty dislocation network within a cellCell
Properties¶
Cell cell
: dislocation network cellT_nodes nodes
: Kokkos view of nodesT_segs segs
: Kokkos view of segmentsT_conn conn
: Kokkos view of node connectivityint Nnodes_local
: number of local nodesint Nsegs_local
: number of local segments
Methods¶
void update_ptr()
: updates network pointers (dummy forDeviceDisNet
)T_nodes::pointer_type get_nodes()
: returns a pointer to the nodes view dataT_segs::pointer_type get_segs()
returns a pointer to the segments view dataT_conn::pointer_type get_conn()
returns a pointer to the connectivity view data
DisNetManager class¶
Class DisNetManager
is used as a container to synchronize dislocation networks between the two classes SerialDisNet
and DeviceDisNet
for use in the different execution spaces. A DisNetManager
object is instantiated by providing a SerialDisNet
(resp. DeviceDisNet
) object, and a mirror DeviceDisNet
(resp. SerialDisNet
) object is automatically created. A given instance of a network type is requested by using functions get_serial_network()
and get_device_network()
. When calling these functions, a memory copy is triggered only if the requested network type instance is not marked as active to minimize memory transfers between host and device memory spaces. DisNetManager
is used as the fundamental network class associated with the ExaDiS System
object that is being propagated through the different ExaDiS modules.
Constructors¶
DisNetManager(SerialDisNet* n)
: instantiates aDisNetManager
object from aSerialDisNet
dislocation networkn
DisNetManager(DeviceDisNet* d)
: instantiates aDisNetManager
object from aDeviceDisNet
dislocation networkd
Methods¶
SerialDisNet* get_serial_network()
: returns a pointer to aSerialDisNet
instance of the dislocation networkDeviceDisNet* get_device_network()
: returns a pointer to aDeviceDisNet
instance of the dislocation networkint get_active()
: returns the currently active network type (SERIAL_ACTIVE
orDEVICE_ACTIVE
)void set_active(int a)
: sets as active the network typea = SERIAL_ACTIVE
ora = DEVICE_ACTIVE
int Nnodes_local()
: returns the number of local nodes in the networkint Nsegs_local()
: returns the number of local segments in the network
System class¶
System
is the base class in ExaDiS that contains all information about the simulated dislocation system, including the parameters, the crystal instance, and the dislocation network object. A System
object is the fundamental data structure that is being propagated from modules to modules.
Important
A System
object must be allocated using the exadis_new()
or the make_system()
helper functions to ensure it is placed on a memory space accessible to all execution spaces.
Constructors¶
System()
: instantiates an emptySystem
objectSystem* make_system(SerialDisNet* net, Crystal crystal, Params params)
: creates aSystem
object from an initial dislocation network, crystal instance, and parameters object.
Properties¶
DisNetManager* net_mngr
: dislocation network manager of the systemdouble neighbor_cutoff
: neighbor cutoff for the simulated systemParams params
: parameters of the simulated systemCrystal crystal
: crystal object of the simulated systemT_x xold
: Kokkos view to store old nodal positionsMat33 extstress
: external/applied stress tensordouble realdt
: current global time step size of the simulationMat33 dEp
: current increment of plastic strain for the time stepMat33 dWp
: current increment of plastic spin for the time stepdouble density
: current dislocation density in the systemSystemTimer timer[]
: array of timers of the systemint numdevtimer
: number of development timers of the systemSystemTimer devtimer[]
: array of development timers of the system
Methods¶
void initialize(Params _params, Crystal _crystal, SerialDisNet* network)
: initialize aSystem
object with a parameters object, a crystal instance, and an initial dislocation networkvoid register_neighbor_cutoff(double cutoff)
: register a minimum cutoff distance to be used in the simulated systemSerialDisNet* get_serial_network()
: returns a pointer to aSerialDisNet
instance of the dislocation network of the systemDeviceDisNet* get_device_network()
: returns a pointer to aDeviceDisNet
instance of the dislocation network of the systemint Nnodes_local()
: returns the local number of dislocation nodes in the systemint Nsegs_local()
: returns the local number of dislocation segments in the systemint Nnodes_total()
: returns the total number of dislocation nodes in the systemint Nsegs_total()
: returns the total number of dislocation segments in the systemvoid plastic_strain()
: computes the plastic strain resulting from the motion of all dislocation lines between the nodal positions stored inxold
and the current positionsvoid reset_glide_planes()
: reset and select appropriate glide planes for all segments in the networkvoid write_config(std::string filename)
: writes the network configuration into a file (in legacy ParaDiS format for now)void print_timers(bool dev=false)
: prints system timers