TexGen
OctreeVoxelMesh.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2017 Mikhail Matveev
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#include "PrecompiledHeaders.h"
21#include "OctreeVoxelMesh.h"
22#include "TexGen.h"
23#include "PeriodicBoundaries.h"
24#include <iterator>
25#include <string>
26#include <algorithm>
27
28using namespace TexGen;
29
30//CTextile gTextile;
31//pair<XYZ, XYZ> g_DomainAABB;
32
33static const int corner_num_hanging[P4EST_CHILDREN] =
34#ifndef P4_TO_P8
35{ 1, 2, 2, 1 }
36#else
37{ 1, 2, 2, 4, 2, 4, 4, 1 }
38#endif
39;
40
41static const int zero = 0;
42static const int ones = P4EST_CHILDREN - 1;
43static const int *corner_to_hanging[P4EST_CHILDREN];
44
46// This stuff is defined in P4EST but by some reason it is "unresolved" when compiled
47const int p8est_face_corners[6][4] =
48{{ 0, 2, 4, 6 },
49 { 1, 3, 5, 7 },
50 { 0, 1, 4, 5 },
51 { 2, 3, 6, 7 },
52 { 0, 1, 2, 3 },
53 { 4, 5, 6, 7 }};
54const int p8est_edge_corners[12][2] =
55{{ 0, 1 },
56 { 2, 3 },
57 { 4, 5 },
58 { 6, 7 },
59 { 0, 2 },
60 { 1, 3 },
61 { 4, 6 },
62 { 5, 7 },
63 { 0, 4 },
64 { 1, 5 },
65 { 2, 6 },
66 { 3, 7 }};
67
68int COctreeVoxelMesh::max_level;
69
70vector<XYZ> COctreeVoxelMesh::cornerPoints;
71vector<XYZ> COctreeVoxelMesh::CentrePoints;
72
73vector<vector<int>> COctreeVoxelMesh::FaceX_min;
74vector<vector<int>> COctreeVoxelMesh::FaceX_max;
75vector<vector<int>> COctreeVoxelMesh::FaceY_min;
76vector<vector<int>> COctreeVoxelMesh::FaceY_max;
77vector<vector<int>> COctreeVoxelMesh::FaceZ_min;
78vector<vector<int>> COctreeVoxelMesh::FaceZ_max;
79
80CTextile COctreeVoxelMesh::gTextile;
81pair<XYZ, XYZ> COctreeVoxelMesh::g_DomainAABB;
82vector<char> COctreeVoxelMesh::materialInfo;
83
85
86// Tolerance is quarter of the max refinement
87int my_comparison(double x, double y)
88{
89 if ( fabs(x - y) < 0.25* P4EST_QUADRANT_LEN(12) / P4EST_QUADRANT_LEN(0))
90 return 1;
91 else
92 return 0;
93}
94
95// This function comes from a p4est example. It decodes tree information to node numbering.
96// I still have no idea how exactly it works :)
97static int
98lnodes_decode2 (p4est_lnodes_code_t face_code, int hanging_corner[P4EST_CHILDREN])
99{
100 if (face_code) {
101 const int c = (int) (face_code & ones);
102 int i, h;
103 int work = (int) (face_code >> P4EST_DIM);
104
105 /* These two corners are never hanging by construction. */
106 hanging_corner[c] = hanging_corner[c ^ ones] = -1;
107 for (i = 0; i < P4EST_DIM; ++i) {
108 /* Process face hanging corners. */
109 h = c ^ (1 << i);
110 hanging_corner[h ^ ones] = (work & 1) ? c : -1;
111 #ifdef P4_TO_P8
112 /* Process edge hanging corners. */
113 hanging_corner[h] = (work & P4EST_CHILDREN) ? c : -1;
114 #endif
115 work >>= 1;
116 }
117 return 1;
118 }
119 return 0;
120}
121
122// Return number of a node which is duplicated by a point or -1 if no duplicate found
123// Do the shifts etc
124int duplicatedHangingNode(double vxyz[3], double hang_coord[8][3], int hang_nums[8])
125{
126 int i = 0;
127
128 for (i = 0; i < 8; i++) {
129 if ( my_comparison(hang_coord[i][0], vxyz[0]) && my_comparison(hang_coord[i][1], vxyz[1]) && my_comparison(hang_coord[i][2], vxyz[2])) {
130 return hang_nums[i];
131 }
132 }
133
134 // Shift array for a new point
135 for (i = 0; i < 8; i++) {
136 hang_coord[i][0] = hang_coord[i+1][0];
137 hang_coord[i][1] = hang_coord[i+1][1];
138 hang_coord[i][2] = hang_coord[i+1][2];
139 hang_nums[i] = hang_nums[i+1];
140 }
141 return -1;
142}
143
144pair<int, int> most_common(vector<int> v) {
145 int currentVal = v[0];
146 int currentCount = 0;
147 int mostVal = v[0];
148 int mostCount = 0;
149
150 for (int i = 0; i < v.size(); i++) {
151 int c = count(v.begin(), v.end(), v[i]);
152 if (c > mostCount) {
153 mostCount = c;
154 mostVal = v[i];
155 }
156 }
157
158 return make_pair(mostVal, mostCount);
159}
160
161// P4EST should be initialised with initial coordinates of the unit cell vertices
162// TODO: Try to initialise P4EST with several elements to have better refinement in a certain direction
163int COctreeVoxelMesh::writeTempFile(string filename, pair<XYZ, XYZ> myDomain)
164{
165 ofstream TempFile(filename);
166 if (!TempFile) {
167 TGERROR("Cannot create an initialisation *.inp file " << filename);
168 return -1;
169 }
170 TempFile << "*HEADING" << "\n";
171 TempFile << "This is a temp input for the octree refinement" << "\n";
172 TempFile << "*NODE" << "\n";
173
174 if ( false )
175 {
176 // Starting from a single element mesh
177 TempFile << "1, " << myDomain.first.x<< ", " << myDomain.first.y << ", " << myDomain.first.z << "\n";
178 TempFile << "2, " << myDomain.second.x << ", " << myDomain.first.y << ", " << myDomain.first.z << "\n";
179 TempFile << "3, " << myDomain.first.x << ", " << myDomain.second.y << ", " << myDomain.first.z << "\n";
180 TempFile << "4, " << myDomain.second.x << ", " << myDomain.second.y << ", " << myDomain.first.z << "\n";
181
182 TempFile << "5, " << myDomain.first.x <<", " << myDomain.first.y << ", " << myDomain.second.z << "\n";
183 TempFile << "6, " << myDomain.second.x << ", " << myDomain.first.y << ", " << myDomain.second.z << "\n";
184 TempFile << "7, " << myDomain.first.x << ", " << myDomain.second.y << ", " << myDomain.second.z << "\n";
185 TempFile << "8, " << myDomain.second.x << ", " << myDomain.second.y << ", " << myDomain.second.z << "\n";
186 TempFile << "*ELEMENT,TYPE=C3D8R" << "\n";
187 TempFile << "1, 5, 7, 3, 1, 6, 8, 4, 2" << "\n";
188 }
189 else
190 {
191
192 XYZ DomSize;
193 DomSize = myDomain.second - myDomain.first;
194
195 double m_VoxSize[3];
196 m_VoxSize[0] = DomSize.x / m_XVoxels;
197 m_VoxSize[1] = DomSize.y / m_YVoxels;
198 m_VoxSize[2] = DomSize.z / m_ZVoxels;
199
200 int iNodeIndex = 1;
201 int x,y,z;
202
203 for ( z = 0; z <= m_ZVoxels; ++z )
204 {
205 for ( y = 0; y <= m_YVoxels; ++y )
206 {
207 for ( x = 0; x <=m_XVoxels; ++x )
208 {
209 XYZ Point;
210 Point.x = myDomain.first.x + m_VoxSize[0] * x;
211 Point.y = myDomain.first.y + m_VoxSize[1] * y;
212 Point.z = myDomain.first.z + m_VoxSize[2] * z;
213 TempFile << iNodeIndex << ", " << Point << "\n";
214 ++iNodeIndex;
215 }
216 }
217 }
218
219 TempFile << "*ELEMENT,TYPE=C3D8R" << "\n";
220 int iElementNumber = 1;
221 int numx = m_XVoxels + 1;
222 int numy = m_YVoxels + 1;
223
224 for ( z = 0; z < m_ZVoxels; ++z )
225 {
226 for ( y = 0; y < m_YVoxels; ++y )
227 {
228 for ( x = 0; x < m_XVoxels; ++x )
229 {
230 TempFile << iElementNumber << ", ";
231 TempFile << x +y*numx + (z+1)*numx*numy + 1 << ", " << x +(y+1)*numx + (z+1)*numx*numy + 1 << ", ";
232 TempFile << x + (y+1)*numx + z*numx*numy + 1 << ", " << x + y*numx + z*numx*numy + 1 << ", ";
233 TempFile << (x+1) +y*numx + (z+1)*numx*numy + 1 << ", " << (x+1) +(y+1)*numx + (z+1)*numx*numy + 1 << ", ";
234 TempFile << (x+1) + (y+1)*numx + z*numx*numy + 1 << ", " << (x+1) +y*numx + z*numx*numy + 1 << "\n";
235 ++iElementNumber;
236 }
237 }
238 }
239 }
240
241 TempFile.close();
242 return 0;
243}
244
245vector<int> GetFaceIndices(CMesh::ELEMENT_TYPE ElemType, const set<int> &NodeIndices)
246{
247 vector<int> facesInd;
248 int numFaces = 0;
249 if (NodeIndices.size() == 5)
250 numFaces = 1;
251 if (NodeIndices.size() == 6)
252 numFaces = 2;
253 if (NodeIndices.size() == 7)
254 numFaces = 3;
255
256 // We are in trouble! All the nodes belong to a surface. There is no way to find out which element faces are on surface
257 if (NodeIndices.size() == 8) {
258 return facesInd;
259 }
260
261 int i = 0, k = 0;
262 while (i < numFaces) {
263 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(3))
264 facesInd.push_back(0), i++;
265 if (NodeIndices.count(4) && NodeIndices.count(5) && NodeIndices.count(6) && NodeIndices.count(7))
266 facesInd.push_back(1), i++;
267 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(4) && NodeIndices.count(5))
268 facesInd.push_back(2), i++;
269 if (NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(5) && NodeIndices.count(6))
270 facesInd.push_back(3), i++;
271 if (NodeIndices.count(2) && NodeIndices.count(3) && NodeIndices.count(6) && NodeIndices.count(7))
272 facesInd.push_back(4), i++;
273 if (NodeIndices.count(3) && NodeIndices.count(0) && NodeIndices.count(7) && NodeIndices.count(4))
274 facesInd.push_back(5), i++;
275 if (k++ > numFaces) {
276 // No faces found
277 return facesInd;
278 }
279 }
280
281 return facesInd;
282}
283
284int GetFaceIndex(CMesh::ELEMENT_TYPE ElemType, const set<int> &NodeIndices)
285{
286 // Face indices taken from abaqus manual 22.1.4 Three-dimensional solid element library
287 switch (ElemType)
288 {
289 case CMesh::HEX:
290 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(3))
291 return 0;
292 if (NodeIndices.count(4) && NodeIndices.count(5) && NodeIndices.count(6) && NodeIndices.count(7))
293 return 1;
294 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(4) && NodeIndices.count(5))
295 return 2;
296 if (NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(5) && NodeIndices.count(6))
297 return 3;
298 if (NodeIndices.count(2) && NodeIndices.count(3) && NodeIndices.count(6) && NodeIndices.count(7))
299 return 4;
300 if (NodeIndices.count(3) && NodeIndices.count(0) && NodeIndices.count(7) && NodeIndices.count(4))
301 return 5;
302 break;
303 }
304 assert(false);
305 return -1;
306}
307
308set<int> GetCommonIndices(const vector<int> &SurfIndices, const vector<int> &VolIndices)
309{
310 set<int> Common;
311 vector<int>::const_iterator itSurf;
312 vector<int>::const_iterator itVol;
313 int i;
314 for (itSurf = SurfIndices.begin(); itSurf != SurfIndices.end(); ++itSurf)
315 {
316 for (itVol = VolIndices.begin(), i=0; itVol != VolIndices.end(); ++itVol, ++i)
317 {
318 if (*itSurf == *itVol)
319 {
320 Common.insert(i);
321 }
322 }
323 }
324 return Common;
325}
326
328:CVoxelMesh(Type)
329{
330 m_bTet = false;
331}
332
334{
335 p4est_destroy (p4est);
336 TGLOG("P4est object destroyed");
337 p4est_connectivity_destroy (conn);
338 TGLOG("Connectivity destoyed");
339 m_ElementsInfo.clear();
340 //Centre
341}
342
343// Boundaries are in format:
344int COctreeVoxelMesh::isBoundary(double point[3])
345{
346 if ( my_comparison(point[0], m_DomainAABB.first.x) || my_comparison(point[0], m_DomainAABB.second.x)) {
347 return 1;
348 } else {
349 if ( my_comparison(point[1], m_DomainAABB.first.y) || my_comparison(point[1], m_DomainAABB.second.y)) {
350 return 1;
351 } else {
352 if ( my_comparison(point[2], m_DomainAABB.first.z) || my_comparison(point[2], m_DomainAABB.second.z)) {
353 return 1;
354 } else {
355 return 0;
356 }
357 }
358 }
359}
360
361
362
363// This node is hanging and DOES NOT have a proper number, the master nodes should be stored
364// Number of node which is hanging is hanging_corner[i]
365int COctreeVoxelMesh::storeHangingNode(int *all_lni, int *hanging_corner, int node_i, int hanging_count, double vxyz[3])
366{
367 int c = hanging_corner[node_i]; /* Child id of quadrant. */
368 int ncontrib = corner_num_hanging[node_i ^ c];
369 const int *contrib_corner = corner_to_hanging[node_i ^ c];
370 vector<int> master_nodes;
371
372 for (int j = 0; j < ncontrib; ++j) {
373 int h = contrib_corner[j]^c;
374 master_nodes.push_back(all_lni[h] + 1);
375 }
376
377 sort(master_nodes.begin(), master_nodes.end());
378
379 /* We also keep master nodes as a string (it should be unique) and store it in
380 a map "(string)master_nodes" -> hanging_node. This will help us to identify if
381 hanging nodes duplicate
382 */
383 std::stringstream ss;
384 for(size_t i = 0; i < master_nodes.size(); ++i)
385 {
386 ss << master_nodes[i];
387 }
388 std::string s = ss.str();
389
390
392 {
393 XYZ node_coord = AllNodes[m_NodeConstraintsReverse[s]];
394 if ( my_comparison( node_coord.x, vxyz[0]) && my_comparison(node_coord.y, vxyz[1]) && my_comparison( node_coord.z, vxyz[2]) )
395 return m_NodeConstraintsReverse[s];
396 else
397 {
398 TGLOG("Hanging constr are the same but coords not!");
399 TGLOG("s = " << s << " for " << m_NodeConstraintsReverse[s]);
400 for (auto it=m_NodeConstraints.begin(); it != m_NodeConstraints.end(); ++it)
401 {
402 XYZ node_coord = AllNodes[it->first];
403 if ( my_comparison( node_coord.x, vxyz[0]) && my_comparison(node_coord.y, vxyz[1]) && my_comparison( node_coord.z, vxyz[2]) )
404 return AllNodes[it->first];
405 }
406 }
407 }
408
409 //else {
410 m_NodeConstraintsReverse.insert(make_pair(s, hanging_count));
411 m_NodeConstraints.insert(make_pair(hanging_count, master_nodes));
412 return 0;
413 //}
414
415 //m_NodeConstraints.insert(make_pair(hanging_count, master_nodes));
416 //return 0;
417}
418
419void COctreeVoxelMesh::OutputPeriodicBoundaries(ostream &Output, CTextile& Textile, int iBoundaryConditions, bool bMatrixOnly)
420{
421 Output << "*EQUATION" << "\n";
422 map<int, vector<int>>::iterator itConstraints;
423 for (itConstraints = m_NodeConstraints.begin(); itConstraints != m_NodeConstraints.end(); itConstraints++) {
424 for (int i = 0; i < 3; i++) { // Write for 3 DoFs
425 int num = (int)itConstraints->second.size();
426 Output << num + 1 << "\n";
427 Output << itConstraints->first << ", " << i + 1 << ", 1, ";
428 for (int j = 0; j < num; ++j) {
429 Output << itConstraints->second[j] << ", " << i + 1 << ", " << -1.0/num;
430 if (j == 2) {
431 Output << "\n";
432 } else {
433 if ( j < num - 1 ) {
434 Output << ", ";
435 }
436 }
437 }
438 Output << "\n";
439 }
440 }
441
443 vector<int> FaceA, FaceB, FaceC, FaceD, FaceE, FaceF;
444 vector<int> Edge1, Edge2, Edge3, Edge4, Edge5, Edge6, Edge7, Edge8, Edge9, Edge10, Edge11, Edge12;
445 int vertices[8];
446 double x,y,z;
447
448 // Sort points by coordinate
449 sort(m_boundaryPoints.begin(), m_boundaryPoints.end());
450 double x_min = m_DomainAABB.first.x;
451 double x_max = m_DomainAABB.second.x;
452 double y_min = m_DomainAABB.first.y;
453 double y_max = m_DomainAABB.second.y;
454 double z_min = m_DomainAABB.first.z;
455 double z_max = m_DomainAABB.second.z;
456
457 // The code checks if the point belongs to a vertex, edge or face
458 for (int i = 0; i < m_boundaryPoints.size(); i++) {
459 x = (double)m_boundaryPoints[i].x;
460 y = (double)m_boundaryPoints[i].y;
461 z = (double)m_boundaryPoints[i].z;
462 if ( my_comparison(x, x_min) && my_comparison(y, y_min) && my_comparison(z, z_min) ) {
463 vertices[0] = m_boundaryPoints[i].nodeNum;
464 } else if ( my_comparison(x, x_max) && my_comparison(y, y_min) && my_comparison(z, z_min) ) {
465 vertices[1] = m_boundaryPoints[i].nodeNum;
466 } else if ( my_comparison(x, x_max) && my_comparison(y, y_max) && my_comparison(z, z_min) ) {
467 vertices[2] = m_boundaryPoints[i].nodeNum;
468 } else if ( my_comparison(x, x_min) && my_comparison(y, y_max) && my_comparison(z, z_min) ) {
469 vertices[3] = m_boundaryPoints[i].nodeNum;
470 } else if ( my_comparison(x, x_min) && my_comparison(y, y_min) && my_comparison(z, z_max) ) {
471 vertices[4] = m_boundaryPoints[i].nodeNum;
472 } else if ( my_comparison(x, x_max) && my_comparison(y, y_min) && my_comparison(z, z_max) ) {
473 vertices[5] = m_boundaryPoints[i].nodeNum;
474 } else if ( my_comparison(x, x_max) && my_comparison(y, y_max) && my_comparison(z, z_max) ) {
475 vertices[6] = m_boundaryPoints[i].nodeNum;
476 } else if ( my_comparison(x, x_min) && my_comparison(y, y_max) && my_comparison(z, z_max) ) {
477 vertices[7] = m_boundaryPoints[i].nodeNum;
478 } else if ( my_comparison(x, x_min) && my_comparison(y, y_min) ) {
479 Edge1.push_back(m_boundaryPoints[i].nodeNum);
480 } else if ( my_comparison(x, x_max) && my_comparison(y, y_min) ) {
481 Edge2.push_back(m_boundaryPoints[i].nodeNum);
482 } else if ( my_comparison(x, x_max) && my_comparison(y, y_max) ) {
483 Edge3.push_back(m_boundaryPoints[i].nodeNum);
484 } else if ( my_comparison(x, x_min) && my_comparison(y, y_max) ) {
485 Edge4.push_back(m_boundaryPoints[i].nodeNum);
486 } else if ( my_comparison(x, x_min) && my_comparison(z, z_min) ) {
487 Edge5.push_back(m_boundaryPoints[i].nodeNum);
488 } else if ( my_comparison(x, x_max) && my_comparison(z, z_min) ) {
489 Edge6.push_back(m_boundaryPoints[i].nodeNum);
490 } else if ( my_comparison(x, x_max) && my_comparison(z, z_max) ) {
491 Edge7.push_back(m_boundaryPoints[i].nodeNum);
492 } else if ( my_comparison(x, x_min) && my_comparison(z, z_max) ) {
493 Edge8.push_back(m_boundaryPoints[i].nodeNum);
494 } else if ( my_comparison(y, y_min) && my_comparison(z, z_min) ) {
495 Edge9.push_back(m_boundaryPoints[i].nodeNum);
496 } else if ( my_comparison(y, y_max) && my_comparison(z, z_min) ) {
497 Edge10.push_back(m_boundaryPoints[i].nodeNum);
498 } else if ( my_comparison(y, y_max) && my_comparison(z, z_max) ) {
499 Edge11.push_back(m_boundaryPoints[i].nodeNum);
500 } else if ( my_comparison(y, y_min) && my_comparison(z, z_max) ) {
501 Edge12.push_back(m_boundaryPoints[i].nodeNum);
502 } else if ( my_comparison(x, x_max) ) {
503 FaceA.push_back(m_boundaryPoints[i].nodeNum);
504 } else if ( my_comparison(x, x_min) ) {
505 FaceB.push_back(m_boundaryPoints[i].nodeNum);
506 } else if ( my_comparison(y, y_max) ) {
507 FaceC.push_back(m_boundaryPoints[i].nodeNum);
508 } else if ( my_comparison(y, y_min) ) {
509 FaceD.push_back(m_boundaryPoints[i].nodeNum);
510 } else if ( my_comparison(z, z_max) ) {
511 FaceE.push_back(m_boundaryPoints[i].nodeNum);
512 } else if ( my_comparison(z, z_min) ) {
513 FaceF.push_back(m_boundaryPoints[i].nodeNum);
514 }
515 }
516
517 m_PeriodicBoundaries->SetFaceA( FaceA, FaceB );
518 m_PeriodicBoundaries->SetFaceB( FaceC, FaceD );
519 m_PeriodicBoundaries->SetFaceC( FaceE, FaceF );
520
533
534 for (int i = 0; i < 8; i++) {
535 m_PeriodicBoundaries->SetVertex( vertices[i] );
536 }
537
538 m_PeriodicBoundaries->CreatePeriodicBoundaries( Output, (int)AllNodes.size() + 1, Textile, iBoundaryConditions, bMatrixOnly );
539}
540
541int COctreeVoxelMesh::OutputHexElements(ostream &Output, bool bOutputMatrix, bool bOutputYarn, int Filetype )
542{
543 CTimer timer;
544 timer.start("Writing elements");
545 vector<vector<int>>::iterator itElements;
546 vector<int>::iterator itNodes;
547 int i, elem_count = 1;
548
549 if ( m_bTet)
550 {
551 TGLOG("START WRITING ELEMENTS " << m_TetElements.size());
552 for (auto itElem = m_TetElements.begin(); itElem != m_TetElements.end(); ++itElem) {
553 Output << elem_count ++ << ", ";
554 for (itNodes = itElem->begin(), i = 1; itNodes != itElem->end(); itNodes++, i++) {
555 Output << *itNodes;
556 if (i < 4) {
557 Output << ", ";
558 }
559 }
560 Output << "\n";
561 }
562// return 0;
563 }
564 else
565 {
566
567 TGLOG("START WRITING ELEMENTS " << m_AllElements.size());
568
569 for (itElements = m_AllElements.begin(); itElements != m_AllElements.end(); itElements++) {
570 Output << elem_count ++ << ", ";
571 for (itNodes = itElements->begin(), i = 1; itNodes != itElements->end(); itNodes++, i++) {
572 Output << *itNodes;
573 if (i < 8) {
574 Output << ", ";
575 }
576 }
577 Output << "\n";
578 }
579 }
580
581
582
583 timer.check("Elements written");
584 timer.stop();
585
586 if ( m_bSurface ) {
587 timer.start("Writing surfaces");
588 map<int, vector<int>>::iterator itSurfaceNodes;
589 for (itSurfaceNodes = m_SurfaceNodes.begin(); itSurfaceNodes != m_SurfaceNodes.end(); ++itSurfaceNodes) {
590 if ( itSurfaceNodes->first == -1) {
591 Output << "*NSET, NSET=SURFACE-NODES-MATRIX" << "\n";
592 } else {
593 Output << "*NSET, NSET=SURFACE-NODES-YARN" << itSurfaceNodes->first << "\n";
594 }
595 WriteValues(Output, itSurfaceNodes->second, 16);
596 }
597
598 map<int, vector< pair<int,int> > >::iterator itSurfaceFaces;
599 for (itSurfaceFaces = m_SurfaceElementFaces.begin(); itSurfaceFaces != m_SurfaceElementFaces.end(); ++itSurfaceFaces) {
600 if (itSurfaceFaces->first == -1) {
601 Output << "*SURFACE, NAME=SURFACE-MATRIX" << "\n";
602 } else {
603 Output << "*SURFACE, NAME=SURFACE-YARN" << itSurfaceFaces->first << "\n";
604 }
605 vector< pair<int, int> >::iterator itFaces;
606 for (itFaces = itSurfaceFaces->second.begin(); itFaces != itSurfaceFaces->second.end(); ++itFaces) {
607 Output << itFaces->first << ", S" << itFaces->second << "\n";
608 }
609 }
610
611 timer.check("Surfaces written");
612 timer.stop();
613 }
614
615 return elem_count;
616}
617
618// Uniform refinement
619int COctreeVoxelMesh::refine_fn_uni(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * quadrant)
620{
621 return 1;
622}
623
624void COctreeVoxelMesh::FindLocMinMax( int& XMin, int& XMax, int& YMin, int& YMax, XYZ& Min, XYZ& Max )
625{
626 double x_dist = (g_DomainAABB.second.x - g_DomainAABB.first.x)/pow(2, max_level);
627 double y_dist = (g_DomainAABB.second.y - g_DomainAABB.first.y)/pow(2, max_level);
628 XMin = (int)floor((Min.x - g_DomainAABB.first.x)/ x_dist);
629 XMax = (int)ceil((Max.x - g_DomainAABB.first.x) / x_dist);
630 YMin = (int)floor((Min.y - g_DomainAABB.first.y) / y_dist);
631 YMax = (int)ceil((Max.y - g_DomainAABB.first.y) / y_dist);
632}
633
634// Refine all boundary elememnts to the maximum
635int COctreeVoxelMesh::refine_fn_periodic(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * quadrant)
636{
637 vector<XYZ> CornerPoints;
638 vector<POINT_INFO> CornerInfo;
639 XYZ Point;
640 int refine = 0;
641 p4est_quadrant_t node_quadrant;
642 XYZ Min, Max;
643 double vxyz[3];
644
645 // Don't refine more than needed
646 if (quadrant->level > max_level - 1) {
647 return 0;
648 }
649
650 // Find the min and max x,y,z coordinates
651 for (int node_i=0; node_i < 8; node_i++) {
652 p4est_quadrant_corner_node(quadrant, node_i, &node_quadrant);
653 p4est_qcoord_to_vertex (p4est->connectivity, which_tree, node_quadrant.x, node_quadrant.y, node_quadrant.z, vxyz);
654 Point.x = vxyz[0];
655 Point.y = vxyz[1];
656 Point.z = vxyz[2];
657
658 if (node_i == 0) {
659 Min.x = Max.x = Point.x;
660 Min.y = Max.y = Point.y;
661 Min.z = Max.z = Point.z;
662 } else {
663 if (Point.x < Min.x)
664 Min.x = Point.x;
665 if (Point.x > Max.x)
666 Max.x = Point.x;
667
668 if (Point.y < Min.y)
669 Min.y = Point.y;
670 if (Point.y > Max.y)
671 Max.y = Point.y;
672
673 if (Point.z < Min.z)
674 Min.z = Point.z;
675 if (Point.z > Max.z)
676 Max.z = Point.z;
677 }
678 }
679
680 // X boundaries
681 if (my_comparison(Min.x, g_DomainAABB.first.x) || my_comparison(Max.x, g_DomainAABB.second.x) ) {
682 return 1;
683 }
684
685 // Y boundaries
686 if ( my_comparison(Min.y, g_DomainAABB.first.y) || my_comparison(Max.y, g_DomainAABB.second.y) ) {
687 return 1;
688 }
689
690 // Z boundaries
691 if ( my_comparison(Min.z, g_DomainAABB.first.z) || my_comparison(Max.z, g_DomainAABB.second.z) ) {
692 return 1;
693 }
694
695 return 0;
696}
697
698// Refinement only if at least two dissimilar materials are within an element
699int COctreeVoxelMesh::refine_fn(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * quadrant)
700{
701 vector<XYZ> CornerPoints;
702 vector<POINT_INFO> CornerInfo;
703 XYZ Point;
704 int refine = 0;
705 p4est_quadrant_t node_quadrant;
706 double x_min, x_max, y_min, y_max, z_min, z_max;
707 double vxyz[3];
708 double cx, cy, cz;
709 cx = cy = cz = 0;
710 int trig = 0;
711
712 // We do not want to refine deeper than a given maximum level.
713 if (quadrant->level > max_level - 1) {
714 return 0;
715 }
716
717 if (quadrant->level <2) {
718 return 1;
719 }
720
721 for (int node_i=0; node_i < 8; node_i++) {
722 p4est_quadrant_corner_node(quadrant, node_i, &node_quadrant);
723 p4est_qcoord_to_vertex (p4est->connectivity, which_tree, node_quadrant.x, node_quadrant.y, node_quadrant.z, vxyz);
724 Point.x = vxyz[0];
725 Point.y = vxyz[1];
726 Point.z = vxyz[2];
727 cx += 1.0/8.0 *vxyz[0];
728 cy += 1.0/8.0 *vxyz[1];
729 cz += 1.0/8.0 *vxyz[2];
730
731 CornerPoints.push_back(Point);
732
733 if (node_i == 0) {
734 x_min = Point.x; x_max = Point.x;
735 y_min = Point.y; y_max = Point.y;
736 z_min = Point.z; z_max = Point.z;
737 } else {
738 if (Point.x < x_min)
739 x_min = Point.x;
740 if (Point.x > x_max)
741 x_max = Point.x;
742 if (Point.y < y_min)
743 y_min = Point.y;
744 if (Point.y > y_max)
745 y_max = Point.y;
746 if (Point.z < z_min)
747 z_min = Point.z;
748 if (Point.z > z_max)
749 z_max = Point.z;
750 }
751 }
752
753 double coef = 1.01;
754 vector<XYZ> ExtraPoints;
755 for (int i = 0; i < 8; i++) {
756 XYZ NewPoint;
757 NewPoint.x = (CornerPoints[i].x - cx)*coef + cx;
758 NewPoint.y = (CornerPoints[i].y - cy)*coef + cy;
759 NewPoint.z = (CornerPoints[i].z - cz)*coef + cz;
760 ExtraPoints.push_back(NewPoint);
761 }
762 ExtraPoints.push_back(XYZ(cx, cy, cz));
763 CornerPoints.push_back(XYZ(cx, cy, cz));
764
765 if (getPointsInfo(CornerPoints, max_level ) == 1 || getPointsInfo(ExtraPoints, max_level) == 1 )
766 return 1;
767
768 return 0;
769}
770
771// After main refinement is done we want to ensure that there are no hanging nodes at the surface
772int COctreeVoxelMesh::refine_fn_post(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * quadrant)
773{
774 vector<XYZ> CornerPoints;
775 vector<XYZ> ExtraPoints;
776 vector<POINT_INFO> ExtraInfo;
777 XYZ Point;
778 p4est_quadrant_t node_quadrant;
779 double vxyz[3];
780 XYZ CentrePoint;
781 CentrePoint.x = 0;
782 CentrePoint.y = 0;
783 CentrePoint.z = 0;
784
785 // We do not want to refine deeper than a given maximum level.
786 if (quadrant->level > max_level -1) {
787 return 0;
788 }
789
790
791 //int trig = 0;
792 for (int i = 0; i < 8; i++) {
793 p4est_quadrant_corner_node(quadrant, i, &node_quadrant);
794 p4est_qcoord_to_vertex (p4est->connectivity, which_tree, node_quadrant.x, node_quadrant.y, node_quadrant.z, vxyz);
795 Point.x = vxyz[0];
796 Point.y = vxyz[1];
797 Point.z = vxyz[2];
798
799 CentrePoint.x += vxyz[0] * 1.0/8.0;
800 CentrePoint.y += vxyz[1] * 1.0/8.0;
801 CentrePoint.z += vxyz[2] * 1.0/8.0;
802
803 CornerPoints.push_back(Point);
804 }
805
806 ExtraPoints.push_back(CentrePoint);
807 double coef = 2.01;
808 for (int i = 0; i < 8; i++) {
809 XYZ NewPoint;
810 //NewPoint.x = (CornerPoints[i].x - CentrePoint.x)*coef + CentrePoint.x;
811 //NewPoint.y = (CornerPoints[i].y - CentrePoint.y)*coef + CentrePoint.y;
812 //NewPoint.z = (CornerPoints[i].z - CentrePoint.z)*coef + CentrePoint.z;
813 NewPoint = (CornerPoints[i] - CentrePoint)*coef + CentrePoint;
814 ExtraPoints.push_back(NewPoint);
815
816 NewPoint.x = (CornerPoints[i].x - CentrePoint.x)*coef + CentrePoint.x;
817 NewPoint.y = CentrePoint.y;
818 NewPoint.z = CentrePoint.z;
819 ExtraPoints.push_back(NewPoint);
820
821 NewPoint.x = CentrePoint.x;
822 NewPoint.y = (CornerPoints[i].y - CentrePoint.y)*coef + CentrePoint.y;
823 NewPoint.z = CentrePoint.z;
824 ExtraPoints.push_back(NewPoint);
825
826 NewPoint.x = CentrePoint.x;
827 NewPoint.y = CentrePoint.y;
828 NewPoint.z = (CornerPoints[i].z - CentrePoint.z)*coef + CentrePoint.z;
829 ExtraPoints.push_back(NewPoint);
830 }
831
832 coef = 1.25;
833 for (int i = 0; i < 8; i++) {
834 XYZ NewPoint;
835 NewPoint.x = (CornerPoints[i].x - CentrePoint.x)*coef + CentrePoint.x;
836 NewPoint.y = (CornerPoints[i].y - CentrePoint.y)*coef + CentrePoint.y;
837 NewPoint.z = (CornerPoints[i].z - CentrePoint.z)*coef + CentrePoint.z;
838 ExtraPoints.push_back(NewPoint);
839
840 NewPoint.x = (CornerPoints[i].x - CentrePoint.x)*coef + CentrePoint.x;
841 NewPoint.y = CentrePoint.y;
842 NewPoint.z = CentrePoint.z;
843 ExtraPoints.push_back(NewPoint);
844
845 NewPoint.x = CentrePoint.x;
846 NewPoint.y = (CornerPoints[i].y - CentrePoint.y)*coef + CentrePoint.y;
847 NewPoint.z = CentrePoint.z;
848 ExtraPoints.push_back(NewPoint);
849
850 NewPoint.x = CentrePoint.x;
851 NewPoint.y = CentrePoint.y;
852 NewPoint.z = (CornerPoints[i].z - CentrePoint.z)*coef + CentrePoint.z;
853 ExtraPoints.push_back(NewPoint);
854 }
855
856 if (getPointsInfo(ExtraPoints, max_level) == 1)
857 return 1;
858
859 return 0;
860}
861
862// Return 1 is at least one of the points is not the same material as others
863// Return 0 is all the points are from the same materials
864int COctreeVoxelMesh::getPointsInfo(vector<XYZ> myPoints, int refineLevel)
865{
866 double x0 = g_DomainAABB.first.x;
867 double y0 = g_DomainAABB.first.y;
868 double z0 = g_DomainAABB.first.z;
869 double x_length = g_DomainAABB.second.x - x0;
870 double y_length = g_DomainAABB.second.y - y0;
871 double z_length = g_DomainAABB.second.z - z0;
872
873 double dx = x_length / pow(2, refineLevel) / g_XVoxels;
874 double dy = y_length / pow(2, refineLevel) / g_YVoxels;
875 double dz = z_length / pow(2, refineLevel) / g_ZVoxels;
876
877 int num = pow(2, refineLevel) + 1;
878
879 /* Works for 1x1x1
880 int row_len = num;
881 int layer_len = num * num;
882 */
883 int row_len = num * g_XVoxels;
884 int layer_len = row_len * num * g_YVoxels;
885
886 vector<XYZ>::const_iterator itPoint;
887 int previousMaterial;
888 int i = 0;
889
890 for (itPoint = myPoints.begin(); itPoint != myPoints.end(); ++itPoint)
891 {
892 double x = itPoint->x;
893 double y = itPoint->y;
894 double z = itPoint->z;
895
896 if ( x > x0 + x_length )
897 x -= x_length;
898
899 if ( x < x0 )
900 x += x_length;
901
902 if ( y > y0 + y_length )
903 y -= y_length;
904
905 if ( y < y0 )
906 y += y_length;
907
908 if ( z > z0 + z_length )
909 z -= z_length;
910
911 if ( z < z0 )
912 z += z_length;
913
914 int index_i = ( (x - x0)/ dx - floor((x - x0) / dx) >= 0.5 ) ? ceil((x - x0) / dx) : floor((x - x0) / dx);
915 int index_j = ( (y - y0)/ dy - floor((y - y0) / dy) >= 0.5 ) ? ceil((y - y0) / dy) : floor((y - y0) / dy);
916 int index_k = ( (z - z0)/ dz - floor((z - z0) / dz) >= 0.5 ) ? ceil((z - z0) / dz) : floor((z - z0) / dz);
917
918 /* Maybe this is still needed for 1x1x1
919 if ( index_i + row_len * index_j + layer_len * index_k > num * num * num || index_i + row_len * index_j + layer_len * index_k < 0)
920 {
921 TGERROR("Something is not right - index is outside of stored info");
922 TGERROR("X, Y, Z: " << x << ", " << y << ", " << z);
923 return 0;
924 }
925 */
926
927 //TGLOG("X: " << x << "(" << index_i << "), Y: " << y << "(" << index_j << "), Z: " << z << "(" << index_k << ")");
928
929 if (i == 0)
930 previousMaterial = materialInfo[index_i + row_len * index_j + layer_len * index_k];
931
932 if (i > 0 && previousMaterial != materialInfo[index_i + row_len * index_j + layer_len * index_k] )
933 return 1;
934
935 i++;
936 }
937
938 return 0;
939}
940
942{
943 vector<XYZ> myPoints;
944 vector<POINT_INFO> temp;
945 double x0 = g_DomainAABB.first.x;
946 double y0 = g_DomainAABB.first.y;
947 double z0 = g_DomainAABB.first.z;
948 double x_length = g_DomainAABB.second.x - x0;
949 double y_length = g_DomainAABB.second.y - y0;
950 double z_length = g_DomainAABB.second.z - z0;
951
952 double dx = x_length / pow(2, refineLevel) / m_XVoxels;
953 double dy = y_length / pow(2, refineLevel) / m_YVoxels;
954 double dz = z_length / pow(2, refineLevel) / m_ZVoxels;
955
956 int num = pow(2, refineLevel) + 1;
957
958 /* Works for 1x1x1 voxels
959 for (int k = 0; k < num; k++)
960 for (int j = 0; j < num; j++)
961 for (int i = 0; i < num; i++)
962 myPoints.push_back(XYZ(x0 + dx*i, y0 + dy*j, z0 + dz*k));
963 */
964 for (int k = 0; k < num * m_ZVoxels; k++)
965 for (int j = 0; j < num * m_YVoxels; j++)
966 for (int i = 0; i < num * m_XVoxels; i++)
967 myPoints.push_back(XYZ(x0 + dx*i, y0 + dy*j, z0 + dz*k));
968
969 //TGLOG("Number of points : "<< k*j*i);
970 temp.clear();
971 gTextile.GetPointInformation(myPoints,temp);
972
973 vector<POINT_INFO>::const_iterator itInfo;
974
975 materialInfo.clear();
976 TGLOG("Infos " << myPoints.size());
977
978 for (itInfo = temp.begin(); itInfo != temp.end(); ++itInfo)
979 materialInfo.push_back(itInfo->iYarnIndex);
980
981 TGLOG("Info stored. Elements = " << materialInfo.size());
982 temp.clear();
983}
984
985
986
988 vector <XYZ> myPoints;
989 for (int i = 0; i < CentrePoints.size(); i++) {
990 myPoints.push_back(CentrePoints[i]);
991 for (int j = 0; j < 8; j++) {
992 myPoints.push_back(cornerPoints[i*8 + j]);
993 }
994 }
995 vector<POINT_INFO> myInfo;
996 gTextile.GetPointInformation(myPoints, myInfo);
997
998 POINT_INFO info;
999 for (int i = 0; i < CentrePoints.size(); i++) {
1000 vector<int> v;
1001 for (int j = 0; j < 9; j++) {
1002 v.push_back(myInfo[i*9 + j].iYarnIndex);
1003 }
1004 pair<int, int> mat = most_common(v);
1005 vector<int>::iterator it = find(v.begin(), v.end(), mat.first);
1006 int pos = distance(v.begin(), it);
1007 v.clear();
1008 //m_ElementsInfo.push_back(myInfo[i*9 + pos]);
1009 m_ElementsInfo.push_back(myInfo[i*9 + 0 * pos]);
1010 }
1011}
1012
1013int COctreeVoxelMesh::CreateP4ESTRefinement(int min_level, int refine_level)
1014{
1015 // The MPI is not included in TexGen - initialise dummy mpi objects for purpose of P4EST
1016 int mpiret = sc_MPI_Init (NULL, NULL);
1017 SC_CHECK_MPI (mpiret);
1018 sc_MPI_Comm mpicomm = sc_MPI_COMM_WORLD;
1019
1020 //conn = p8est_connectivity_new_unitcube ();
1021 //p4est = p4est_new (mpicomm, conn, 0, NULL, NULL);
1022
1023 int len = pow(2, max_level);
1024 for (int i = 0; i < len + 1; i++) {
1025 vector<int> temp(len, 0);
1026 FaceX_min.push_back(temp);
1027 FaceX_max.push_back(temp);
1028 FaceY_min.push_back(temp);
1029 FaceY_max.push_back(temp);
1030 FaceZ_min.push_back(temp);
1031 FaceZ_max.push_back(temp);
1032 }
1033
1034 if (writeTempFile("temp_octree.inp", m_DomainAABB) == -1) {
1035 return -1;
1036 }
1037
1039
1040 TGLOG("Stored");
1041
1042 // Create a forest from the inp file
1043 conn = p4est_connectivity_read_inp ("temp_octree.inp");
1044
1045 if (conn == NULL) {
1046 TGERROR("Failed to read a valid connectivity from temp_octree.inp");
1047 return -1;
1048 }
1049 // Create a forest that is not refined; it consists of the root octant.
1050 p4est = p4est_new (mpicomm, conn, 0, NULL, NULL);
1051
1052 /* Comment from P4EST: Refine the forest iteratively, load balancing at each iteration.
1053 * This is important when starting with an unrefined forest */
1054 // Refine all elements to min_level
1055 for (int level = 0; level < min_level; ++level) {
1057 p4est_partition (p4est, 0, NULL);
1058 }
1059
1060 // Refine elements which have multiple materials within them
1061 for (int level = min_level; level < refine_level; ++level) {
1062 p4est_refine (p4est,1, refine_fn, NULL);
1063 p4est_partition (p4est, 0, NULL);
1064
1065 p4est_refine (p4est, 0, refine_fn_periodic, NULL);
1066 p4est_partition (p4est, 0, NULL);
1067 }
1068
1069 // P4EST_CONNECT_FULL is used for 2:1 balancing across all faces, edges and corners
1070 p4est_balance (p4est, P4EST_CONNECT_FULL, NULL);
1071 p4est_partition (p4est, 0, NULL);
1072 TGLOG("Post-refinement now");
1073
1074 // Post refinement is needed to have the boundaries of the inclusions to be represented by the smallest refinement only
1075
1076 for (int i = 0; i < 3; i++) {
1077 p4est_refine (p4est, 0, refine_fn_post, NULL);
1078 //p4est_refine (p4est, 1, refine_fn_periodic, NULL);
1079 p4est_partition (p4est, 0, NULL);
1080 p4est_balance (p4est, P4EST_CONNECT_FULL, NULL);
1081 p4est_partition (p4est, 0, NULL);
1082 }
1083
1084 materialInfo.clear();
1085
1086 return 0;
1087}
1088
1089void COctreeVoxelMesh::SaveVoxelMesh(CTextile &Textile, string OutputFilename, int XVoxNum, int YVoxNum, int ZVoxNum, int min_level, int refine_level, bool smoothing, int iter, double s1, double s2, bool surfaceOutput)
1090{
1091 m_XVoxels = XVoxNum;
1092 m_YVoxels = YVoxNum;
1093 m_ZVoxels = ZVoxNum;
1094
1095 g_XVoxels = XVoxNum;
1096 g_YVoxels = YVoxNum;
1097 g_ZVoxels = ZVoxNum;
1098
1099
1100 CTimer timer;
1101 max_level = refine_level;
1103 m_smoothIter = iter;
1104 m_smoothCoef1 = s1;
1105 m_smoothCoef2 = s2;
1106 m_bSurface = surfaceOutput;
1107
1108 gTextile = Textile;
1109 m_DomainAABB = Textile.GetDomain()->GetMesh().GetAABB();
1111 //m_bTet = bTet;
1112
1113 if (min_level < 0 || refine_level < 0 || min_level > refine_level) {
1114 TGERROR("Incorrect refinement levels specified. min_level should be lower than refine_level");
1115 return;
1116 }
1117
1118 if ( m_bSmooth) {
1119 if (!( ((s1 > 0 && s1 == s2) || (s1 > 0 && s2 < 0 && s1 < -s2)) && m_smoothIter > 0)) {
1120 TGERROR("Smoothing coefficients are not correct. It should be:\n1. Coef1 = Coef2 - for Laplacian smoothing\n2. Coef1 < -Coef2 (and Coef1 > 0) - for non-shrinking smoothing\nIter > 0");
1121 return;
1122 }
1123 }
1124
1125 timer.start("Starting octree refinement...");
1126 if (CreateP4ESTRefinement(min_level, refine_level) == -1)
1127 return;
1128
1129 CVoxelMesh::SaveVoxelMesh(Textile, OutputFilename, m_XVoxels, m_YVoxels, m_ZVoxels, true, true, SINGLE_LAYER_RVE);
1130
1131 timer.check("Octree refinement finished");
1132 timer.stop();
1133}
1134
1136{
1137 return true;
1138}
1139
1140
1142{
1143 p4est_ghost_t *ghost;
1144 p4est_lnodes_t *lnodes;
1145 // Create the ghost layer to learn about parallel neighbors.
1146 ghost = p4est_ghost_new (p4est, P4EST_CONNECT_FULL);
1147 // Create a node numbering for continuous linear finite elements.
1148 lnodes = p4est_lnodes_new (p4est, ghost, 1 );
1149 // Destroy the ghost structure -- no longer needed after node creation.
1150 p4est_ghost_destroy (ghost);
1151 ghost = NULL;
1152 CentrePoints.clear();
1153
1154 // Assign independent nodes for hanging nodes (this piece is copied from one of the examples provided with p4est)
1155 corner_to_hanging[0] = &zero;
1160 corner_to_hanging[ones - 2] = p4est_face_corners[2];
1161 corner_to_hanging[ones - 1] = p4est_face_corners[0];
1163
1164 int i, k, node_i, q, Q, used, anyhang, hanging_corner[P4EST_CHILDREN], node_elements[8], hang_nums[8];
1165 int elem_order[8] = {0, 2, 3, 1, 4, 6, 7, 5}; // That is how elements should be ordered in abaqus
1166 sc_array_t *tquadrants;
1167 p4est_topidx_t tt;
1168 p4est_locidx_t all_lni[P4EST_CHILDREN];
1169 p4est_tree_t *tree;
1170 p4est_quadrant_t *quad, node_quadrant; //,node;
1171
1172 double vxyz[3];
1173 int node_count = 0;
1174 int hanging_count = pow((pow(2,max_level) + 1),3) * (m_XVoxels + 1) * (m_YVoxels + 1) * (m_ZVoxels + 1); // Offset for numbering hanging nodes
1175
1176 // The mesh is stored as a tree and all of the last 8 hanging nodes belong to one
1177 // parent element. Therefore, it is enough to store last 8 elements to eliminate duplicates
1178 double hang_coord[8][3];
1179
1180 int ElemCount = 1;
1181 // Loop over all the trees
1182 for (tt = p4est->first_local_tree, k = 0; tt <= p4est->last_local_tree; ++tt) {
1183 tree = p4est_tree_array_index (p4est->trees, tt);
1184 tquadrants = &tree->quadrants;
1185 Q = (p4est_locidx_t) tquadrants->elem_count;
1186 // loop over all the quadrant in the tree
1187 for (q = 0; q < Q; ++q, ++k) {
1188 XYZ CurrentCentre;
1189 // Extract an element by index
1190 quad = p4est_quadrant_array_index (tquadrants, q);
1191 // Get the numbers of the corners nodes
1192 for (i = 0; i < P4EST_CHILDREN; ++i) {
1193 all_lni[i] = lnodes->element_nodes[P4EST_CHILDREN * k + i];
1194 }
1195
1196 // Figure out the hanging corners on this element, if any.
1197 anyhang = lnodes_decode2 (lnodes->face_code[k], hanging_corner);
1198
1199 vector<int> elemNodes;
1200
1201 // Loop through nodes
1202 for(node_i = 0; node_i < P4EST_CHILDREN; node_i++) {
1203 // Extract the coordinates
1204 p4est_quadrant_corner_node(quad, node_i, &node_quadrant);
1205 p4est_qcoord_to_vertex (p4est->connectivity, tt, node_quadrant.x, node_quadrant.y, node_quadrant.z, vxyz);
1206
1207
1208 // The node is not hanging and therefore has correct numbering
1209 if (!anyhang || hanging_corner[node_i] == -1) {
1210
1211 if (node_count - 1 < lnodes->element_nodes[P4EST_CHILDREN * k + node_i]) {
1212 AllNodes.insert(make_pair(lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1, XYZ(vxyz[0], vxyz[1], vxyz[2])));
1213 node_count++;
1214
1215 if ( isBoundary(vxyz) ) {
1216 m_boundaryPoints.push_back(Point(lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1, vxyz[0], vxyz[1], vxyz[2]));
1217 }
1218 }
1219
1220 // Keep the information for the element connectivity
1221 node_elements[node_i] = lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1;
1222
1223 } else {
1224 // Check if that hanging corner has been already written. This function call only check recent elements not the full list
1225 used = duplicatedHangingNode(vxyz, hang_coord, hang_nums);
1226
1227 if ( used > 0 ) {
1228 // The node has already appeared and therefore does not need to be written again, use it to create an element only
1229 node_elements[node_i] = used;
1230
1231 } else {
1232
1233 int loc_hang = storeHangingNode(all_lni, hanging_corner, node_i, hanging_count + 1, vxyz);
1234 if ( loc_hang != 0 ) {
1235
1236
1237 node_elements[node_i] = loc_hang;
1238 } else {
1239 AllNodes.insert(make_pair(++hanging_count, XYZ(vxyz[0], vxyz[1], vxyz[2])));
1240 node_elements[node_i] = hanging_count;
1241 hang_coord[7][0] = vxyz[0];
1242 hang_coord[7][1] = vxyz[1];
1243 hang_coord[7][2] = vxyz[2];
1244 hang_nums[7] = hanging_count;
1245 }
1246
1247 /*
1248 // The node has not appeared earlier, write it, form an element, store the node for further comparisons
1249 AllNodes.insert(make_pair(++hanging_count, XYZ(vxyz[0], vxyz[1], vxyz[2])));
1250 node_elements[node_i] = hanging_count;
1251 hang_coord[7][0] = vxyz[0];
1252 hang_coord[7][1] = vxyz[1];
1253 hang_coord[7][2] = vxyz[2];
1254 hang_nums[7] = hanging_count;
1255
1256 // Write constraints for the hanging node
1257 storeHangingNode(all_lni, hanging_corner, node_i, hanging_count);
1258 */
1259 }
1260 }
1261 CurrentCentre.x += 1.0/8.0 * vxyz[0];
1262 CurrentCentre.y += 1.0/8.0 * vxyz[1];
1263 CurrentCentre.z += 1.0/8.0 * vxyz[2];
1264 cornerPoints.push_back(XYZ(vxyz[0], vxyz[1], vxyz[2]));
1265 }
1266
1267 for(i = 0; i < 8; i++) {
1268 elemNodes.push_back(node_elements[elem_order[i]]);
1269 m_NodesEncounter[node_elements[i]].push_back(ElemCount);
1270 }
1271 ElemCount++;
1272 CentrePoints.push_back(CurrentCentre);
1273 m_AllElements.push_back(elemNodes);
1274
1275 // Create connectivity for the nodes in the element (only if it is the final level of the refinement)
1276 if ( quad->level == max_level ) {
1277 vector<int>::iterator itNodes;
1278 int i = 0;
1279 vector<int> temp;
1280 for (itNodes = elemNodes.begin(); itNodes != elemNodes.end(); ++itNodes, i++) {
1281 // No need to iterate through the elements which have this node as the loop will go through
1282 // these elements anyway. Only store the information available for this element - neighbouring nodes etc
1283 int a[3];
1284 switch(i) {
1285 case 0: { a[0] = elemNodes[1]; a[1] = elemNodes[3]; a[2] = elemNodes[4]; break; }
1286 case 1: { a[0] = elemNodes[0]; a[1] = elemNodes[2]; a[2] = elemNodes[5]; break; }
1287 case 2: { a[0] = elemNodes[1]; a[1] = elemNodes[3]; a[2] = elemNodes[6]; break; }
1288 case 3: { a[0] = elemNodes[0]; a[1] = elemNodes[2]; a[2] = elemNodes[7]; break; }
1289 case 4: { a[0] = elemNodes[0]; a[1] = elemNodes[5]; a[2] = elemNodes[7]; break; }
1290 case 5: { a[0] = elemNodes[1]; a[1] = elemNodes[4]; a[2] = elemNodes[6]; break; }
1291 case 6: { a[0] = elemNodes[2]; a[1] = elemNodes[5]; a[2] = elemNodes[7]; break; }
1292 case 7: { a[0] = elemNodes[3]; a[1] = elemNodes[4]; a[2] = elemNodes[6]; break; }
1293 }
1294 m_NeighbourNodes[*itNodes].push_back(a[0]);
1295 m_NeighbourNodes[*itNodes].push_back(a[1]);
1296 m_NeighbourNodes[*itNodes].push_back(a[2]);
1297 }
1298 }
1299
1300 elemNodes.clear();
1301 }
1302 }
1303 p4est_lnodes_destroy (lnodes);
1304 TGLOG("Num of elements: " << m_AllElements.size());
1305
1306}
1307
1308
1309
1310/*
1311void COctreeVoxelMesh::ConvertOctreeToNodes()
1312{
1313 p4est_ghost_t *ghost;
1314 p4est_lnodes_t *lnodes;
1315 // Create the ghost layer to learn about parallel neighbors.
1316 ghost = p4est_ghost_new (p4est, P4EST_CONNECT_FULL);
1317 // Create a node numbering for continuous linear finite elements.
1318 lnodes = p4est_lnodes_new (p4est, ghost, 1 );
1319 // Destroy the ghost structure -- no longer needed after node creation.
1320 p4est_ghost_destroy (ghost);
1321 ghost = NULL;
1322 CentrePoints.clear();
1323
1324 // Assign independent nodes for hanging nodes (this piece is copied from one of the examples provided with p4est)
1325 corner_to_hanging[0] = &zero;
1326 corner_to_hanging[1] = p8est_edge_corners[0];
1327 corner_to_hanging[2] = p8est_edge_corners[4];
1328 corner_to_hanging[3] = p8est_face_corners[4];
1329 corner_to_hanging[4] = p8est_edge_corners[8];
1330 corner_to_hanging[ones - 2] = p4est_face_corners[2];
1331 corner_to_hanging[ones - 1] = p4est_face_corners[0];
1332 corner_to_hanging[ones] = &ones;
1333
1334 int i, k, node_i, q, Q, used, anyhang, hanging_corner[P4EST_CHILDREN], node_elements[8], hang_nums[8];
1335 int elem_order[8] = {0, 2, 3, 1, 4, 6, 7, 5}; // That is how elements should be ordered in abaqus
1336 sc_array_t *tquadrants;
1337 p4est_topidx_t tt;
1338 p4est_locidx_t all_lni[P4EST_CHILDREN];
1339 p4est_tree_t *tree;
1340 p4est_quadrant_t *quad, node_quadrant; //,node;
1341
1342 double vxyz[3];
1343 int node_count = 0;
1344 int hanging_count = 9000000; // Large number for node offest
1345
1346 // The mesh is stored as a tree and all of the last 8 hanging nodes belong to one
1347 // parent element. Therefore, it is enough to store last 8 elements to eliminate duplicates
1348 double hang_coord[8][3];
1349
1350 int ElemCount = 1;
1351 // Loop over all the trees
1352 for (tt = p4est->first_local_tree, k = 0; tt <= p4est->last_local_tree; ++tt) {
1353 tree = p4est_tree_array_index (p4est->trees, tt);
1354 tquadrants = &tree->quadrants;
1355 Q = (p4est_locidx_t) tquadrants->elem_count;
1356 // loop over all the quadrant in the tree
1357 for (q = 0; q < Q; ++q, ++k) {
1358 XYZ CurrentCentre;
1359 // Extract an element by index
1360 quad = p4est_quadrant_array_index (tquadrants, q);
1361 // Get the numbers of the corners nodes
1362 for (i = 0; i < P4EST_CHILDREN; ++i) {
1363 all_lni[i] = lnodes->element_nodes[P4EST_CHILDREN * k + i];
1364 }
1365
1366 // Figure out the hanging corners on this element, if any.
1367 anyhang = lnodes_decode2 (lnodes->face_code[k], hanging_corner);
1368
1369 vector<int> elemNodes;
1370 // Loop through nodes
1371 for(node_i = 0; node_i < P4EST_CHILDREN; node_i++) {
1372 // Extract the coordinates
1373 p4est_quadrant_corner_node(quad, node_i, &node_quadrant);
1374 p4est_qcoord_to_vertex (p4est->connectivity, tt, node_quadrant.x, node_quadrant.y, node_quadrant.z, vxyz);
1375
1376 // The node is not hanging and therefore has correct numbering
1377 if (!anyhang || hanging_corner[node_i] == -1) {
1378 if (node_count - 1 < lnodes->element_nodes[P4EST_CHILDREN * k + node_i]) {
1379 AllNodes.insert(std::make_pair(lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1, XYZ(vxyz[0], vxyz[1], vxyz[2])));
1380 node_count++;
1381
1382 if ( isBoundary(vxyz) ) {
1383 m_boundaryPoints.push_back(Point(lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1, vxyz[0], vxyz[1], vxyz[2]));
1384 }
1385 }
1386
1387 // Keep the information for the element connectivity
1388 node_elements[node_i] = lnodes->element_nodes[P4EST_CHILDREN * k + node_i] + 1;
1389
1390 } else {
1391 // Check if that hanging corner has been already written
1392 used = duplicatedHangingNode(vxyz, hang_coord, hang_nums);
1393 //used = 0;
1394 if ( used > 0 ) {
1395 // The node has already appeared and therefore does not need to be written again, use it to create an element only
1396 node_elements[node_i] = used;
1397 } else {
1398 // The node has not appeared earlier, write it, form an element, store the node for further comparisons
1399 AllNodes.insert(std::make_pair(++hanging_count, XYZ(vxyz[0], vxyz[1], vxyz[2])));
1400 node_elements[node_i] = hanging_count;
1401 hang_coord[7][0] = vxyz[0];
1402 hang_coord[7][1] = vxyz[1];
1403 hang_coord[7][2] = vxyz[2];
1404 hang_nums[7] = hanging_count;
1405
1406 // Write constraints for the hanging node
1407 int mytemp = storeHangingNode(all_lni, hanging_corner, node_i, hanging_count);
1408 if (hanging_count == 9110609 )
1409 {
1410 TGLOG("This is node " << hanging_count << " mytemp = " << mytemp);
1411 }
1412 }
1413 }
1414 CurrentCentre.x += 1.0/8.0 * vxyz[0];
1415 CurrentCentre.y += 1.0/8.0 * vxyz[1];
1416 CurrentCentre.z += 1.0/8.0 * vxyz[2];
1417 cornerPoints.push_back(XYZ(vxyz[0], vxyz[1], vxyz[2]));
1418 }
1419
1420 for(i = 0; i < 8; i++) {
1421 elemNodes.push_back(node_elements[elem_order[i]]);
1422 m_NodesEncounter[node_elements[i]].push_back(ElemCount);
1423 }
1424 ElemCount++;
1425 CentrePoints.push_back(CurrentCentre);
1426 m_AllElements.push_back(elemNodes);
1427
1428 // Create connectivity for the nodes in the element (only if it is the final level of the refinement)
1429 if ( quad->level == max_level ) {
1430 vector<int>::iterator itNodes;
1431 int i = 0;
1432 std::vector<int> temp;
1433 for (itNodes = elemNodes.begin(); itNodes != elemNodes.end(); ++itNodes, i++) {
1434 // No need to iterate through the elements which have this node as the loop will go through
1435 // these elements anyway. Only store the information available for this element - neighbouring nodes etc
1436 int a[3];
1437 switch(i) {
1438 case 0: { a[0] = elemNodes[1]; a[1] = elemNodes[3]; a[2] = elemNodes[4]; break; }
1439 case 1: { a[0] = elemNodes[0]; a[1] = elemNodes[2]; a[2] = elemNodes[5]; break; }
1440 case 2: { a[0] = elemNodes[1]; a[1] = elemNodes[3]; a[2] = elemNodes[6]; break; }
1441 case 3: { a[0] = elemNodes[0]; a[1] = elemNodes[2]; a[2] = elemNodes[7]; break; }
1442 case 4: { a[0] = elemNodes[0]; a[1] = elemNodes[5]; a[2] = elemNodes[7]; break; }
1443 case 5: { a[0] = elemNodes[1]; a[1] = elemNodes[4]; a[2] = elemNodes[6]; break; }
1444 case 6: { a[0] = elemNodes[2]; a[1] = elemNodes[5]; a[2] = elemNodes[7]; break; }
1445 case 7: { a[0] = elemNodes[3]; a[1] = elemNodes[4]; a[2] = elemNodes[6]; break; }
1446 }
1447 m_NeighbourNodes[*itNodes].push_back(a[0]);
1448 m_NeighbourNodes[*itNodes].push_back(a[1]);
1449 m_NeighbourNodes[*itNodes].push_back(a[2]);
1450 }
1451 }
1452
1453 elemNodes.clear();
1454 }
1455 }
1456 p4est_lnodes_destroy (lnodes);
1457 TGLOG("Num of elements: " << m_AllElements.size());
1458}
1459
1460*/
1461
1462
1464{
1465 CTimer timer;
1466 map<int, vector<int>>::iterator itConstraints;
1467 vector<int>::const_iterator itNodes;
1468 vector<int> masterNodes;
1469 vector<int> elementsInvolved;
1470 vector<int>::iterator pos;
1471 int i;
1472 /* This array corresponds to the numbering on nodes on six faces of an element
1473 1st line - x_min face, 2nd - x_max,
1474 3rd - y_min, 4th - y_max
1475 5th - z_min, 6th - z_max
1476 */
1477 int faces_inds[6][4] = {
1478 {0, 1, 2, 3},
1479 {4, 5, 6, 7},
1480 {0, 1, 4, 5},
1481 {2, 3, 6, 7},
1482 {1, 2, 5, 6},
1483 {0, 3, 4, 7}
1484 };
1485
1486 vector<int> local_face;
1487 map<int, map<int, vector<int> >> markedElements;
1488
1489 // itConstraints->first - hanging node
1490 // itConstraints->second[j] - master nodes
1491 TGLOG("There are " << m_NodeConstraints.size() << " constrained nodes");
1492 int mycount = 0;
1493 timer.start("Start constraint processing");
1494 for (itConstraints = m_NodeConstraints.begin(); itConstraints != m_NodeConstraints.end(); itConstraints++) {
1495 //TGLOG("Node: " << itConstraints->first);
1496 // Go through all nodes to which a hanging node is constrained, see what elements they belong too
1497 masterNodes = itConstraints->second;
1498 sort(masterNodes.begin(), masterNodes.end());
1499 int num = masterNodes.size();
1500
1501 elementsInvolved.clear();
1502 for (int j = 0; j < num; ++j) {
1503 int currentNode = itConstraints->second[j] ;
1504 elementsInvolved.insert( elementsInvolved.end(), m_NodesEncounter[currentNode].begin(), m_NodesEncounter[currentNode].end() );
1505 }
1506
1507 // Count how many times each element has been counted
1508 i = 0;
1509 map<int, int> elemCount;
1510 for (auto iter = elementsInvolved.begin(); iter != elementsInvolved.end(); ++iter) {
1511 elemCount[*iter]++;
1512
1513 if ( *iter == 17682 ) {
1514 TGLOG("Elemen 17682 constrained " << elemCount[*iter]);
1515 }
1516 }
1517
1518
1519 for (auto iter = elemCount.begin(); iter != elemCount.end(); ++iter) {
1520 // The master element(s) must have the same count as the number of constraints
1521 if ( iter->second == num ) {
1522 // Not let's find the face to which this node needs to be added
1523 int elemNum = iter->first;
1524 vector<int> nodes = m_AllElements[elemNum-1];
1525
1526 for (int j = 0; j < 6; j++)
1527 {
1528 local_face.clear();
1529 local_face.push_back(nodes[faces_inds[j][0]]);
1530 local_face.push_back(nodes[faces_inds[j][1]]);
1531 local_face.push_back(nodes[faces_inds[j][2]]);
1532 local_face.push_back(nodes[faces_inds[j][3]]);
1533 sort(local_face.begin(), local_face.end());
1534
1535 // We now only look for two nodes (edge)
1536 if (num == 2) {
1537 if ( find(local_face.begin(), local_face.end(), masterNodes[0]) != local_face.end() &&
1538 find(local_face.begin(), local_face.end(), masterNodes[1]) != local_face.end() ) {
1539 markedElements[elemNum][j].push_back(itConstraints->first);
1540
1541 if (elemNum == 17682) {
1542 TGLOG("Element 17682: mark " << j << " with " << itConstraints->first)
1543 }
1544
1545 }
1546 }
1547
1548 // We now check if entire face is what we need
1549 if (num == 4) {
1550 if ( equal(masterNodes.begin(), masterNodes.end(), local_face.begin()) )
1551 {
1552 markedElements[elemNum][j].push_back(itConstraints->first);
1553
1554 if (elemNum == 17682) {
1555 TGLOG("Element 17682: mark " << j << " with " << itConstraints->first)
1556 }
1557
1558 }
1559 }
1560
1561 }
1562 } else {
1563 //TGLOG("Skip this element - it is not a 'master' element");
1564 }
1565 }
1566 }
1567 timer.check("Finished");
1568 timer.stop();
1569
1570
1571 // Everything is marked, let's split every element (marked or not) into tets
1572 int newNodesCount = AllNodes.size() + 1;
1573
1574 // Numbering of nodes to split a hex to 12 tets
1575 vector<int> existingNodes;
1576 int tet_split[12][3] = {
1577 {1, 2, 4},
1578 {2, 3, 4},
1579 {5, 8, 6},
1580 {8, 7, 6},
1581 {1, 6, 2},
1582 {1, 5, 6},
1583 {4, 3, 7},
1584 {4, 7, 8},
1585 {7, 3, 2},
1586 {7, 2, 6},
1587 {1, 4, 8},
1588 {1, 8, 5}
1589 };
1590
1591 // Numbering of nodes to split a large tet (which is based on 9-noded faces) into 8 tets
1592 // 9 is the centre of the face node
1593 int face_tet_split[8][3] = {
1594 {1, 2, 9},
1595 {2, 3, 4},
1596 {4, 5, 9},
1597 {5, 6, 9},
1598 {6, 7, 8},
1599 {8, 1, 9},
1600 {9, 2, 4},
1601 {9, 6, 8}
1602 };
1603
1604 int faceLoops[6][4] = {
1605 {0, 1, 2, 3},
1606 {5, 4, 7, 6},
1607 {0, 4, 5, 1},
1608 {2, 6, 7, 3},
1609 {1, 5, 6, 2},
1610 {4, 0, 3, 7}
1611 };
1612
1613 TGLOG("Start hex splitting");
1614 vector<XYZ> newCentrePoints;
1615 i = 1;
1616 for (auto it = m_AllElements.begin(); it != m_AllElements.end(); ++it, ++i) {
1617 XYZ newNode = CentrePoints[i - 1]; // Create a new node at the center point
1618 int newCentreNode = newNodesCount++;
1619 AllNodes.insert(make_pair(newCentreNode, newNode));
1620 existingNodes = m_AllElements[i - 1];
1621
1622 if ( markedElements.find(i) != markedElements.end() ) {
1623 // This element needs to be split taking the hanging nodes into account
1624
1625 if ( i == 17682 ) {
1626 TGLOG("Let's split 17682");
1627 }
1628
1629 // Loop through all faces - some of them are marked, some are not
1630 for (int faces = 0; faces < 6; faces++) {
1631 // Face is marked
1632 if ( markedElements[i].find(faces) != markedElements[i].end() ) {
1633 vector<int> faceNodes;
1634 XYZ faceCentre = XYZ(0, 0, 0);
1635 int newFaceNode = 0;
1636 int faceInd = faces;
1637
1638 if ( i == 17682 )
1639 {
1640 TGLOG("Face " << faces << " has " << markedElements[i][faces].size() << " nodes");
1641 }
1642
1643 // If there are 5 nodes associated with this face then the central node is already present
1644 if ( markedElements[i][faces].size() == 5 ) {
1645 // Find the central node
1646
1647 if ( i == 17682 ) {
1648 TGLOG("Let's split 17682, face " << faces << ": 5 nodes");
1649 }
1650
1651 for (auto it3 = markedElements[i][faces].begin(); it3 != markedElements[i][faces].end(); ++it3) {
1652 if ( m_NodeConstraints[*it3].size() == 4 ) {
1653 faceCentre = AllNodes[*it3];
1654 newFaceNode = *it3;
1655 }
1656 }
1657
1658 for (int kk = 0; kk < 4; kk++) {
1659 faceNodes.push_back(existingNodes[faceLoops[faceInd][kk]]);
1660 }
1661
1662
1663 } else {
1664 // Create new face node
1665
1666 if ( i == 17682 ) {
1667 TGLOG("Let's split 17682 " << faces << ": create node");
1668 }
1669
1670 newFaceNode = newNodesCount++;
1671 for (int kk = 0; kk < 4; kk++) {
1672 faceNodes.push_back(existingNodes[faceLoops[faceInd][kk]]);
1673 faceCentre += 0.25*AllNodes[faceNodes[kk]];
1674 }
1675 AllNodes.insert(make_pair(newFaceNode, faceCentre));
1676 }
1677
1678 // Add all hanging nodes to the "face node loop"
1679
1680 if ( markedElements[i][faces].size() > 0 && markedElements[i][faces].size() != 4) {
1681 // Add all the hanging nodes to the list of the face nodes
1682 for (auto it3 = markedElements[i][faces].begin(); it3 != markedElements[i][faces].end(); ++it3) {
1683
1684 if ( i == 17682 )
1685 {
1686 TGLOG("Element 17682, it3 = " << *it3 << " its 0 = " << m_NodeConstraints[*it3][0] << " and 1 " << m_NodeConstraints[*it3][1]);
1687 TGLOG("El 17682, it3 = " << *it3 << " num of constr " << m_NodeConstraints[*it3].size());
1688 //for (auto itFa = faceNodes.begin(); itFa != faceNodes.end(); ++itFa) {
1689 // TGLOG("Face node: " << *itFa);
1690 //}
1691 }
1692
1693 auto newFaceNodeIt1 = find(faceNodes.begin(), faceNodes.end(), m_NodeConstraints[*it3][0]);
1694 auto newFaceNodeIt2 = find(faceNodes.begin(), faceNodes.end(), m_NodeConstraints[*it3][1]);
1695 int newPos1 = distance(faceNodes.begin(), newFaceNodeIt1);
1696 int newPos2 = distance(faceNodes.begin(), newFaceNodeIt2);
1697
1698 if ( *it3 == 2003180 ) {
1699 TGLOG("pos 1 = " << newPos1 << " , pos 2 = " << newPos2 << ", length = " << faceNodes.size());
1700 }
1701
1702 if ( newPos1 == newPos2 - 1 ) {
1703 faceNodes.insert(newFaceNodeIt1 + 1, *it3);
1704 }
1705
1706 if ( newPos1 - 1 == newPos2 ) {
1707 faceNodes.insert(newFaceNodeIt2 + 1, *it3);
1708 }
1709
1710 if ( newPos1 == newPos2 - 3 || newPos1 - 3 == newPos2 ) {
1711 faceNodes.push_back(*it3);
1712 }
1713
1714 if ( newPos1 == newPos2 + 1 - faceNodes.size() || newPos1 + 1 - faceNodes.size() == newPos2 ) {
1715 faceNodes.push_back(*it3);
1716 }
1717 }
1718
1719 // Add the first node again to "complete" the node loop
1720 if ( markedElements[i][faces].size() != 5 ) //&& ( faces != 2 || faces != 4))
1721 {
1722
1723 faceNodes.push_back(existingNodes[faceLoops[faceInd][0]]);
1724 }
1725 // Iterate to create elements
1726
1727 if ( i == 17682 )
1728 {
1729 TGLOG("Print all face");
1730 for (auto itFa = faceNodes.begin(); itFa != faceNodes.end(); ++itFa) {
1731 TGLOG("Face node: " << *itFa);
1732 }
1733 TGLOG("newFaceNode " << newFaceNode << " newCentreNode " << newCentreNode);
1734 }
1735
1736 if ( markedElements[i][faces].size() == 5 ) // && (faces == 2 || faces == 4))
1737 {
1738 faceNodes.push_back(newFaceNode);
1739 for (int kk = 0; kk < 8; kk++) {
1740 vector<int> new_tet;
1741 new_tet.push_back(faceNodes[face_tet_split[kk][0] - 1]);
1742 new_tet.push_back(faceNodes[face_tet_split[kk][1] - 1]);
1743 new_tet.push_back(faceNodes[face_tet_split[kk][2] - 1]);
1744 new_tet.push_back(newCentreNode);
1745 // In C++11 it can be made with one line:
1746 // vector<int> new_tet ={existingNodes[tet_split[k][0]], existingNodes[tet_split[k][1]], existingNodes[tet_split[k][2]], newNodesCount};
1747 m_TetElements.push_back(new_tet);
1748 newCentrePoints.push_back(CentrePoints[i - 1]);
1749 }
1750
1751 } else {
1752
1753 for (int kk = 0; kk < faceNodes.size() - 1; kk++) {
1754 vector<int> new_tet;
1755 new_tet.push_back(faceNodes[kk]);
1756 new_tet.push_back(faceNodes[kk + 1]);
1757 new_tet.push_back(newFaceNode);
1758 new_tet.push_back(newCentreNode);
1759 m_TetElements.push_back(new_tet);
1760 newCentrePoints.push_back(CentrePoints[i - 1]);
1761 }
1762 }
1763 }
1764 } else {
1765
1766 for (int k = faces*2; k < (faces + 1) * 2; k++) {
1767 vector<int> new_tet;
1768 new_tet.push_back(existingNodes[tet_split[k][0] - 1]);
1769 new_tet.push_back(existingNodes[tet_split[k][1] - 1]);
1770 new_tet.push_back(existingNodes[tet_split[k][2] - 1]);
1771 new_tet.push_back(newCentreNode);
1772 // In C++11 it can be made with one line:
1773 // vector<int> new_tet ={existingNodes[tet_split[k][0]], existingNodes[tet_split[k][1]], existingNodes[tet_split[k][2]], newNodesCount};
1774 m_TetElements.push_back(new_tet);
1775 newCentrePoints.push_back(CentrePoints[i - 1]);
1776 }
1777 }
1778 }
1779
1780
1781
1782
1783 /*
1784 for (auto it2 = markedElements[i].begin(); it2 != markedElements[i].end(); ++it2) {
1785 vector<int> faceNodes;
1786 XYZ faceCentre = XYZ(0, 0, 0);
1787 int newFaceNode = 0;
1788 int faceInd = it2->first;
1789
1790 // If there are 5 hanging nodes then the face node is already present
1791 if ( it2->second.size() == 5 ) {
1792 // Find the central node
1793 for (auto it3 = it2->second.begin(); it3 != it2->second.end(); ++it3) {
1794 if ( m_NodeConstraints[*it3].size() == 4 ) {
1795 faceCentre = AllNodes[*it3];
1796 newFaceNode = *it3;
1797 }
1798 }
1799 } else {
1800 // Create new face node
1801 newFaceNode = newNodesCount++;
1802 for (int kk = 0; kk < 4; kk++) {
1803 faceNodes.push_back(existingNodes[faceLoops[faceInd][kk]]);
1804 faceCentre += 0.25*AllNodes[faceNodes[kk]];
1805 }
1806 AllNodes.insert(make_pair(newFaceNode, faceCentre));
1807 }
1808
1809 // Add all hanging nodes to the "face node loop"
1810
1811 if ( it2->second.size() > 0 && it2->second.size() != 4) {
1812 // Add all the hanging nodes to the list of the face nodes
1813 for (auto it3 = it2->second.begin(); it3 != it2->second.end(); ++it3) {
1814 auto newFaceNodeIt1 = find(faceNodes.begin(), faceNodes.end(), m_NodeConstraints[*it3][0]);
1815 auto newFaceNodeIt2 = find(faceNodes.begin(), faceNodes.end(), m_NodeConstraints[*it3][1]);
1816
1817 int newPos1 = distance(faceNodes.begin(), newFaceNodeIt1);
1818 int newPos2 = distance(faceNodes.begin(), newFaceNodeIt2);
1819 if ( newPos1 == newPos2 - 1 ) {
1820 faceNodes.insert(newFaceNodeIt1 + 1, *it3);
1821 }
1822
1823 if ( newPos1 - 1 == newPos2 ) {
1824 faceNodes.insert(newFaceNodeIt2 + 1, *it3);
1825 }
1826
1827 if ( newPos1 == newPos2 - 3 || newPos1 - 3 == newPos2 ) {
1828 faceNodes.push_back(*it3);
1829 }
1830 }
1831
1832 // Add the first node again to "complete" the node loop
1833 faceNodes.push_back(existingNodes[faceLoops[faceInd][0]]);
1834
1835 // Iterate to create elements
1836 for (int kk = 0; kk < faceNodes.size() - 1; kk++) {
1837 vector<int> new_tet;
1838 new_tet.push_back(faceNodes[kk]);
1839 new_tet.push_back(faceNodes[kk + 1]);
1840 new_tet.push_back(newFaceNode);
1841 new_tet.push_back(newCentreNode);
1842 m_TetElements.push_back(new_tet);
1843
1844 if ( m_TetElements.size() == 150 ) {
1845 TGLOG("Extra node is " << m_NodeConstraints[2000059][0] << " and " << m_NodeConstraints[2000059][1]);
1846 TGLOG("Preparing element 150. Node loop is: ");
1847 for (auto itt = faceNodes.begin(); itt != faceNodes.end(); ++itt) {
1848 TGLOG("Node N: " << *itt);
1849 }
1850
1851 }
1852 }
1853 }
1854 }
1855*/
1856
1857
1858
1859 } else {
1860 // Simple element - just split it
1861 for (int k = 0; k < 12; k++) {
1862 vector<int> new_tet;
1863 new_tet.push_back(existingNodes[tet_split[k][0] - 1]);
1864 new_tet.push_back(existingNodes[tet_split[k][1] - 1]);
1865 new_tet.push_back(existingNodes[tet_split[k][2] - 1]);
1866 new_tet.push_back(newCentreNode);
1867 // In C++11 it can be made with one line:
1868 // vector<int> new_tet ={existingNodes[tet_split[k][0]], existingNodes[tet_split[k][1]], existingNodes[tet_split[k][2]], newNodesCount};
1869 m_TetElements.push_back(new_tet);
1870 newCentrePoints.push_back(CentrePoints[i - 1]);
1871
1872 }
1873 }
1874
1875 }
1876
1877 CentrePoints.clear();
1878 CentrePoints = newCentrePoints;
1879 TGLOG("Splitting is finished");
1880 TGLOG("Nodes: " << AllNodes.size() << " Tet elements: " << m_TetElements.size());
1881
1882}
1883
1884void COctreeVoxelMesh::OutputNodes(ostream &Output, CTextile &Textile, int Filetype )
1885{
1886 CTimer timer;
1887 //timer.start("Starting octree refinement");
1888 TGLOG("Converting octree to nodes coordinates");
1890 TGLOG("Octree converted");
1891 //timer.stop();
1892 /*
1893 if ( m_bTet )
1894 {
1895 ConvertHexToTets();
1896 }
1897 */
1898
1899 //timer.start("Retrieving info on centre points");
1900 TGLOG("Retrieving info on centre points");
1902 //fillMaterialInfo();
1903 //timer.check("Info retrieved");
1904 TGLOG("Info retrieved");
1905 //timer.stop();
1906
1907 // Now try to eliminate "stray" voxels (those which is surrounded mostly by other material
1908 // Not allow yarn voxels to be between two matrix voxels
1909 vector<XYZ>::iterator itCentres;
1910 vector<XYZ>::iterator itCentres2;
1911 vector<vector<int>>::iterator itElemNodes;
1912 TGLOG("Remove strays");
1913 int i = 0;
1915 if (false)
1916 {
1917
1918 double x0 = g_DomainAABB.first.x;
1919 double y0 = g_DomainAABB.first.y;
1920 double z0 = g_DomainAABB.first.z;
1921 double x_length = g_DomainAABB.second.x - x0;
1922 double y_length = g_DomainAABB.second.y - y0;
1923 double z_length = g_DomainAABB.second.z - z0;
1924
1925 double dx = x_length / pow(2, max_level);
1926 double dy = y_length / pow(2, max_level);
1927 double dz = z_length / pow(2, max_level);
1928 vector <XYZ> checkPoints;
1929
1930
1931 int matNum;
1932 vector<int> toChange;
1933
1934 for (itCentres = CentrePoints.begin(), i = 0; itCentres != CentrePoints.end(); ++itCentres, ++i)
1935 {
1936 vector<int> el1 = m_AllElements[i];
1937 XYZ n1 = AllNodes[el1[0]];
1938 XYZ n2 = AllNodes[el1[1]];
1939 int localMats[7] = { 0, 0, 0, 0, 0, 0, 0};
1940 // Check if it is the maximum refinement level
1941
1942
1943 if ( fabs(fabs(n1.x - n2.x) - dx) < dx/100.0 || fabs(fabs(n1.y - n2.y) - dy) < dy/100.0 || fabs(fabs(n1.z - n2.z) - dz) < dz/100.0 )
1944 {
1945 // .. and that it is a yarn
1946 if ( m_ElementsInfo[i].iYarnIndex > -1) {
1947 int j = 0;
1948 matNum = 0;
1949 int curMat = m_ElementsInfo[i].iYarnIndex;
1950
1951 for ( itCentres2 = CentrePoints.begin(), j = 0; itCentres2 != CentrePoints.end(); ++itCentres2, ++j )
1952 {
1953
1954 if ( fabs(itCentres->x + dx - itCentres2->x) < dx/10 && fabs(itCentres->y - itCentres2->y) < dy/10 && fabs(itCentres->z - itCentres2->z) < dz/10 )
1955 {
1956 localMats[1] = m_ElementsInfo[j].iYarnIndex;
1957 matNum++;
1958 }
1959
1960 //if ( itCentres2->x == itCentres->x - dx && itCentres2->y == itCentres->y && itCentres2->z == itCentres->z )
1961 if ( fabs(itCentres->x - dx - itCentres2->x) < dx/10 && fabs(itCentres->y - itCentres2->y) < dy/10 && fabs(itCentres->z - itCentres2->z) < dz/10 )
1962 {
1963 localMats[2] = m_ElementsInfo[j].iYarnIndex;
1964 matNum++;
1965 }
1966
1967 //if ( itCentres2->x == itCentres->x && itCentres2->y == itCentres->y + dy && itCentres2->z == itCentres->z )
1968 if ( fabs(itCentres->x - itCentres2->x) < dx/10 && fabs(itCentres->y + dy - itCentres2->y) < dy/10 && fabs(itCentres->z - itCentres2->z) < dz/10 )
1969 {
1970 localMats[3] = m_ElementsInfo[j].iYarnIndex;
1971 matNum++;
1972
1973 }
1974
1975 //if ( itCentres2->x == itCentres->x && itCentres2->y == itCentres->y - dy && itCentres2->z == itCentres->z )
1976 if ( fabs(itCentres->x - itCentres2->x) < dx/10 && fabs(itCentres->y - dy - itCentres2->y) < dy/10 && fabs(itCentres->z - itCentres2->z) < dz/10 )
1977 {
1978 localMats[4] = m_ElementsInfo[j].iYarnIndex;
1979 matNum++;
1980
1981 }
1982
1983 //if ( itCentres2->x == itCentres->x && itCentres2->y == itCentres->y && itCentres2->z == itCentres->z + dz )
1984 if ( fabs(itCentres->x - itCentres2->x) < dx/10 && fabs(itCentres->y - itCentres2->y) < dy/10 && fabs(itCentres->z + dz - itCentres2->z) < dz/10 )
1985 {
1986 localMats[5] = m_ElementsInfo[j].iYarnIndex;
1987 matNum++;
1988 }
1989
1990
1991 //if ( itCentres2->x == itCentres->x && itCentres2->y == itCentres->y && fabs( itCentres->z - dz - itCentres2->z) < dz/10 )
1992 if ( fabs(itCentres->x - itCentres2->x) < dx/10 && fabs(itCentres->y - itCentres2->y) < dy/10 && fabs(itCentres->z - dz - itCentres2->z) < dz/10 )
1993 {
1994 localMats[6] = m_ElementsInfo[j].iYarnIndex;
1995 matNum++;
1996 }
1997
1998 /*
1999 if ( localMats[1] == -1 && localMats[2] == -1)
2000 {
2001 //m_ElementsInfo[i].iYarnIndex = -1;
2002 toChange.push_back(i);
2003 break;
2004 }
2005
2006 if ( localMats[3] == -1 && localMats[4] == -1)
2007 {
2008 //m_ElementsInfo[i].iYarnIndex = -1;
2009 toChange.push_back(i);
2010 break;
2011 }*/
2012
2013 if ( localMats[5] == -1 && localMats[6] == -1)
2014 {
2015 //m_ElementsInfo[i].iYarnIndex = -1;
2016 toChange.push_back(i);
2017 break;
2018 }
2019
2020 if ( matNum == 6 )
2021 {
2022 break;
2023 }
2024 }
2025 }
2026 }
2027
2028
2029 }
2030 TGLOG("Total elements: " << i);
2031 vector<int>::iterator myIt;
2032 for (myIt = toChange.begin(); myIt != toChange.end(); ++myIt)
2033 {
2034 m_ElementsInfo[*myIt].iYarnIndex = -1;
2035 }
2036
2037 }
2039
2040 TGLOG("Stray voxels removed");
2041
2042
2043 if (m_bSmooth || m_bSurface) {
2044 map<int, vector<int>> NodeSurf;
2045 vector<int> AllSurf;
2046 extractSurfaceNodeSets(NodeSurf, AllSurf);
2047
2048 if (m_bSmooth) {
2049 //timer.start("Smoothing starts");
2050 TGLOG("Smoothing starts");
2051 smoothing(NodeSurf, AllSurf);
2052 //timer.check("Smoothing finished");
2053 TGLOG("Smoothing finished");
2054 //timer.stop();
2055 }
2056
2057 if (m_bSurface) {
2058 //timer.start("Preparing interface definitions");
2059 TGLOG("Preparing interface definitions");
2060 OutputSurfaces(NodeSurf, AllSurf);
2061 //timer.check("Interfaces defined");
2062 TGLOG("Interfaces defined");
2063 //timer.stop();
2064 }
2065 }
2066
2067
2068
2069
2070 //timer.start("Write the nodes");
2071 TGLOG("Write the nodes");
2072 map<int,XYZ>::iterator itNodes, itNodes2;
2073
2074 for (itNodes = AllNodes.begin(); itNodes != AllNodes.end(); ++itNodes) {
2075 Output << setprecision(12) << itNodes->first << ", " << itNodes->second.x << ", " << itNodes->second.y << ", " << itNodes->second.z << "\n";
2076 }
2077 //timer.check("Nodes written");
2078 TGLOG("Nodes written");
2079 //timer.check("Octree refinement finished");
2080 //timer.stop();
2081}
2082
2083int COctreeVoxelMesh::checkIndex(int currentElement, vector<int> nodes)
2084{
2085 vector<int> elems;
2086
2087 vector<int>::const_iterator itNodes;
2088 for(itNodes = nodes.begin(); itNodes != nodes.end(); ++itNodes) {
2089 vector<int>::iterator itEnc;
2090 for (itEnc = m_NodesEncounter[*itNodes].begin(); itEnc != m_NodesEncounter[*itNodes].end(); ++itEnc)
2091 elems.push_back(*itEnc);
2092 //elems.insert(elems.end(), NodesEncounter[*itNodes].begin(), NodesEncounter[*itNodes].end());
2093 }
2094
2095
2096 elems.erase(remove(elems.begin(), elems.end(), currentElement), elems.end());
2097 pair<int, int> p = most_common(elems);
2098 if (p.second == 4) {
2099 if ( m_ElementsInfo[currentElement - 1].iYarnIndex == m_ElementsInfo[p.first - 1].iYarnIndex )
2100 return -1;
2101 }
2102
2103 return 0;
2104}
2105
2106pair<int, vector<int> > COctreeVoxelMesh::GetFaceIndices2(CMesh::ELEMENT_TYPE ElemType, const set<int> &NodeIndices, int currentElement)
2107{
2108 //TGLOG("Checking element " << currentElement);
2109 vector<int> facesInd;
2110 int numFaces = 0;
2111 if (NodeIndices.size() == 5 || NodeIndices.size() == 4)
2112 numFaces = 1;
2113 if (NodeIndices.size() == 6)
2114 numFaces = 2;
2115 if (NodeIndices.size() == 7)
2116 numFaces = 6;
2117 if (NodeIndices.size() == 8)
2118 numFaces = 6;
2119
2120 int i = 0, k = 0;
2121 while (i < numFaces) {
2122 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(3)) {
2123 vector<int> n;
2124 n.push_back(m_AllElements[currentElement-1][0]);
2125 n.push_back(m_AllElements[currentElement-1][1]);
2126 n.push_back(m_AllElements[currentElement-1][2]);
2127 n.push_back(m_AllElements[currentElement-1][3]);
2128
2129 int check = checkIndex(currentElement, n);
2130 if ( check != -1 )
2131 facesInd.push_back(0), i++;
2132 }
2133
2134 if (NodeIndices.count(4) && NodeIndices.count(5) && NodeIndices.count(6) && NodeIndices.count(7)) {
2135 vector<int> n;
2136 n.push_back(m_AllElements[currentElement-1][4]);
2137 n.push_back(m_AllElements[currentElement-1][5]);
2138 n.push_back(m_AllElements[currentElement-1][6]);
2139 n.push_back(m_AllElements[currentElement-1][7]);
2140
2141 int check = checkIndex(currentElement, n);
2142 if ( check != -1 )
2143 facesInd.push_back(1), i++;
2144 }
2145
2146 if (NodeIndices.count(0) && NodeIndices.count(1) && NodeIndices.count(4) && NodeIndices.count(5)) {
2147 vector<int> n;
2148 n.push_back(m_AllElements[currentElement-1][0]);
2149 n.push_back(m_AllElements[currentElement-1][1]);
2150 n.push_back(m_AllElements[currentElement-1][4]);
2151 n.push_back(m_AllElements[currentElement-1][5]);
2152
2153 int check = checkIndex(currentElement, n);
2154 if ( check != -1 )
2155 facesInd.push_back(2), i++;
2156 }
2157
2158 if (NodeIndices.count(1) && NodeIndices.count(2) && NodeIndices.count(5) && NodeIndices.count(6)) {
2159 vector<int> n;
2160 n.push_back(m_AllElements[currentElement-1][1]);
2161 n.push_back(m_AllElements[currentElement-1][2]);
2162 n.push_back(m_AllElements[currentElement-1][5]);
2163 n.push_back(m_AllElements[currentElement-1][6]);
2164
2165 int check = checkIndex(currentElement, n);
2166 if ( check != -1 )
2167 facesInd.push_back(3), i++;
2168 }
2169
2170 if (NodeIndices.count(2) && NodeIndices.count(3) && NodeIndices.count(6) && NodeIndices.count(7)) {
2171 vector<int> n;
2172 n.push_back(m_AllElements[currentElement-1][2]);
2173 n.push_back(m_AllElements[currentElement-1][3]);
2174 n.push_back(m_AllElements[currentElement-1][6]);
2175 n.push_back(m_AllElements[currentElement-1][7]);
2176
2177 int check = checkIndex(currentElement, n);
2178 if ( check != -1 )
2179 facesInd.push_back(4), i++;
2180 }
2181
2182 if (NodeIndices.count(3) && NodeIndices.count(0) && NodeIndices.count(7) && NodeIndices.count(4)) {
2183 vector<int> n;
2184 n.push_back(m_AllElements[currentElement-1][3]);
2185 n.push_back(m_AllElements[currentElement-1][0]);
2186 n.push_back(m_AllElements[currentElement-1][7]);
2187 n.push_back(m_AllElements[currentElement-1][4]);
2188
2189 int check = checkIndex(currentElement, n);
2190 if ( check != -1 )
2191 facesInd.push_back(5), i++;
2192 }
2193
2194 if (k++ > numFaces) {
2195 // No faces found
2196 return make_pair(i,facesInd);
2197 }
2198 }
2199
2200 return make_pair(numFaces, facesInd);
2201}
2202
2203// Populate sets of nodes which are at an interface and elements which have at least one onde at an interface
2204void COctreeVoxelMesh::extractSurfaceNodeSets(map<int, vector<int>> &NodeSurf, vector<int> &AllSurf) {
2205 int i;
2206 map<int, vector<int>> NodeSets;
2207 vector<POINT_INFO>::iterator itData;
2208 vector<int>::iterator itNodes;
2209 map<int, vector<int>>::iterator itNodeSurf, itNodeSets;
2210
2211 NodeSurf.clear();
2212 AllSurf.clear();
2213
2214 // Create element and node sets for each material
2215 for (itData = m_ElementsInfo.begin(), i = 0; itData != m_ElementsInfo.end(); ++itData, i++) {
2216 NodeSets[itData->iYarnIndex].insert(NodeSets[itData->iYarnIndex].end(), m_AllElements[i].begin(), m_AllElements[i].end());
2217 }
2218
2219
2220 // Remove non-unique entries
2221 for (itNodeSets = NodeSets.begin(); itNodeSets != NodeSets.end(); ++itNodeSets) {
2222 vector<int> mat = itNodeSets->second;
2223 sort(mat.begin(), mat.end());
2224 mat.erase( unique(mat.begin(), mat.end()), mat.end() );
2225 itNodeSets->second = mat;
2226 }
2227
2228 // Create sets of surface nodes for each material (find nodes which fall into both material sets)
2229 for (itNodeSets = NodeSets.begin(); itNodeSets != NodeSets.end(); ++itNodeSets) {
2230 map<int,vector<int>>::iterator itTempNodeSet;
2231 vector<int> currentSet;
2232 for (itTempNodeSet = NodeSets.begin(); itTempNodeSet != NodeSets.end(); ++itTempNodeSet) {
2233 if (itNodeSets->first != itTempNodeSet->first) {
2234 vector<int> v1 = itNodeSets->second;
2235 vector<int> v2 = itTempNodeSet->second;
2236 sort(v1.begin(), v1.end());
2237 sort(v2.begin(), v2.end());
2238
2239 vector<int> v_intersection;
2240 set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(v_intersection));
2241 currentSet.insert(currentSet.end(), v_intersection.begin(), v_intersection.end());
2242 }
2243 }
2244 sort(currentSet.begin(), currentSet.end());
2245 currentSet.erase( unique(currentSet.begin(), currentSet.end()), currentSet.end());
2246 NodeSurf[itNodeSets->first] = currentSet;
2247 }
2248
2249 // Store all surface nodes in one place
2250 for (itNodeSurf = NodeSurf.begin(); itNodeSurf != NodeSurf.end(); ++itNodeSurf) {
2251 for (itNodes = itNodeSurf->second.begin(); itNodes != itNodeSurf->second.end(); ++itNodes) {
2252 // Instead of this if-condition sort/unique/erase sequence can be used
2253 if ( find(AllSurf.begin(), AllSurf.end(), *itNodes) == AllSurf.end() )
2254 AllSurf.push_back(*itNodes);
2255 }
2256 }
2257}
2258
2259void COctreeVoxelMesh::smoothing(const map<int, vector<int>> &NodeSurf, const vector<int> &AllSurf)
2260{
2261 vector<POINT_INFO>::iterator itData;
2262 map<int, vector<int>>::const_iterator itNodeSurf;
2263
2264 double coef = 0.63;
2265 map<int,XYZ> AllLapl;
2266 map<int,XYZ> PrevNodes;
2267 map<int,XYZ> OldNodes = AllNodes;
2268
2269 vector<int> v = AllSurf;
2270 sort(v.begin(),v.end());
2271
2272 // Prepare the neighbour connections (leave only nodes which are on an interface)
2273 map<int, vector<int>>::iterator itNeighbourNodes;
2274
2275 for (itNeighbourNodes = m_NeighbourNodes.begin(); itNeighbourNodes != m_NeighbourNodes.end(); ++itNeighbourNodes) {
2276 vector<int> temp;
2277 vector<int> v_intersection;
2278
2279 temp = itNeighbourNodes->second;
2280 sort(temp.begin(), temp.end());
2281 temp.erase( unique(temp.begin(), temp.end()), temp.end());
2282 set_intersection(v.begin(), v.end(), temp.begin(), temp.end(), back_inserter(v_intersection));
2283 itNeighbourNodes->second = v_intersection;
2284 }
2285
2286 for (int iter_i = 0; iter_i < m_smoothIter; iter_i++) {
2287 if ( m_smoothCoef2 > 0 || iter_i%2 == 0) {
2288 PrevNodes = AllNodes;
2289 }
2290
2291 coef = (iter_i%2 == 0) ? m_smoothCoef1 : m_smoothCoef2;
2292
2293 double max_dx = 0.5*(m_DomainAABB.second.x - m_DomainAABB.first.x) / pow(2,max_level);
2294 double max_dy = 0.5*(m_DomainAABB.second.y - m_DomainAABB.first.y) / pow(2,max_level);
2295 double max_dz = 0.5*(m_DomainAABB.second.z - m_DomainAABB.first.z) / pow(2,max_level);
2296 double diag = sqrt( 4*max_dx * max_dx + 4*max_dy * max_dy + 4*max_dz * max_dz );
2297
2298 for (itNodeSurf = NodeSurf.begin(); itNodeSurf != NodeSurf.end(); ++itNodeSurf) {
2299 vector<int>::const_iterator itNodes;
2300 for (itNodes = itNodeSurf->second.begin(); itNodes != itNodeSurf->second.end(); ++itNodes) {
2301 vector<int>::iterator itNeighbour;
2302 XYZ laplacian(0.0, 0.0, 0.0);
2303
2304 int num = m_NeighbourNodes[*itNodes].size();
2305 //XYZ orig = OldNodes[*itNodes];
2306 XYZ orig = PrevNodes[*itNodes];
2307
2308 for (itNeighbour = m_NeighbourNodes[*itNodes].begin(); itNeighbour != m_NeighbourNodes[*itNodes].end(); ++itNeighbour) {
2309 laplacian -= coef/num*(orig - AllNodes[*itNeighbour]);
2310
2311 // If a point is on a boundary, it should stay there
2312 if ( my_comparison(orig.x , m_DomainAABB.first.x) || my_comparison(orig.x , m_DomainAABB.second.x) )
2313 laplacian.x = 0;
2314
2315 if ( my_comparison(orig.y , m_DomainAABB.first.y) || my_comparison(orig.y , m_DomainAABB.second.y) )
2316 laplacian.y = 0;
2317
2318 if ( my_comparison(orig.z , m_DomainAABB.first.z) || my_comparison(orig.z , m_DomainAABB.second.z) )
2319 laplacian.z = 0;
2320 }
2321
2322 if ( AllLapl.find(*itNodes) == AllLapl.end() ) {
2323 AllLapl.insert(make_pair(*itNodes,laplacian));
2324 }
2325 }
2326 }
2327
2328 map<int, XYZ>::iterator itNodes;
2329 for (itNodes = AllNodes.begin(); itNodes != AllNodes.end(); ++itNodes) {
2330 if ( AllLapl.find(itNodes->first) != AllLapl.end() ) {
2331 AllNodes[itNodes->first] += AllLapl[itNodes->first];
2332 XYZ node_move = AllNodes[itNodes->first] - OldNodes[itNodes->first];
2333 // Now let's do the quality check:
2334 // We do not want to have a node move more than 0.5 of a side length or of element diagonal
2335 if ( fabs(node_move.x) > max_dx || fabs(node_move.y) > 0.5 * max_dy || fabs(node_move.z) > max_dz ||
2336 sqrt( node_move.x * node_move.x + node_move.y * node_move.y + node_move.z * node_move.z) > diag)
2337 AllNodes[itNodes->first] -= AllLapl[itNodes->first];
2338
2339 }
2340 }
2341 AllLapl.clear();
2342 }
2343}
2344
2345
2346// Create a surface between the materials
2347// Iterate through surface nodes
2348// * For every node retrieve all elements containing this node
2349// * Check to how many materials these elements belong to
2350// * * For elements belonging to element with minimal material number - leave the original node
2351// * * For elements belonging to other materials - duplicate the node (for every material - one copy)
2352// * * Replace original node's entries in elements with newly create elements
2353// * Store original node and newly created in sets for surface definitions
2354void COctreeVoxelMesh::OutputSurfaces(const map<int, vector<int> > &NodeSurf, const vector<int> &AllSurf) {
2355 vector<int> AllSurfElems;
2356 vector<POINT_INFO>::iterator itData;
2357 vector<int>::const_iterator itNodes;
2358 map<int, vector<int>>::iterator itNodeSurf, itElemSurf, itYarnElems;
2359 map<int, vector<int>> MyNodeSurf, MyElemSurf, InteriorElems;
2360 vector<POINT_INFO>::iterator itInfo;
2361
2362 int extraNodeCount = 3000000;
2363
2364 // Iterating through surface nodes
2365 for (itNodes = AllSurf.begin(); itNodes != AllSurf.end(); ++itNodes) {
2366 // Looking though elements containing this node and finding what material has the minimum index
2367 // The elements with minimum index are not changed. Others are "disconnected" by copying a node
2368 vector<int>::iterator itEncounter;
2369 //int minMaterial = NodeSurf.size() + 1;
2370
2371 vector<int> temp;
2372 for (itEncounter = m_NodesEncounter[*itNodes].begin(); itEncounter != m_NodesEncounter[*itNodes].end(); ++itEncounter) {
2373 temp.push_back(m_ElementsInfo[*itEncounter - 1].iYarnIndex);
2374 //if (m_ElementsInfo[*itEncounter - 1].iYarnIndex < minMaterial) {
2375 // minMaterial = m_ElementsInfo[*itEncounter - 1].iYarnIndex;
2376 //}
2377 }
2378 int minMaterial = *min_element(temp.begin(), temp.end());
2379
2380 vector<int> usedMaterial;
2381 vector<int> usedNodes;
2382
2383 // Iterating through elements which include this surface node
2384 // The elements with the minimal material number (usually matrix) are left intact
2385 // The elements with other material number are amended as follows:
2386 // * if this is the first appearance of this material number
2387 // * * copy the node, reassign the original node with copied node to the element definition
2388 // * if this is not the first appearance of this material number
2389 // * * find number of the copied node and reassign the original node with the copied node to the element definition
2390 for (itEncounter = m_NodesEncounter[*itNodes].begin(); itEncounter != m_NodesEncounter[*itNodes].end(); ++itEncounter) {
2391
2392 MyElemSurf[m_ElementsInfo[*itEncounter-1].iYarnIndex].push_back(*itEncounter);
2393 MyNodeSurf[m_ElementsInfo[*itEncounter-1].iYarnIndex].push_back(*itNodes);
2394 }
2395 }
2396
2397
2398 for (itNodeSurf = MyNodeSurf.begin(); itNodeSurf != MyNodeSurf.end(); ++itNodeSurf)
2399 {
2400 sort( itNodeSurf->second.begin(), itNodeSurf->second.end());
2401 itNodeSurf->second.erase( unique(itNodeSurf->second.begin(), itNodeSurf->second.end()) , itNodeSurf->second.end() );
2402 }
2403
2404 m_SurfaceNodes = MyNodeSurf;
2405
2406 for (itElemSurf = MyElemSurf.begin(); itElemSurf != MyElemSurf.end(); ++itElemSurf)
2407 {
2408 sort( itElemSurf->second.begin(), itElemSurf->second.end());
2409 itElemSurf->second.erase( unique(itElemSurf->second.begin(), itElemSurf->second.end()) , itElemSurf->second.end() );
2410 }
2411
2412 for (itElemSurf = MyElemSurf.begin(); itElemSurf != MyElemSurf.end(); ++itElemSurf) {
2413 vector<int>::iterator itElems;
2414 for (itElems = itElemSurf->second.begin(); itElems != itElemSurf->second.end(); ++itElems) {
2415 set<int> CommonIndices = GetCommonIndices(MyNodeSurf[itElemSurf->first], m_AllElements[*itElems-1]);
2416
2417 pair<int,vector<int>> checkFaces = GetFaceIndices2(CMesh::HEX, CommonIndices, *itElems);
2418 if ( checkFaces.first != -1 ) {
2419 vector<int>::iterator itFace;
2420 for (itFace = checkFaces.second.begin(); itFace != checkFaces.second.end(); ++itFace) {
2421 m_SurfaceElementFaces[itElemSurf->first].push_back(make_pair(*itElems, *itFace + 1));
2422 }
2423 }
2424 }
2425 }
2426
2427 MyNodeSurf.clear();
2428 MyElemSurf.clear();
2429 for (itNodes = AllSurf.begin(); itNodes != AllSurf.end(); ++itNodes) {
2430 // Looking though elements containing this node and finding what material has the minimum index
2431 // The elements with minimum index are not changed. Others are "disconnected" by copying a node
2432 vector<int>::iterator itEncounter;
2433 //int minMaterial = NodeSurf.size() + 1;
2434
2435 vector<int> temp;
2436 for (itEncounter = m_NodesEncounter[*itNodes].begin(); itEncounter != m_NodesEncounter[*itNodes].end(); ++itEncounter) {
2437 temp.push_back(m_ElementsInfo[*itEncounter - 1].iYarnIndex);
2438 //if (m_ElementsInfo[*itEncounter - 1].iYarnIndex < minMaterial) {
2439 // minMaterial = m_ElementsInfo[*itEncounter - 1].iYarnIndex;
2440 //}
2441 }
2442 int minMaterial = *min_element(temp.begin(), temp.end());
2443
2444 vector<int> usedMaterial;
2445 vector<int> usedNodes;
2446
2447 // Iterating through elements which include this surface node
2448 // The elements with the minimal material number (usually matrix) are left intact
2449 // The elements with other material number are amended as follows:
2450 // * if this is the first appearance of this material number
2451 // * * copy the node, reassign the original node with copied node to the element definition
2452 // * if this is not the first appearance of this material number
2453 // * * find number of the copied node and reassign the original node with the copied node to the element definition
2454 for (itEncounter = m_NodesEncounter[*itNodes].begin(); itEncounter != m_NodesEncounter[*itNodes].end(); ++itEncounter) {
2455
2456 MyElemSurf[m_ElementsInfo[*itEncounter-1].iYarnIndex].push_back(*itEncounter);
2457
2458 if (m_ElementsInfo[*itEncounter-1].iYarnIndex == minMaterial) {
2459 MyNodeSurf[m_ElementsInfo[*itEncounter-1].iYarnIndex].push_back(*itNodes);
2460 } else {
2461 vector<int>::iterator it = find(usedMaterial.begin(), usedMaterial.end(), m_ElementsInfo[*itEncounter-1].iYarnIndex);
2462 if ( usedMaterial.size() > 0 && it != usedMaterial.end() ) {
2463 // The node has already been copied, replace corresponding nodes in the element
2464 replace(m_AllElements[*itEncounter-1].begin(), m_AllElements[*itEncounter-1].end(), *itNodes, usedNodes[it - usedMaterial.begin()]);
2465 } else {
2466 // Copy the existing node and replace it in the element
2467 AllNodes.insert(make_pair(extraNodeCount, AllNodes[*itNodes]));
2468 MyNodeSurf[m_ElementsInfo[*itEncounter-1].iYarnIndex].push_back(extraNodeCount);
2469 replace(m_AllElements[*itEncounter-1].begin(), m_AllElements[*itEncounter-1].end(), *itNodes, extraNodeCount);
2470
2471 // Save info about the copied node
2472 usedMaterial.push_back(m_ElementsInfo[*itEncounter - 1].iYarnIndex);
2473 usedNodes.push_back(extraNodeCount);
2474 extraNodeCount++;
2475 }
2476 }
2477 }
2478 }
2479
2480 for (itNodeSurf = MyNodeSurf.begin(); itNodeSurf != MyNodeSurf.end(); ++itNodeSurf)
2481 {
2482 sort( itNodeSurf->second.begin(), itNodeSurf->second.end());
2483 itNodeSurf->second.erase( unique(itNodeSurf->second.begin(), itNodeSurf->second.end()) , itNodeSurf->second.end() );
2484 }
2485
2486 m_SurfaceNodes = MyNodeSurf;
2487
2488}
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define TGLOG(MESSAGE)
Definition: Logger.h:36
const int p8est_face_corners[6][4]
int GetFaceIndex(CMesh::ELEMENT_TYPE ElemType, const set< int > &NodeIndices)
int g_YVoxels
int g_ZVoxels
const int p8est_edge_corners[12][2]
pair< int, int > most_common(vector< int > v)
static const int zero
static int lnodes_decode2(p4est_lnodes_code_t face_code, int hanging_corner[P4EST_CHILDREN])
int my_comparison(double x, double y)
vector< int > GetFaceIndices(CMesh::ELEMENT_TYPE ElemType, const set< int > &NodeIndices)
set< int > GetCommonIndices(const vector< int > &SurfIndices, const vector< int > &VolIndices)
static const int corner_num_hanging[P4EST_CHILDREN]
static const int * corner_to_hanging[P4EST_CHILDREN]
int g_XVoxels
int duplicatedHangingNode(double vxyz[3], double hang_coord[8][3], int hang_nums[8])
static const int ones
#define NULL
Definition: ShinyConfig.h:50
const CMesh & GetMesh() const
Get the mesh representing the domain as a surface mesh.
Definition: Domain.h:73
ELEMENT_TYPE
Each element type is represented by a unique integer value.
Definition: Mesh.h:66
pair< XYZ, XYZ > GetAABB(double dGrowDistance=0) const
Get an axis aligned bounding box for the mesh.
Definition: Mesh.cpp:340
void OutputSurfaces(const std::map< int, vector< int > > &NodeSurf, const std::vector< int > &AllSurf)
vector< std::vector< int > > m_AllElements
void OutputPeriodicBoundaries(ostream &Output, CTextile &Textile, int iBoundaryConditions, bool bMatrixOnly)
Store info (nodes at boundaries) for periodic BCs.
static vector< vector< int > > FaceZ_max
static vector< vector< int > > FaceX_max
map< int, vector< int > > m_NeighbourNodes
vector< vector< int > > m_TetElements
int CreateP4ESTRefinement(int min_level, int refine_level)
Performs octree refinement using external P4EST library.
static vector< XYZ > cornerPoints
void SaveVoxelMesh(CTextile &Textile, string OutputFilename, int XVoxNum, int YVoxNum, int ZVoxNum, int min_level, int refine_level, bool smoothing, int smoothIter, double smooth1, double smooth2, bool surfaceOuput)
static int getPointsInfo(vector< XYZ > myPoints, int refineLevel)
static vector< char > materialInfo
static vector< vector< int > > FaceX_min
void extractSurfaceNodeSets(std::map< int, vector< int > > &NodeSurf, std::vector< int > &AllSurf)
int storeHangingNode(int *all_lni, int *hanging_corner, int node_i, int hanging_count, double v[3])
Storing hanging nodes from octree-mesh to a vector for writing the constraints.
map< int, vector< pair< int, int > > > m_SurfaceElementFaces
static vector< XYZ > CentrePoints
vector< Point > m_boundaryPoints
static int refine_fn_post(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
COctreeVoxelMesh(string Type="CPeriodicBoundaries")
static vector< vector< int > > FaceY_min
bool CalculateVoxelSizes(CTextile &Textile)
Calculate voxel size based on number of voxels on each axis and domain size.
static int refine_fn_uni(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
map< int, vector< int > > m_SurfaceNodes
static int refine_fn(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
static void FindLocMinMax(int &XMin, int &XMax, int &YMin, int &YMax, XYZ &Min, XYZ &Max)
int checkIndex(int currentElement, vector< int > nodes)
map< int, vector< int > > m_NodeConstraints
pair< int, vector< int > > GetFaceIndices2(CMesh::ELEMENT_TYPE ElemType, const set< int > &NodeIndices, int currentElement)
int OutputHexElements(ostream &Output, bool bOutputMatrix, bool bOutputYarn, int Filetype=INP_EXPORT)
Output elements to .inp file.
static pair< XYZ, XYZ > g_DomainAABB
static CTextile gTextile
map< int, vector< int > > m_NodesEncounter
static vector< vector< int > > FaceY_max
void OutputNodes(ostream &Output, CTextile &Textile, int Filetype=INP_EXPORT)
Outputs nodes to .inp file and gets element information.
map< string, int > m_NodeConstraintsReverse
void storePointInfo(int refineLevel)
int writeTempFile(string filename, pair< XYZ, XYZ > myDomain)
static int refine_fn_periodic(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
p4est_connectivity_t * conn
void smoothing(const std::map< int, vector< int > > &NodeSurf, const vector< int > &AllSurf)
Smoothing.
static vector< vector< int > > FaceZ_min
void ConvertOctreeToNodes()
Decode the P4EST mesh structure and store nodes/elements.
void SetFaceB(vector< int > &B1, vector< int > &B2)
void CreatePeriodicBoundaries(ostream &Output, int iDummyNodeNum, CTextile &Textile, int iBoundarConditions, bool bMatrixOnly)
void SetEdges(vector< int > &Edge)
virtual void SetDomainSize(const CMesh &Mesh)
void SetFaceA(vector< int > &A1, vector< int > &A2)
void SetFaceC(vector< int > &C1, vector< int > &C2)
Represents a textile cell containing yarns.
Definition: Textile.h:39
const CDomain * GetDomain() const
Definition: Textile.h:287
void GetPointInformation(const vector< XYZ > &Points, vector< POINT_INFO > &PointsInfo, double dTolerance=1e-9)
Get useful information of a list of points.
Definition: Textile.cpp:410
Class used to meaure the amount of time it takes to perform a certain task.
Definition: Timer.h:12
void stop(const char *msg=0)
Stop the timer and print an optional message.
Definition: Timer.h:86
void check(const char *msg=0)
Definition: Timer.h:96
void start(const char *msg=0)
Definition: Timer.h:57
Class used to generate voxel mesh for output to ABAQUS.
Definition: VoxelMesh.h:35
pair< XYZ, XYZ > m_DomainAABB
Domain limits.
Definition: VoxelMesh.h:121
int m_XVoxels
Number of voxels along x,y and z axes.
Definition: VoxelMesh.h:115
CPeriodicBoundaries * m_PeriodicBoundaries
Definition: VoxelMesh.h:126
vector< POINT_INFO > m_ElementsInfo
Element information as calculated by GetPointInformation.
Definition: VoxelMesh.h:123
virtual void SaveVoxelMesh(CTextile &Textile, string OutputFilename, int XVoxNum, int YVoxNum, int ZVoxNum, bool bOutputMatrix, bool bOutputYarns, int iBoundaryConditions, int iElementType=0, int FileType=INP_EXPORT)
Definition: VoxelMesh.cpp:51
Namespace containing a series of customised math operations not found in the standard c++ library.
void WriteValues(std::ostream &Output, T &Values, int iMaxPerLine)
Definition: Misc.h:274
double Max(XYZ &Vector)
Get maximum element of vector and return it.
Definition: mymath.h:642
XYZ Min(const XYZ &P1, const XYZ &P2)
Given two points, return a new point who's coordinates are the smaller of the two.
Definition: mymath.h:1142
@ SINGLE_LAYER_RVE
Definition: Misc.h:265
Structure used to retreive information about a particular point in space.
Definition: Misc.h:217
Struct for representing points in 3D space.
Definition: mymath.h:56
double z
Definition: mymath.h:57
double x
Definition: mymath.h:57
double y
Definition: mymath.h:57