Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
PyGlideSolver.cpp
Go to the documentation of this file.
1/* This file is part of MoDELib, the Mechanics Of Defects Evolution Library.
2 * Written in 2024 by Matthew Maron <mlm335@miami.edu>
3 *
4 *
5 * MoDELib is distributed without any warranty under the
6 * GNU General Public License (GPL) v2 <http://www.gnu.org/licenses/>.
7 */
8
9#ifndef model_PyGlideSolver_cpp_
10#define model_PyGlideSolver_cpp_
11#include <random>
12#include <filesystem>
13#include <PyGlideSolver.h>
15#include <TerminalColors.h>
16#include <Eigen/StdVector>
17#include <vector>
18#include <list>
19
20
21// Functions for Adjusting Lists and Outputting Data
22void printNestedList(std::list<std::list<int>> connections) // Print the connections
23{
24 std::cout << "[\n";
25 std::list<std::list<int> >::iterator connections_itr;
26 for (connections_itr = connections.begin();
27 connections_itr != connections.end();
28 ++connections_itr)
29 {
30 std::cout << " [";
31 std::list<int>::iterator single_list_itr;
32 std::list<int>& single_list_pointer = *connections_itr;
33 for (single_list_itr = single_list_pointer.begin();
34 single_list_itr != single_list_pointer.end();
35 single_list_itr++)
36 {
37 std::cout << " " << *single_list_itr << " ";
38 }
39 std::cout << "]\n";
40 }
41 std::cout << "]";
42}
43
44void printNestedListToFile(std::list<std::list<int>>& connections, std::ofstream& myFile)
45{
46 std::list<std::list<int>>::iterator connections_itr;
47 myFile << "[\n";
48 for (connections_itr = connections.begin();
49 connections_itr != connections.end();
50 ++connections_itr)
51 {
52 myFile << " [";
53 std::list<int>::iterator single_list_itr;
54 std::list<int>& single_list_pointer = *connections_itr;
55 for (single_list_itr = single_list_pointer.begin();
56 single_list_itr != single_list_pointer.end();
57 single_list_itr++)
58 {
59 myFile << " " << *single_list_itr << " ";
60 }
61 myFile << "]\n";
62 }
63 myFile << "]";
64}
65
66void sequenceOuterConnections(std::list<std::list<int>>& connections)
67{
68 std::set<int> unique_numbers;
69 for (const auto& sublist : connections)
70 {
71 if (!sublist.empty())
72 {
73 unique_numbers.insert(sublist.front());
74 unique_numbers.insert(sublist.back());
75 }
76 }
77 std::vector<int> sorted_numbers(unique_numbers.begin(), unique_numbers.end());
78 for (size_t i = 1; i < sorted_numbers.size(); ++i)
79 {
80 if (sorted_numbers[i] != sorted_numbers[i - 1] + 1)
81 {
82 int diff = sorted_numbers[i] - (sorted_numbers[i - 1] + 1);
83 for (size_t j = i; j < sorted_numbers.size(); ++j)
84 {
85 sorted_numbers[j] -= diff;
86 }
87 }
88 }
89 std::map<int, int> adjust_map;
90 for (size_t i = 0; i < sorted_numbers.size(); ++i)
91 {
92 adjust_map[*next(unique_numbers.begin(), i)] = sorted_numbers[i];
93 }
94 for (auto& sublist : connections)
95 {
96 for (auto& num : sublist)
97 {
98 if (adjust_map.find(num) != adjust_map.end())
99 {
100 num = adjust_map[num];
101 }
102 }
103 }
104}
105
106void adjustQPConnections(std::list<std::list<int>>& connections)
107{
108 // First pass:
109 int largest_outer_num = std::numeric_limits<int>::min();
110 for (const auto& sublist : connections)
111 {
112 largest_outer_num = std::max(largest_outer_num, sublist.front());
113 largest_outer_num = std::max(largest_outer_num, sublist.back());
114 }
115 int current_value = largest_outer_num + 1;
116 // Second pass:
117 for (auto& sublist : connections)
118 {
119 if (sublist.size() > 2)
120 {
121 for (auto it = std::next(sublist.begin()); it != std::prev(sublist.end()); ++it)
122 {
123 *it = current_value++;
124 }
125 }
126 }
127}
128
129
130int findMin(const std::list<std::list<int>>& connections)
131{
132 int minVal = std::numeric_limits<int>::max();
133 for (const auto& sublist : connections)
134 {
135 for (const auto& val : sublist)
136 {
137 if (val < minVal)
138 {
139 minVal = val;
140 }
141 }
142 }
143 return minVal;
144}
145void adjustMinValueToZero(std::list<std::list<int>>& connections)
146{
147 int minVal = findMin(connections);
148 if (minVal == 0)
149 {
150 return;
151 }
152 for (auto& sublist : connections) {
153 for (auto& val : sublist) {
154 val -= minVal;
155 }
156 }
157}
158
159
160#include <DislocationNetwork.h>
161
162namespace model
163{
164
165 #ifdef _MODEL_PYBIND11_ // COMPLIED WITH PYBIND11
166
167 template <int dim>
169 /* init */ DislocationGlideSolverBase<dim>(DN_in)
170 /* init */,pyModuleName(this->DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/"+TextFileParser(this->DN.ddBase.simulationParameters.traitsIO.inputFilesFolder+"/DD.txt").readString("pyModuleName"))
171 {
172 std::filesystem::path pyModulePath(pyModuleName);
173 std::string pyModuleDir(pyModulePath.parent_path());
174 std::string pyModuleFile(pyModulePath.extension()==".py" ? pyModulePath.stem().string() : pyModulePath.filename().string());
175 std::cout<<greenBoldColor<<"Creating PyGlideSolver: dir= "<<pyModuleDir<<", file="<<pyModuleFile<<defaultColor<<std::endl;
176 //pybind11::scoped_interpreter guard{};
177 pybind11::module sys = pybind11::module::import("sys");
178 pybind11::list path = sys.attr("path");
179 path.append(pyModuleDir.c_str());
180 pyModule=pybind11::module::import(pyModuleFile.c_str());
181 }
182
183 template <int dim>
184 Eigen::MatrixXd PyGlideSolver<dim>::updateUnconnectedNodePythonVelocity(const Eigen::MatrixXd& nodePythonVelocity, const std::map<size_t, size_t>& removedNodeIDmap) const
185 {
186 std::set<size_t> removedIndices;
187 for (const auto& pair : removedNodeIDmap)
188 {
189 removedIndices.insert(pair.second);
190 }
191 Eigen::MatrixXd updatedNodePythonVelocity = Eigen::MatrixXd::Zero(nodePythonVelocity.rows() + removedIndices.size(), this->NdofXnode);
192
193 int oldRow = 0;
194 int newRow = 0;
195 for (newRow = 0; oldRow < nodePythonVelocity.rows(); ++newRow)
196 {
197 if (removedIndices.find(newRow) != removedIndices.end())
198 {
199 updatedNodePythonVelocity.row(newRow) = Eigen::RowVectorXd::Zero(this->NdofXnode); // Insert zero row
200 }
201 else
202 {
203 updatedNodePythonVelocity.row(newRow) = nodePythonVelocity.row(oldRow); // Copy existing row
204 ++oldRow;
205 }
206 }
207 return updatedNodePythonVelocity;
208 }
209
210
211 template <int dim>
213 {
214 const auto t0= std::chrono::system_clock::now();
215 std::cout<<"PyGlideSolver solving " << "\n" << std::flush;
216
217 DefectiveCrystalConfigIO<dim> configIO(".");
219 std::ofstream f_file;
220 std::ofstream F_labels;
221 this->DN.output(configIO,auxIO,f_file,F_labels);
222 // Solver input is independent of optional diagnostic output.
223 auxIO.quadraturePoints().clear();
224 for(const auto& entry : this->DN.networkLinks())
225 {
226 for(const auto& point : entry.second.lock()->quadraturePoints())
227 {
228 auxIO.quadraturePoints().emplace_back(point);
229 }
230 }
231 const auto Temperature(this->DN.ddBase.poly.T);
232 configIO.finalize();
233 const auto segmentMap(configIO.segments());
234
235 std::map<size_t, DislocationNodeIO<3>> nodeMap;
236 int k(0);
237 for (const auto &node : configIO.nodes())
238 {
239 nodeMap.emplace(node.sID, node);
240 k++;
241 }
242
243 std::map<std::pair<size_t, size_t>, std::map<size_t, DislocationQuadraturePointIO<3>>> qPointsMap;
244 std::set<std::pair<size_t, size_t>> segmentConnetions;
245 int qpSize(0);
246 for (const auto &qp : auxIO.quadraturePoints())
247 {
248 const std::pair<size_t, size_t> outerKey(std::make_pair(qp.sourceID, qp.sinkID));
249 const size_t innerKey(qp.qID);
250 qPointsMap[outerKey].emplace(innerKey, qp);
251 segmentConnetions.insert(outerKey);
252 qpSize+=1;
253 }
254 int segmentsSize(segmentConnetions.size());
255
256 std::map<size_t, size_t> nodesToRemove; // Unconnected nodes
257 size_t j(0);
258 for (const auto& node : nodeMap)
259 {
260 bool found = false;
261 for (const auto& qp : qPointsMap)
262 {
263 if (qp.first.first == node.first || qp.first.second == node.first)
264 {
265 found = true;
266 break;
267 }
268 }
269 if (!found)
270 {
271 nodesToRemove.emplace(node.first, j);
272 }
273 j++;
274 }
275 for (const auto& nodeKey : nodesToRemove)
276 {
277 nodeMap.erase(nodeKey.first);
278 }
279 int nodeSize(nodeMap.size());
280
281
282 Eigen::MatrixXd nodalPositions(Eigen::MatrixXd::Zero(nodeSize+qpSize,this->DN.NdofXnode));
283 int positionsCount(0);
284 for (const auto &node : nodeMap)
285 {
286 nodalPositions.row(positionsCount) << node.second.P.transpose()*this->DN.ddBase.poly.b_SI*1.0e10;
287 positionsCount+=1;
288 }
289 for (const auto &outerPair : qPointsMap)
290 {
291 for (const auto &innerPair : outerPair.second)
292 {
293 const auto &qp(innerPair.second);
294 nodalPositions.row(positionsCount) << qp.r.transpose()*this->DN.ddBase.poly.b_SI*1.0e10;
295 positionsCount+=1;
296 }
297 }
298
299
300 Eigen::MatrixXd nodalStresses(Eigen::MatrixXd::Zero(nodeSize+qpSize,this->DN.NdofXnode*this->DN.NdofXnode));
301 int stressesCount(nodeMap.size());
302 for (const auto &outerPair : qPointsMap)
303 {
304 for (const auto &innerPair : outerPair.second)
305 {
306 const auto &qp(innerPair.second);
307 Eigen::Matrix<double, 3, 3> tempStress(Eigen::Matrix<double,3,3>::Zero());
308 tempStress << qp.stress*this->DN.ddBase.poly.mu_SI*1e-9;
309 nodalStresses.row(stressesCount) << tempStress.reshaped<Eigen::RowMajor>().transpose();
310 stressesCount+=1;
311 }
312 }
313
314
315 Eigen::MatrixXd nodalBurgersVector(Eigen::MatrixXd::Zero(segmentsSize,this->DN.NdofXnode));
316 int burgersVectorCount(0);
317 for (const auto &outerPair : qPointsMap)
318 {
319 nodalBurgersVector.row(burgersVectorCount) << segmentMap.at(outerPair.first).b.transpose()*this->DN.ddBase.poly.b_SI*1.0e10;
320 burgersVectorCount+=1;
321 }
322
323
324 std::list<std::list<int>> segmentConnections;
325 std::list<int> singleConnection;
326 size_t qPointsCounter(1);
327 for (const auto &outerPair : qPointsMap)
328 {
329 const auto &sourceNodeID(outerPair.first.first);
330 const auto &sinkNodeID(outerPair.first.second);
331 singleConnection.push_back(sourceNodeID);
332 for (size_t k = 0; k < outerPair.second.size(); ++k)
333 {
334 singleConnection.push_back(qPointsCounter + k + nodeMap.rbegin()->first);
335 }
336 qPointsCounter += outerPair.second.size();
337 singleConnection.push_back(sinkNodeID);
338 segmentConnections.push_back(singleConnection);
339 singleConnection.erase(singleConnection.begin(),singleConnection.end());
340 }
341 sequenceOuterConnections(segmentConnections);
342 adjustQPConnections(segmentConnections);
343 adjustMinValueToZero(segmentConnections);
344 //printNestedList(segmentConnections);
345
346
347 Eigen::MatrixXd nodePythonVelocity;
348 if (nodeSize>0)
349 {
350 std::cout<< "Computing Nodal Velocities from ML..." << std::endl;
351 nodePythonVelocity = pyModule.attr("PIGNN")().attr("MLmobility")(nodalPositions,nodalStresses,nodalBurgersVector,segmentConnections,Temperature).template cast<Eigen::MatrixXd>();
352 }
353 else
354 {
355 std::cout<< "There are No Remaining Dislocations..." << std::endl;
356 nodePythonVelocity = Eigen::MatrixXd::Zero(nodeMap.size(), 3); // Returns an empty matrix if nodeSize is 0
357
358 }
359
360 if(nodePythonVelocity.rows()!=nodeSize || nodePythonVelocity.cols()!=dim || !nodePythonVelocity.allFinite())
361 {
362 throw std::runtime_error("Python glide model returned invalid nodal velocities.");
363 }
364 Eigen::MatrixXd updatedVelo = updateUnconnectedNodePythonVelocity(nodePythonVelocity, nodesToRemove);
365 Eigen::MatrixXd updatedVelocity = updatedVelo;
366 updatedVelocity /= 3.228757859764734e01; //Convert to Velocities
367
368// pybind11::print(pyModule.attr("PIGNN")().attr("MLmobility")(positionNodes,stressNodes,burgersNodes,connections,Temperature).template cast<Eigen::MatrixXd>());
369// const std::string directory = "/Users/matthewmaron/Documents/MoDELib2-ML/tutorials/DislocationDynamics/periodicDomains/uniformLoadControllerML_500K/config/";
370// const std::string base = "MLData_";
371// const std::string extension = ".txt";
372// const double runid(this->DN.ddBase.simulationParameters.runID);
373// std::ostringstream oss;
374// oss << directory << base << runid << extension;
375// std::cout << "Writing " << oss.str() << std::endl;
376// std::ofstream myfile;
377// myfile.open(oss.str());
378// myfile << "Temperature:" << " \n" << Temperature << " \n"<< " \n"<<std::endl;
379// myfile << "Positions Nodes + QP:" << " \n" << nodalPositions << " \n"<< " \n"<<std::endl;
380// myfile << "Stress Nodes + QP:" << " \n" << std::setprecision(15) << nodalStresses<< " \n"<< " \n"<<std::endl;
381// myfile << "Burgers Vectors Nodes:" << " \n" << nodalBurgersVector<< " \n"<< " \n"<<std::endl;
382// myfile << "Cell Connections:" << " \n" << std::endl;
383// printNestedListToFile(segmentConnections,myfile);
384// myfile << " \n" << " \n" << std::endl;
385// myfile << "Output Velocity:" << " \n" << nodePythonVelocity << " \n"<< " \n"<<std::endl;
386// myfile.close();
387//
388 std::cout<<magentaColor<<std::setprecision(3)<<std::scientific<<" ["<<(std::chrono::duration<double>(std::chrono::system_clock::now()-t0)).count()<<" sec]."<<defaultColor<<std::endl;
389
390 return compatiblePredictedVelocities<dim>(this->DN,updatedVelocity.reshaped<Eigen::RowMajor>());
391
392 }
393
394 #else // COMPLIED WITHOUT PYBIND11
395
396 template <int dim>
398 /* init */ DislocationGlideSolverBase<dim>(DN_in)
399 {
400 std::cout<<greenBoldColor<<"Creating PyGlideSolver"<<defaultColor<<std::endl;
401 throw std::runtime_error("PyGlideSolver must be compiled with pybind11");
402 }
403
404 template <int dim>
405 Eigen::VectorXd PyGlideSolver<dim>::getNodeVelocities() const
406 {
407 return Eigen::VectorXd();
408 }
409 #endif
410
411
412 template class PyGlideSolver<3>;
413
414}
415#endif
void sequenceOuterConnections(std::list< std::list< int > > &connections)
void printNestedList(std::list< std::list< int > > connections)
void printNestedListToFile(std::list< std::list< int > > &connections, std::ofstream &myFile)
void adjustQPConnections(std::list< std::list< int > > &connections)
int findMin(const std::list< std::list< int > > &connections)
void adjustMinValueToZero(std::list< std::list< int > > &connections)
Eigen::VectorXd getNodeVelocities() const override
Eigen::MatrixXd updateUnconnectedNodePythonVelocity(const Eigen::MatrixXd &nodePythonVelocity, const std::map< size_t, size_t > &removedNodeIDmap) const
const std::string pyModuleName
pybind11::module pyModule
PyGlideSolver(const DislocationNetwork< dim > &)
size_t InstanceCount< Derived >::count
static std::string magentaColor
Eigen::VectorXd compatiblePredictedVelocities(const Network &network, const Eigen::VectorXd &prediction)
static std::string greenBoldColor
static std::string defaultColor
const std::vector< DislocationQuadraturePointIO< dim > > & quadraturePoints() const
DislocationGlideSolverBase(const DislocationNetwork< dim > &)
int j
REAL t0
int k
int i
int e