NeoPZ
pzdohrstructmatrix.cpp
Go to the documentation of this file.
1 
6 #include "pzdohrstructmatrix.h"
7 #include "tpzdohrmatrix.h"
9 #include "tpzdohrprecond.h"
10 #include "tpznodesetcompute.h"
11 #include "TPZRenumbering.h"
12 #include "pzmetis.h"
13 
14 #include "pzskylstrmatrix.h"
15 #include "pzmatred.h"
16 #include "tpzmatredstructmatrix.h"
17 #include "tpzpairstructmatrix.h"
18 #include "pzfstrmatrix.h"
19 
20 #include "pzsubcmesh.h"
21 #include "pzintel.h"
22 
23 #include "TPZBoostGraph.h"
24 #include "pzsloan.h"
25 #include "pzvisualmatrix.h"
26 #include "TPZRefPatternTools.h"
27 #include "tpzverysparsematrix.h"
28 
29 #include <sstream>
30 #include <map>
31 #include "pzlog.h"
32 
33 #include "TPZfTime.h"
34 #include "TPZTimeTemp.h"
35 #include "TPZVTKGeoMesh.h"
36 #include <stdlib.h>
37 
38 #ifdef LOG4CXX
39 static LoggerPtr logger(Logger::getLogger("structmatrix.dohrstructmatrix"));
40 static LoggerPtr loggerasm(Logger::getLogger("structmatrix.dohrstructmatrix.asm"));
41 #endif
42 
43 #include "pz_pthread.h"
44 #include "clock_timer.h"
45 #include "timing_analysis.h"
46 #include "arglib.h"
47 #include "run_stats_table.h"
48 
49 #ifdef USING_TBB
50 #include <tbb/parallel_for.h>
51 #include <tbb/blocked_range.h>
52 using namespace tbb;
53 #endif
54 
55 #include <rcm.h>
56 
57 #ifdef USING_PAPI
58 #include <papi.h>
59 
60 static float stiff_sum = 0;
61 #endif
62 
64 static int64_t NSubMesh(TPZAutoPointer<TPZCompMesh> compmesh);
65 
67 static TPZSubCompMesh *SubMesh(TPZAutoPointer<TPZCompMesh> compmesh, int isub);
68 
70  pthread_mutex_t* TestThread);
71 
72 static void DecomposeBig(TPZAutoPointer<TPZDohrSubstructCondense<STATE> > substruct, int numa_node);
73 static void DecomposeInternal(TPZAutoPointer<TPZDohrSubstructCondense<STATE> > substruct, int numa_node);
74 
76 TPZStructMatrix(), fDohrAssembly(0), fDohrPrecond(0)
77 {
78  PZ_PTHREAD_MUTEX_INIT(&fAccessElement, 0, "TPZDohrStructMatrix::TPZDohrStructMatrix()");
79 }
80 
83 fDohrPrecond(0)
84 {
85  PZ_PTHREAD_MUTEX_INIT(&fAccessElement, 0, "TPZDohrStructMatrix::TPZDohrStructMatrix()");
86 }
87 
90 {
91  PZ_PTHREAD_MUTEX_INIT(&fAccessElement, 0, "TPZDohrStructMatrix::TPZDohrStructMatrix(copy)");
92 }
93 
95 {
96  PZ_PTHREAD_MUTEX_DESTROY(&fAccessElement, "TPZDohrStructMatrix::~TPZDohrStructMatrix()");
97 }
98 
99 
100 // this will create a DohrMatrix
102 {
103 
104  TPZfTime timeforcopute; // init of timer for compute
107  fDohrAssembly = assembly;
108 
110  {
111  TPZVec<int64_t> perm,iperm;
112  TPZStack<int64_t> elgraph,elgraphindex;
113 
114 
115  int nindep = fMesh->NIndependentConnects();
116  fMesh->ComputeElGraph(elgraph,elgraphindex);
117  int nel = elgraphindex.NElements()-1;
118 #ifdef USING_BOOST
119  TPZBoostGraph boost(nel,nindep);
120  boost.setGType(TPZBoostGraph::KMC);
121  boost.SetElementGraph(elgraph, elgraphindex);
122  boost.CompressedResequence(perm, iperm);
123 #else
124  TPZSloan sloan(nel,nindep);
125  sloan.SetElementGraph(elgraph, elgraphindex);
126  sloan.Resequence(perm, iperm);
127 #endif
128  fMesh->Permute(perm);
129  }
130  int nsub = NSubMesh(fCompMesh);
131  int isub;
132 
133  for(isub=0; isub<nsub; isub++)
134  {
135  TPZSubCompMesh *submesh = SubMesh(fCompMesh, isub);
136 #ifdef PZDEBUG
137  std::cout << '.'; std::cout.flush();
138 #endif
139  if(!submesh)
140  {
141  continue;
142  }
143  TPZVec<int64_t> perm,iperm;
144  TPZStack<int64_t> elgraph,elgraphindex;
145  int64_t nindep = submesh->NIndependentConnects();
146  submesh->ComputeElGraph(elgraph,elgraphindex);
147  int64_t nel = elgraphindex.NElements()-1;
148 #ifdef USING_BOOST
149  TPZBoostGraph boost(nel,nindep);
150  boost.setGType(TPZBoostGraph::KMC);
151  boost.SetElementGraph(elgraph, elgraphindex);
152  boost.CompressedResequence(perm, iperm);
153 #else
154  TPZSloan sloan(nel,nindep);
155  sloan.SetElementGraph(elgraph, elgraphindex);
156  sloan.Resequence(perm, iperm);
157 #endif
158 
159  submesh->Permute(perm);
160 #ifdef PZDEBUG
161  std::stringstream filename;
162  filename << "SubMatrix" << submesh->Index() << ".vtk";
163  TPZFMatrix<REAL> fillin(50,50);
164  submesh->ComputeFillIn(50, fillin);
165  VisualMatrix(fillin, filename.str().c_str());
166 #endif
167  }
168 
169  tempo.ft1comput = timeforcopute.ReturnTimeDouble(); //end of time for compute
170 #ifdef PZDEBUG
171  std::cout << tempo.ft1comput << std::endl;
172  std::cout << "Identifying corner nodes\n";
173  TPZfTime timefornodes; // init of timer
174 #endif
175 
177 
178 #ifdef PZDEBUG
179  tempo.ft4identcorner = timefornodes.ReturnTimeDouble();
180  std::cout << "Total for Identifying Corner Nodes: " << tempo.ft4identcorner << std::endl; // end of timer
181 #endif
182 
184 
185  int64_t neq = fMesh->NEquations();
186  dohr->Resize(neq,neq);
187  // fCornerEqs was initialized during the mesh generation process
188  dohr->SetNumCornerEqs(this->fCornerEqs.size());
189 
190  assembly->fFineEqs.Resize(nsub);
191  assembly->fCoarseEqs.Resize(nsub);
192  for(isub=0; isub<nsub; isub++)
193  {
194  TPZSubCompMesh *submesh = SubMesh(fCompMesh, isub);
195  if(!submesh)
196  {
197  continue;
198  }
200  submesh->ComputeNodElCon();
201  int64_t neq = ((TPZCompMesh *)submesh)->NEquations();
202  // int neq = substruct->fStiffness->Rows();
203 
204  substruct->fNEquations = neq;
205 
206 
207  // identify the equation numbers of the submesh
208  std::map<int,int> globinv,globaleqs;
209  // initialize the globaleqs data structure
210  // the global eqs are ordered in the sequence the connects appear
211  IdentifyEqNumbers(submesh, globaleqs ,globinv);
212  int next = globaleqs.size();
213  substruct->fNumExternalEquations = next;
214  substruct->fNumInternalEquations = submesh->NumInternalEquations();
215  assembly->fFineEqs[isub].Resize(next);
216  std::map<int,int>::iterator it;
217  int count = 0;
218  for(it=globaleqs.begin(); it!=globaleqs.end(); it++)
219  {
220  assembly->fFineEqs[isub][count++] = it->second;
221  }
222 
223 
224  // initialize the permutations from the mesh enumeration to the external enumeration
226  typedef std::pair<ENumbering,ENumbering> Numberingpair;
227  ENumbering tsub,text,tint;
231 
232  TPZVec<int> &toexternal = substruct->fPermutationsScatter[Numberingpair(tsub,text)];
233  TPZVec<int> &fromexternal = substruct->fPermutationsScatter[Numberingpair(text,tsub)];
234  toexternal.Resize(neq,-1);
235  fromexternal.Resize(neq,-1);
236  int nel = globaleqs.size();
237  count = 0;
238  for(it=globaleqs.begin(); it!=globaleqs.end(); it++)
239  {
240  toexternal[it->first] = count++;
241  }
242  count = nel++;
243  int ieq;
244  for(ieq=0; ieq<neq; ieq++)
245  {
246  if(toexternal[ieq] == -1) toexternal[ieq] = count++;
247  }
248  for(ieq=0; ieq<neq; ieq++)
249  {
250  fromexternal[toexternal[ieq]] = ieq;
251  }
252 
253  ComputeInternalEquationPermutation(submesh, substruct->fPermutationsScatter[Numberingpair(tsub,tint)], substruct->fPermutationsScatter[Numberingpair(tint,tsub)]);
254  // IdentifyEqNumbers(submesh, substruct->fGlobalIndex,globinv);
255 
256  // initialize the fC matrix
257  // associate each column of the fC matrix with a coarse index
258  IdentifySubCornerEqs(globinv,substruct->fCoarseNodes,assembly->fCoarseEqs[isub]);
259 
260 
261  // int ncoarse = substruct->fCoarseNodes.NElements();
262 
263  // reorder by internal nodes
264  // the fInternalEqs data structure will not be filled if the connects are made internal
265 
266  // this permutes the nodes of the submesh
267  // This is a lengthy process which should run on the remote processor
268  dohr->AddSubstruct(substruct);
269  }
270  return dohr;
271 }
272 
273 
274 // this will create a DohrMatrix and compute its matrices
276  unsigned numthreads_assemble, unsigned numthreads_decompose)
277 {
278  TPZMatrix<STATE> *dohrgeneric = Create();
279  Assemble(*dohrgeneric, rhs, guiInterface, numthreads_assemble, numthreads_decompose);
280  return dohrgeneric;
281 }
282 
283 template<class TVar>
285 {
286 private:
287 
294  template<class TTVar>
295  struct work_item_t
296  {
297  work_item_t (unsigned submesh_idx, const TPZAutoPointer<TPZDohrSubstructCondense<TTVar> >& substruct) :
298  fSubMeshIndex(submesh_idx), fSubstruct(substruct) {}
299 
300  unsigned fSubMeshIndex;
302  };
303 
305  std::vector<work_item_t<TVar> > work_items;
306  // TODO: Try the cache_aligned_allocator for improved performance.
307  //std::vector<work_item_t<TVar>,cache_aligned_allocator<work_item_t<TVar> > > work_items;
308 
309  /* Pointers to shared data structures. */
312 
313 public:
314 
317  fAssembly(assembly), fMesh(mesh) {}
318 
320  void push_work_item(unsigned submesh_idx, const TPZAutoPointer<TPZDohrSubstructCondense<TVar> >& substruct)
321  {
322  work_items.push_back(work_item_t<TVar>(submesh_idx, substruct));
323  }
324 
326  void run_serial()
327  {
328  typename std::vector<work_item_t<TVar> >::iterator it = work_items.begin();
329  typename std::vector<work_item_t<TVar> >::iterator end = work_items.end();
330 
331  for (;it != end; it++)
332  {
333  work_item_t<TVar>& wi = *it;
334  TPZSubCompMesh* submesh = SubMesh(fMesh, wi.fSubMeshIndex);
335  ::AssembleMatrices(submesh, wi.fSubstruct, fAssembly,NULL);
336  ::DecomposeBig(wi.fSubstruct, -2 /* Do not realloc */);
337  ::DecomposeInternal(wi.fSubstruct, -2 /* Do not realloc */);
338  }
339  }
340 
341 #ifdef USING_TBB
342 
343  void operator()(const blocked_range<size_t>& range) const
344  {
345  for(size_t i=range.begin(); i!=range.end(); ++i ) {
346  const work_item_t<TVar>& wi = work_items[i];
347  TPZSubCompMesh* submesh = SubMesh(fMesh, wi.fSubMeshIndex);
348  ::AssembleMatrices(submesh, wi.fSubstruct, fAssembly,NULL);
349  ::DecomposeBig(wi.fSubstruct,-2 /* Do not realloc */);
350  ::DecomposeInternal(wi.fSubstruct,-2 /* Do not realloc */);
351  }
352  }
353 
355  void run_parallel_for()
356  {
357  /* TBB Parallel for. It will split the range into N sub-ranges and
358  invoke the operator() for each sub-range.*/
359  parallel_for(blocked_range<size_t>(0,work_items.size(), 1 /*IdealGrainSize*/), *this);
360  }
361 #endif
362 
363 };
364 
366  TPZAutoPointer<TPZGuiInterface> guiInterface)
367 {
368  TPZMatrix<STATE> *dohrgeneric = &mat;
370  dynamic_cast<TPZDohrMatrix<STATE,TPZDohrSubstructCondense<STATE> > *> (dohrgeneric);
371 
372  const std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > > &sublist = dohr->SubStructures();
373  unsigned isub;
374  unsigned nsub = NSubMesh(fMesh);
375  std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > >::const_iterator it = sublist.begin();
377 
378  /* Initialize work items. */
379  std::cout << "Assembling " << nsub << " submeshes" << std::endl;
380  for (isub=0; isub<nsub ; isub++) {
381  TPZSubCompMesh *submesh = SubMesh(fMesh, isub);
382  if(!submesh) continue;
383  parallel_tasks.push_work_item(isub, *it);
384  it++;
385  }
386 
387  /* Run assemble and decompose. */
388 #ifdef USING_TBB
389  parallel_tasks.run_parallel_for();
390 #else
391  parallel_tasks.run_serial();
392 #endif
393 
394  /* Post processing. */
395  for (isub=0, it=sublist.begin(); it != sublist.end(); it++, isub++) {
396  TPZFMatrix<STATE> rhsloc((*it)->fNumExternalEquations,1,0.);
397  (*it)->ContributeRhs(rhsloc);
398  fDohrAssembly->Assemble(isub,rhsloc,rhs);
399  }
400 
401  dohr->Initialize();
402 
404 
405  precond->Initialize();
406 
407  fDohrPrecond = precond;
408 
409  return; // dohrgeneric;
410 }
411 
412 template<class T>
414 {
415  ThreadDohrmanAssemblyList_ThreadArgs_t() : thread_idx(-1), list(NULL) {}
416 
417  /* Thread index. */
418  unsigned thread_idx;
419  /* Thread descriptor. */
420  pthread_t pthread;
421  /* List of items to be assembled. */
423 };
424 
431 /* Run statistics. */
435 RunStatsTable dohr_ass ("-tpz_dohr_ass", "Raw data table statistics for TPZDohrStructMatrix::Assemble assemble (first)");
436 RunStatsTable dohr_dec ("-tpz_dohr_dec", "Raw data table statistics for TPZDohrStructMatrix::Assemble decompose (second)");
437 
438 
440  TPZAutoPointer<TPZGuiInterface> guiInterface,
441  unsigned numthreads_assemble, unsigned numthreads_decompose)
442 {
443 #ifdef PERF_ANALYSIS
444  ClockTimer timer;
445  TimingAnalysis ta;
446 #endif
447 
448  TPZMatrix<STATE> *dohrgeneric = &mat;
450  const std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > > &sublist = dohr->SubStructures();
451 
452  int nsub = NSubMesh(fCompMesh); // mod fMesh
453  std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > >::const_iterator it = sublist.begin();
454 
455  /* Create a list of items to assemble. */
457  for (int isub=0; isub<nsub ; isub++) {
458  TPZSubCompMesh *submesh = SubMesh(fCompMesh, isub); // mod fMesh
459  if(!submesh) continue;
461  worklist.Append(work);
462  it++;
463  }
464 
465  if(guiInterface){
466  if(guiInterface->AmIKilled()){
467  return ;//0;
468  }
469  }
470 
471  // First pass : assembling the matrices
472  ThreadDohrmanAssemblyList<STATE> worklistAssemble(worklist);
473  std::list<TPZAutoPointer<ThreadDohrmanAssembly<STATE> > >::iterator itwork =
474  worklistAssemble.fList.begin();
475  while (itwork != worklistAssemble.fList.end()) {
477  itwork++;
478  }
479 
480 
481 #ifdef USING_PAPI
482  float rtime, ptime, mflops;
483  int64_t flpops;
484  PAPI_flops ( &rtime, &ptime, &flpops, &mflops );
485 #endif
486 
487  dohr_ass.start();
488  if (numthreads_assemble == 0) {
489  /* Put the main thread to work on all items. */
491  targ.thread_idx=0;
492  targ.list = &worklistAssemble;
494  }
495  else {
496  /* Threads arguments. */
497  std::vector<ThreadDohrmanAssemblyList_ThreadArgs_t<STATE> > args(numthreads_assemble);
498 
499  /* Assemble multi-threaded */
500  for(unsigned itr=0; itr<numthreads_assemble; itr++)
501  {
503  targ->thread_idx=itr;
504  targ->list = &worklistAssemble;
505  PZ_PTHREAD_CREATE(&targ->pthread, NULL,
507  targ, __FUNCTION__);
508  }
509  /* Sync. */
510  for(unsigned itr=0; itr<numthreads_assemble; itr++)
511  {
512  PZ_PTHREAD_JOIN(args[itr].pthread, NULL, __FUNCTION__);
513  }
514  }
515  dohr_ass.stop();
516 
517 #ifdef USING_PAPI
518  float ltime;
519  PAPI_flops ( &ltime, &ptime, &flpops, &mflops );
520 
521  printf("Assemble Time: %.2f \t", ltime-rtime);
522  printf("Assemble Stiffness : %.2f seconds\n", stiff_sum);
523 
524 #endif
525 #ifdef LOG4CXX
526  if (logger->isDebugEnabled())
527  {
528  int isub = 0;
529  for (it=sublist.begin(); it!=sublist.end(); it++) {
530  std::stringstream sout;
531  sout << "Substructure number " << isub <<std::endl;
532  isub++;
533  // TPZDohrSubstructCondense<STATE> *ptr = (*it).operator->();
534  (*it)->fMatRed->Print("Matred",sout);
535  LOGPZ_DEBUG(logger, sout.str())
536  }
537  }
538 #endif
539 
540  // Second pass : decomposing
541  // Philippe: this may be easier to adapt the code for NUMA.
542  // Edson: TODO: Measure time again.
543  ThreadDohrmanAssemblyList<STATE> worklistDecompose;
544  itwork = worklist.fList.begin();
545  while (itwork != worklist.fList.end()) {
548  worklistDecompose.Append(pt1);
551  worklistDecompose.Append(pt2);
552  itwork++;
553  }
554 
555  dohr_dec.start();
556  if (numthreads_decompose == 0) {
557  /* Compute it sequentialy */
559  targ.thread_idx = 0;
560  targ.list = &worklistDecompose;
562  }
563  else {
564  /* Threads arguments. */
565  std::vector<ThreadDohrmanAssemblyList_ThreadArgs_t<STATE> >
566  args(numthreads_decompose);
567  for(unsigned itr=0; itr<numthreads_decompose; itr++)
568  {
570  targ.thread_idx=itr;
571  targ.list = &worklistDecompose;
572  PZ_PTHREAD_CREATE(&targ.pthread, NULL,
574  &targ, __FUNCTION__);
575  }
576  for(unsigned itr=0; itr<numthreads_decompose; itr++)
577  {
578  PZ_PTHREAD_JOIN(args[itr].pthread, NULL, __FUNCTION__);
579  }
580  }
581  dohr_dec.stop();
582 
583  // Post processing (TODO: check whethe it is time consuming
584  int isub;
585  for (it=sublist.begin(), isub=0; it != sublist.end(); it++,isub++) {
586  TPZFMatrix<STATE> rhsloc((*it)->fNumExternalEquations,1,0.);
587  (*it)->ContributeRhs(rhsloc);
588  fDohrAssembly->Assemble(isub,rhsloc,rhs);
589  }
590 
591  dohr->SetNumThreads(this->fNumThreads);
592 
593  dohr->Initialize();
595  precond->Initialize();
596  fDohrPrecond = precond;
597 
598  return; // dohrgeneric;
599 }
600 
605 {
606  int rows = fMesh->NEquations();
607  rhs.Redim(rows,1);
609  const std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > > &sublist = precond->Global();
610 
611  int nsub = NSubMesh(fMesh);
612  std::list<TPZAutoPointer<TPZDohrSubstructCondense<STATE> > >::const_iterator it = sublist.begin();
613 
614 
615  int isub;
616  for (isub=0; isub<nsub ; isub++) {
617  TPZSubCompMesh *submesh = SubMesh(fCompMesh, isub);
618  if(!submesh)
619  {
620  DebugStop();
621  continue;
622  }
623  TPZFStructMatrix fullstr(submesh);
624  (*it)->fLocalLoad.Zero();
625  fullstr.Assemble((*it)->fLocalLoad,guiInterface);
626  it++;
627  }
628  for (it=sublist.begin(), isub=0; it != sublist.end(); it++,isub++) {
629 
630  // const std::list<TPZAutoPointer<TPZDohrSubstructCondense> > &sublist
631  // *it represents the substructure
632  TPZFMatrix<STATE> rhsloc((*it)->fNumExternalEquations,1,0.);
633  (*it)->ContributeRhs(rhsloc);
634  fDohrAssembly->Assemble(isub,rhsloc,rhs);
635  }
636 
637 
638 }
639 
640 
641 // identify cornernodes
643 {
644  fCornerEqs.clear();
645  TPZStack<int64_t> elementgraph,elementgraphindex;
646  TPZStack<int64_t> expelementgraph,expelementgraphindex;
647  std::set<int> subelindexes;
648  int nelem = fMesh->NElements();
649  int iel;
650  for (iel=0; iel<nelem ; iel++) {
651  TPZSubCompMesh *sub = dynamic_cast<TPZSubCompMesh *> (fMesh->ElementVec()[iel]);
652  if (sub) {
653  subelindexes.insert(iel);
654  }
655  }
656  // Determine the eligible connect sequence numbers
657  std::set<int64_t> cornerconnind;
658  std::set<int> cornerconnseq;
659  fMesh->BuildCornerConnectList(cornerconnind);
660  std::set<int64_t>::iterator it;
661  for (it=cornerconnind.begin(); it!=cornerconnind.end(); it++) {
662  TPZConnect &c = fMesh->ConnectVec()[*it];
663  int seqnum = c.SequenceNumber();
664  cornerconnseq.insert(seqnum);
665  }
666 
667  // fCompMesh->ComputeElGraph(elementgraph,elementgraphindex);
668  int nindep = fMesh->NIndependentConnects();
669  // int neq = fCMesh->NEquations();
670  fMesh->ComputeElGraph(elementgraph,elementgraphindex);
671  int nel = elementgraphindex.NElements()-1;
672  // expand the element graph to include a ficticious internal node to all elements
673  expelementgraphindex.Push(0);
674  int nelprev = nel;
675 
676 
677  int count = 0;
678  for (iel=0; iel<nel; iel++) {
679  int nc = elementgraphindex[iel+1]-elementgraphindex[iel];
680  if (nc) {
681  int index = elementgraphindex[iel];
682  int ic;
683  for (ic=0; ic<nc; ic++) {
684  expelementgraph.Push(0);
685  expelementgraph[count++] = elementgraph[index++];
686  }
687  expelementgraph.Push(0);
688  expelementgraph[count++] = nindep;
689  nindep++;
690  }
691  expelementgraphindex.Push(count);
692  }
693 
694 
695  int next = fExternalConnectIndexes.NElements();
696 
697 
698  if(next)
699  // if(0)
700  {
701  TPZManVector<int> externalconnect(nindep,0);
702  // add the external connects
703  int iext;
704  for (iext=0; iext<next; iext++) {
705  int extindex = fExternalConnectIndexes[iext];
706  int seqnum = fMesh->ConnectVec()[extindex].SequenceNumber();
707  if (seqnum >= 0) {
708  externalconnect[seqnum] = 1;
709  }
710  }
711  nel = expelementgraphindex.NElements()-1;
712  for (iel=0; iel<nel; iel++) {
713  bool hasext = false;
714  int firstnode = expelementgraphindex[iel];
715  int lastnode = expelementgraphindex[iel+1];
716  int nodeindex;
717  for (nodeindex= firstnode; nodeindex < lastnode; nodeindex++) {
718  int node = expelementgraph[nodeindex];
719  if (externalconnect[node] ==1) {
720  hasext = true;
721  break;
722  }
723  }
724  if (hasext) {
725  for (nodeindex= firstnode; nodeindex < lastnode; nodeindex++) {
726  int node = expelementgraph[nodeindex];
727  if (externalconnect[node] ==1) {
728  expelementgraph.Push(node);
729  }
730  expelementgraph.Push(nindep++);
731  }
732  expelementgraphindex.Push(expelementgraph.NElements());
733  }
734  }
735  }
736 
737 
738 
739 
740  // Put a global external element on top of everything
741  // if (next) {
742  if (0) {
743  count = expelementgraph.NElements();
744  int iext;
745  for (iext=0; iext<next; iext++) {
746  int extindex = fExternalConnectIndexes[iext];
747  int seqnum = fMesh->ConnectVec()[extindex].SequenceNumber();
748  if (seqnum >= 0) {
749  expelementgraph.Push(0);
750  expelementgraph[count++] = seqnum;
751  }
752  }
753  expelementgraphindex.Push(count);
754  }
755  nel = expelementgraphindex.NElements()-1;
756  // nel = elementgraphindex.NElements()-1;
757  TPZRenumbering renum(nel,nindep);
758  renum.SetElementGraph(expelementgraph, expelementgraphindex);
759 #ifdef LOG4CXX
760  {
761  std::stringstream sout;
762  renum.Print(expelementgraph, expelementgraphindex,"Expanded graph",sout);
763  if (logger->isDebugEnabled())
764  {
765  LOGPZ_DEBUG(logger, sout.str())
766  }
767  }
768 #endif
769  // renum.SetElementGraph(elementgraph, elementgraphindex);
770  std::set<int> othercornereqs;
771  renum.CornerEqs(3,nelprev,cornerconnseq,othercornereqs);
772 #ifdef LOG4CXX
773  if (logger->isDebugEnabled())
774  {
775  std::stringstream str;
776  int nelem = fMesh->NElements();
777  int iel;
778  int sub = 0;
779  for (iel=0; iel<nelem; iel++) {
780  TPZCompEl *cel = fMesh->ElementVec()[iel];
781  if (!cel) {
782  continue;
783  }
784  str << "SubCMesh " << sub << std::endl;
785  int nc = cel->NConnects();
786  int ic;
787  for (ic=0; ic<nc; ic++) {
788  TPZConnect &con = cel->Connect(ic);
789  int seqnum = con.SequenceNumber();
790  if (othercornereqs.find(seqnum) != othercornereqs.end()) {
791  str << seqnum << " ";
792  }
793  }
794  str << std::endl;
795  sub++;
796  }
797  LOGPZ_DEBUG(logger,str.str());
798  }
799 #endif
800 #ifdef PZDEBUG
801  std::set<int> cornerseqnums;
802 #endif
803  int nnodes = fMesh->Block().NBlocks();
804  int in;
805  for (in=0; in<nnodes; in++) {
806  if (othercornereqs.find(in) != othercornereqs.end()) {
807 #ifdef PZDEBUG
808  cornerseqnums.insert(in);
809 #endif
810  int pos = fMesh->Block().Position(in);
811  int size = fMesh->Block().Size(in);
812  int ieq;
813  for(ieq=0; ieq<size; ieq++)
814  {
815  this->fCornerEqs.insert(pos+ieq);
816  }
817 
818  }
819  }
820 #ifdef PZDEBUG
821  std::cout << "Number cornereqs " << fCornerEqs.size() << std::endl;
822 
823  cornerseqnums = othercornereqs;
824  std::set<int> connectindices;
825  TPZStack<int> geonodeindices;
826  int ncon = fMesh->ConnectVec().NElements();
827  int ic;
828  for (ic=0; ic<ncon; ic++) {
829  if (cornerseqnums.find(fMesh->ConnectVec()[ic].SequenceNumber()) != cornerseqnums.end()) {
830  connectindices.insert(ic);
831  }
832  }
833  int el;
834  int numcel = fMesh->NElements();
835  for (el=0; el<numcel; el++) {
836  TPZCompEl *cel = fMesh->ElementVec()[el];
837  if(!cel) continue;
838  TPZSubCompMesh *submesh = dynamic_cast<TPZSubCompMesh *> (cel);
839  if(!submesh) continue;
840  int elsub;
841  int nelsub = submesh->NElements();
842  for (elsub=0; elsub<nelsub; elsub++) {
843  TPZCompEl *cel = submesh->ElementVec()[elsub];
844  if (!cel) {
845  continue;
846  }
847  int ic;
848  int nc = cel->NConnects();
849  for (ic=0; ic<nc ; ic++) {
850  int connectindex = cel->ConnectIndex(ic);
851  int fatherindex = submesh->NodeIndex(connectindex,fMesh);
852  if(fatherindex != -1)
853  {
854  if (connectindices.find(fatherindex) != connectindices.end())
855  {
856  // good one
857  TPZGeoEl *gel = cel->Reference();
858  int ncornernodes = gel->NCornerNodes();
859  if(ic<ncornernodes)
860  {
861  int nodeindex = gel->NodeIndex(ic);
862  geonodeindices.Push(nodeindex);
863  }
864  connectindices.erase(fatherindex);
865  }
866  }
867  }
868  }
869  }
870  TPZAutoPointer<TPZGeoMesh> pointgmesh = new TPZGeoMesh;
871  pointgmesh->NodeVec() = fMesh->Reference()->NodeVec();
872  TPZManVector<int64_t> nodeindices(1,0);
873  int ngeo = geonodeindices.NElements();
874  int igeo;
875  for (igeo=0; igeo<ngeo; igeo++) {
876  nodeindices[0] = geonodeindices[igeo];
877  int64_t index;
878  pointgmesh->CreateGeoElement(EPoint,nodeindices,1,index);
879  }
880  pointgmesh->BuildConnectivity();
881  std::ofstream arquivo("PointMesh.vtk");
882  TPZVTKGeoMesh::PrintGMeshVTK(pointgmesh.operator->(),arquivo,true);
883 #endif
884 
885 #ifdef LOG4CXX
886  if (logger->isDebugEnabled())
887  {
888  std::stringstream str;
889  str << "number of corner equations " << fCornerEqs.size() << std::endl;
890  int count = 0;
891  str << " corner equations ";
892  std::set<int>::iterator it;
893  for(it=fCornerEqs.begin(); it!=fCornerEqs.end(); it++)
894  {
895  str << *it << " ";
896  count++;
897  if (!(count%100)) {
898  str << std::endl;
899  }
900  }
901  str << std::endl;
902 
903  count = 0;
904 
905  str << "\nnumber of corner block indices after " << othercornereqs.size() << std::endl;
906  for(it=othercornereqs.begin(); it!=othercornereqs.end(); it++)
907  {
908  str << *it << " ";
909  count++;
910  if (!(count%100)) {
911  str << std::endl;
912  }
913 
914  }
915  LOGPZ_DEBUG(logger,str.str());
916  }
917 #endif
918 }
919 
920 // get the global equation numbers of a substructure (and their inverse)
921 void TPZDohrStructMatrix::IdentifyEqNumbers(TPZSubCompMesh *sub, std::map<int,int> &global, std::map<int,int> &globinv)
922 {
923  int64_t ncon = sub->ConnectVec().NElements();
924  // ncon is the number of connects of the subcompmesh
925  TPZCompMesh *super = fMesh;
926  int64_t ic;
927 #ifdef LOG4CXX_STOP
928  std::stringstream sout;
929  sout << "total submesh connects/glob/loc ";
930 #endif
931  for(ic=0; ic<ncon; ic++)
932  {
933  int64_t glob = sub->NodeIndex(ic,super);
934  // continue is the connect is internal
935  if(glob == -1) continue;
936  int64_t locseq = sub->ConnectVec()[ic].SequenceNumber();
937  int64_t globseq = super->ConnectVec()[glob].SequenceNumber();
938  int64_t locpos = sub->Block().Position(locseq);
939  int64_t globpos = super->Block().Position(globseq);
940  int locsize = sub->Block().Size(locseq);
941  // int globsize = super->Block().Size(globseq);
942  int ieq;
943  for(ieq =0; ieq<locsize; ieq++)
944  {
945 #ifdef LOG4CXX_STOP
946  sout << ic << "/" << globpos+ieq << "/" << locpos+ieq << " ";
947 #endif
948  global[locpos+ieq] = globpos+ieq;
949  globinv[globpos+ieq] = locpos+ieq;
950  }
951  }
952 #ifdef LOG4CXX_STOP
953  if (logger->isDebugEnabled())
954  {
955  LOGPZ_DEBUG(logger, sout.str())
956  }
957 #endif
958 }
959 
960 // return the number of submeshes
962 {
963  int64_t nel = compmesh->NElements();
964  TPZCompEl *cel;
965  int64_t iel, count = 0;
966  for(iel=0; iel<nel; iel++)
967  {
968  cel = compmesh->ElementVec()[iel];
969  if(!cel) continue;
970  TPZSubCompMesh *sub = dynamic_cast<TPZSubCompMesh *>(cel);
971  if(sub) count++;
972  }
973  return count;
974 }
975 
976 // return a pointer to the isub submesh
978 {
979  int64_t nel = compmesh->NElements();
980  TPZCompEl *cel;
981  int64_t iel, count = 0;
982  for(iel=0; iel<nel; iel++)
983  {
984  cel = compmesh->ElementVec()[iel];
985  if(!cel) continue;
986  TPZSubCompMesh *sub = dynamic_cast<TPZSubCompMesh *>(cel);
987  if(sub && isub == count) return sub;
988  if(sub) count++;
989  }
990  return NULL;
991 }
992 
993 // computes the permutation vectors from the subcompmesh ordening to the "internal first" ordering
994 // the mesh is modified during this method but is returned to its original state at the end of execution
996  TPZVec<int> &scatterpermute, TPZVec<int> &gatherpermute)
997 {
998  // This permutation vector is with respect to the blocks of the mesh
999  TPZVec<int64_t> scatterpermuteblock;
1000  sub->ComputePermutationInternalFirst(scatterpermuteblock);
1001  TPZBlock<STATE> destblock = sub->Block();
1002  TPZBlock<STATE> &origblock = sub->Block();
1003  int64_t nblocks = origblock.NBlocks();
1004  if(scatterpermuteblock.NElements() != origblock.NBlocks())
1005  {
1006  std::cout << __PRETTY_FUNCTION__ << " something seriously wrong!!!\n";
1007  }
1008  int64_t ib;
1009  for(ib=0; ib<nblocks; ib++)
1010  {
1011  destblock.Set(scatterpermuteblock[ib],origblock.Size(ib));
1012  }
1013  destblock.Resequence();
1014 
1015  int64_t neq = ((TPZCompMesh *)sub)->NEquations();
1016  scatterpermute.Resize(neq);
1017  gatherpermute.Resize(neq);
1018  scatterpermute.Fill(-1);
1019  gatherpermute.Fill(-1);
1020  int64_t ncon = sub->ConnectVec().NElements();
1021 #ifdef LOG4CXX_STOP
1022  std::stringstream sout;
1023  sout << "internal submesh connects/glob/loc ";
1024 #endif
1025  int64_t ic;
1026  for(ic=0; ic<ncon; ic++)
1027  {
1028  // skip dependent connects
1029  TPZConnect &con = sub->ConnectVec()[ic];
1030  if(con.HasDependency() || con.IsCondensed() ) continue;
1031  int64_t locseq = sub->ConnectVec()[ic].SequenceNumber();
1032  // skip unused connects
1033  if(locseq < 0) continue;
1034  int destseq = scatterpermuteblock[locseq];
1035  int64_t locpos = origblock.Position(locseq);
1036  int64_t destpos = destblock.Position(destseq);
1037  int size = origblock.Size(locseq);
1038  // int globsize = super->Block().Size(globseq);
1039  int ieq;
1040  for(ieq =0; ieq<size; ieq++)
1041  {
1042 #ifdef LOG4CXX_STOP
1043  sout << ic << "/" << locpos+ieq << "/" << destpos+ieq << " ";
1044 #endif
1045  scatterpermute[locpos+ieq] = destpos+ieq;
1046  }
1047  }
1048  int64_t ieq;
1049  for(ieq = 0; ieq < neq; ieq++)
1050  {
1051  gatherpermute[scatterpermute[ieq]] = ieq;
1052  }
1053 #ifdef LOG4CXX_STOP
1054  if (logger->isDebugEnabled())
1055  {
1056  LOGPZ_DEBUG(logger, sout.str())
1057  }
1058 #endif
1059 
1060 }
1061 
1062 // Identify the corner equations associated with a substructure
1063 void TPZDohrStructMatrix::IdentifySubCornerEqs(std::map<int,int> &globaltolocal, TPZVec<int> &cornereqs,
1064  TPZVec<int> &coarseindex)
1065 {
1066 #ifdef LOG4CXX
1067  if (logger->isDebugEnabled())
1068  {
1069  std::stringstream sout;
1070  sout << "Input data for IdentifySubCornerEqs \nglobaltolocal";
1071  std::map<int,int>::iterator mapit;
1072  for(mapit = globaltolocal.begin(); mapit != globaltolocal.end(); mapit++)
1073  {
1074  sout << " [" << mapit->first << " , " << mapit->second << "] ";
1075  }
1076  sout << "\nCorner equations stored in the GenSubStructure data ";
1077  std::set<int>::iterator setit;
1078  for(setit = fCornerEqs.begin(); setit != fCornerEqs.end(); setit++)
1079  {
1080  sout << *setit << " , ";
1081  }
1082  sout << "\ncornereqs " << cornereqs;
1083  LOGPZ_DEBUG(logger,sout.str())
1084  }
1085 #endif
1086 
1087 
1088  cornereqs.Resize(fCornerEqs.size());
1089  coarseindex.Resize(fCornerEqs.size());
1090  std::set<int>::iterator it;
1091  int64_t count = 0;
1092  int64_t localcount = 0;
1093  for(it = fCornerEqs.begin(); it!= fCornerEqs.end(); it++,count++)
1094  {
1095  if(globaltolocal.find(*it) != globaltolocal.end())
1096  {
1097  cornereqs[localcount] = globaltolocal[*it];
1098  coarseindex[localcount] = count;
1099  localcount++;
1100  }
1101  }
1102  cornereqs.Resize(localcount);
1103  coarseindex.Resize(localcount);
1104 }
1105 
1106 
1107 // partition the mesh in submeshes
1109 {
1110 
1111  int64_t nel = fMesh->NElements();
1112  int meshdim = fMesh->Dimension();
1113  int64_t nnodes = fMesh->NIndependentConnects();
1114 
1115  TPZMetis metis(nel,nnodes);
1116  TPZStack<int64_t> elgraph,elgraphindex;
1117  fMesh->ComputeElGraph(elgraph,elgraphindex);
1118  metis.SetElementGraph(elgraph, elgraphindex);
1119  TPZManVector<int> domain_index(nel,-1);
1120  metis.Subdivide(nsub, domain_index);
1121  CorrectNeighbourDomainIndex(fMesh, domain_index);
1122 #ifdef PZDEBUG
1123  {
1124  TPZGeoMesh *gmesh = fMesh->Reference();
1125  int64_t nelgeo = gmesh->NElements();
1126  TPZVec<int> domaincolor(nelgeo,-999);
1127  int64_t cel;
1128  for (cel=0; cel<nel; cel++) {
1129  TPZCompEl *compel = fMesh->ElementVec()[cel];
1130  if(!compel) continue;
1131  TPZGeoEl *gel = compel->Reference();
1132  if (!gel) {
1133  continue;
1134  }
1135  domaincolor[gel->Index()] = domain_index[cel];
1136  }
1137  std::ofstream vtkfile("partitionbefore.vtk");
1138  TPZVTKGeoMesh::PrintGMeshVTK(gmesh, vtkfile, domaincolor);
1139  }
1140 #endif
1141  if(meshdim == 3)
1142  {
1143  int nsubnew = 0;
1144  while (nsubnew != nsub)
1145  {
1146  nsubnew = SeparateUnconnected(domain_index,nsub,meshdim-1);
1147  nsub = nsubnew;
1148  }
1149  nsub = ClusterIslands(domain_index,nsub,meshdim-1);
1150  }
1151  CorrectNeighbourDomainIndex(fMesh, domain_index);
1152 #ifdef LOG4CXX
1153  if (logger->isDebugEnabled())
1154  {
1155  std::stringstream sout;
1156  sout << "Geometric mesh and domain indices\n";
1157  fMesh->Reference()->Print(sout);
1158  sout << "Domain indices : \n";
1159  int64_t nel = fMesh->NElements();
1160  for (int64_t el=0; el<nel; el++) {
1161  sout << "el " << el << " domain " << domain_index[el] << std::endl;
1162  }
1163  LOGPZ_DEBUG(logger, sout.str())
1164  }
1165 #endif
1166 
1167 
1168 #ifdef PZDEBUG
1169  {
1170  TPZGeoMesh *gmesh = fMesh->Reference();
1171  int64_t nelgeo = gmesh->NElements();
1172  TPZVec<int> domaincolor(nelgeo,-999);
1173  int64_t cel;
1174  for (cel=0; cel<nel; cel++) {
1175  TPZCompEl *compel = fMesh->ElementVec()[cel];
1176  if(!compel) continue;
1177  TPZGeoEl *gel = compel->Reference();
1178  if (!gel) {
1179  continue;
1180  }
1181  domaincolor[gel->Index()] = domain_index[cel];
1182  }
1183  std::ofstream vtkfile("partition.vtk");
1184  TPZVTKGeoMesh::PrintGMeshVTK(gmesh, vtkfile, domaincolor);
1185  }
1186 #endif
1187  int isub;
1188  TPZManVector<TPZSubCompMesh *> submeshes(nsub,0);
1189  for (isub=0; isub<nsub; isub++) {
1190  int64_t index;
1191 #ifdef PZDEBUG
1192  std::cout << '^'; std::cout.flush();
1193 #endif
1194  submeshes[isub] = new TPZSubCompMesh(*fMesh,index);
1195  if (index < domain_index.NElements()) {
1196  domain_index[index] = -1;
1197  }
1198  }
1199  int64_t iel;
1200  for (iel=0; iel<nel; iel++) {
1201  int domindex = domain_index[iel];
1202  if (domindex >= 0) {
1203  TPZCompEl *cel = fMesh->ElementVec()[iel];
1204  if (!cel) {
1205  continue;
1206  }
1207  submeshes[domindex]->TransferElement(fMesh,iel);
1208  }
1209  }
1210  for (isub = 0; isub<nsub; isub++) {
1211  int64_t nel = submeshes[isub]->NElements();
1212  if (nel == 0) {
1213  delete submeshes[isub];
1214  submeshes[isub] = 0;
1215  }
1216  }
1218  for (isub=0; isub<nsub; isub++) {
1219  if (submeshes[isub])
1220  {
1221  submeshes[isub]->MakeAllInternal();
1222  submeshes[isub]->PermuteExternalConnects();
1223 #ifdef PZDEBUG
1224  std::cout << '*'; std::cout.flush();
1225 #endif
1226  }
1227  }
1228 
1231 }
1232 
1233 // This is a lengthy process which should run on the remote processor assembling all
1235  pthread_mutex_t* TestThread)
1236 {
1237  // static std::set<int> subindexes;
1238  // int index = submesh->Index();
1239  // if (subindexes.find(index) != subindexes.end()) {
1240  // DebugStop();
1241  // }
1242  // subindexes.insert(index);
1243 
1244 
1245  {
1247  typedef std::pair<ENumbering,ENumbering> pairnumbering;
1249  TPZVec<int> &permutescatter = substruct->fPermutationsScatter[fromsub];
1250  // create a skyline matrix based on the current numbering of the mesh
1251  // put the stiffness matrix in a TPZMatRed object to facilitate the computation of phi and zi
1252  TPZSkylineStructMatrix skylstr(submesh);
1253  skylstr.EquationFilter().Reset();
1254 
1255 
1256  TPZAutoPointer<TPZMatrix<STATE> > Stiffness = skylstr.Create();
1257 
1258 
1259  TPZMatRed<STATE, TPZFMatrix<STATE> > *matredbig = new TPZMatRed<STATE,TPZFMatrix<STATE> >(Stiffness->Rows()+substruct->fCoarseNodes.NElements(),Stiffness->Rows());
1260 
1261 
1262  matredbig->SetK00(Stiffness);
1263  substruct->fMatRedComplete = matredbig;
1264 
1265 
1266 
1267  TPZVec<int64_t> permuteconnectscatter;
1268 
1269  substruct->fNumInternalEquations = submesh->NumInternalEquations();
1270 
1271 #ifdef LOG4CXX
1272  if (logger->isDebugEnabled())
1273  {
1274  std::stringstream sout;
1275  sout << "SubMesh Index = " << submesh->Index() << " Before permutation sequence numbers ";
1276  int64_t i;
1277  int64_t ncon = submesh->ConnectVec().NElements();
1278  for (i=0; i<ncon; i++) {
1279  sout << i << '|' << submesh->ConnectVec()[i].SequenceNumber() << " ";
1280  }
1281  LOGPZ_DEBUG(logger,sout.str())
1282  }
1283 #endif
1284  // change the sequencing of the connects of the mesh, putting the internal connects first
1285  submesh->PermuteInternalFirst(permuteconnectscatter);
1286 
1287  // pthread_mutex_lock(&TestThread);
1288 
1289 #ifdef LOG4CXX
1290  if (logger->isDebugEnabled())
1291  {
1292  std::stringstream sout;
1293  sout << "SubMesh Index = " << submesh->Index() << " After permutation sequence numbers ";
1294  int64_t i;
1295  int64_t ncon = submesh->ConnectVec().NElements();
1296  for (i=0; i<ncon; i++) {
1297  sout << i << '|' << submesh->ConnectVec()[i].SequenceNumber() << " ";
1298  }
1299  LOGPZ_DEBUG(logger,sout.str())
1300  }
1301 #endif
1302 #ifdef LOG4CXX
1303  if (logger->isDebugEnabled())
1304  {
1305  std::stringstream sout;
1306  sout << "SubMesh Index = " << submesh->Index() << "\nComputed scatter vector ";
1307  sout << permuteconnectscatter;
1308  sout << "\nStored scatter vector " << permutescatter;
1309  LOGPZ_DEBUG(logger,sout.str())
1310  }
1311 #endif
1312 
1313 
1314  // create a "substructure matrix" based on the submesh using a skyline matrix structure as the internal matrix
1316  TPZMatRed<STATE, TPZVerySparseMatrix<STATE> > *matredptr = dynamic_cast<TPZMatRed<STATE, TPZVerySparseMatrix<STATE> > *>(redstruct.Create());
1317  //TPZAutoPointer<TPZMatRed<TPZVerySparseMatrix> > matred = matredptr;
1318 
1319  // create a structural matrix which will assemble both stiffnesses simultaneously
1320  // permutescatter will reorder the equations to internal first
1321  TPZPairStructMatrix pairstructmatrix(submesh,permutescatter);
1322 
1323  // reorder the sequence numbering of the connects to reflect the original ordering
1324  TPZVec<int64_t> invpermuteconnectscatter(permuteconnectscatter.NElements());
1325  int64_t iel;
1326  for (iel=0; iel < permuteconnectscatter.NElements(); iel++) {
1327  invpermuteconnectscatter[permuteconnectscatter[iel]] = iel;
1328  }
1329  TPZAutoPointer<TPZMatrix<STATE> > InternalStiffness = matredptr->K00();
1330 
1331 #ifdef PZDEBUG
1332  std::stringstream filename;
1333  filename << "SubMatrixInternal" << submesh->Index() << ".vtk";
1334  TPZFMatrix<REAL> fillin(50,50);
1335  submesh->ComputeFillIn(50, fillin);
1336  VisualMatrix(fillin, filename.str().c_str());
1337 #endif
1338 
1339  // put the equation back in the optimized ordering for all equations (original ordering)
1340  submesh->Permute(invpermuteconnectscatter);
1341 
1342 
1343 
1344  // pthread_mutex_unlock(&TestThread);
1345 
1346  // compute both stiffness matrices simultaneously
1347  substruct->fLocalLoad.Redim(Stiffness->Rows(),1);
1348 #ifdef USING_PAPI
1349  float rtime, ptime, mflops, ltime;
1350  int64_t flpops;
1351 
1352  PAPI_flops ( &rtime, &ptime, &flpops, &mflops );
1353 #endif
1354  pairstructmatrix.Assemble(Stiffness.operator->(), matredptr, substruct->fLocalLoad);
1355 #ifdef USING_PAPI
1356  PAPI_flops ( &ltime, &ptime, &flpops, &mflops );
1357  //printf("Stiff: %.2f \t", ltime-rtime);
1358 
1359  stiff_sum += ltime-rtime;
1360 #endif
1361  // fLocalLoad is in the original ordering of the submesh
1362  matredbig->SimetrizeMatRed();
1363  matredptr->SimetrizeMatRed();
1364 
1365  substruct->fWeights.Resize(Stiffness->Rows());
1366  int64_t i;
1367  for(i=0; i<substruct->fWeights.NElements(); i++)
1368  {
1369  substruct->fWeights[i] = Stiffness->GetVal(i,i);
1370  }
1371  // Desingularize the matrix without affecting the solution
1372  int64_t ncoarse = substruct->fCoarseNodes.NElements(), ic;
1373  int64_t neq = Stiffness->Rows();
1374  for(ic=0; ic<ncoarse; ic++)
1375  {
1376  int coarse = substruct->fCoarseNodes[ic];
1377  Stiffness->operator()(coarse,coarse) += 10.;
1378  //Philippe 7/6/2012
1379  //matredbig->operator()(coarse,coarse) += 10.;
1380  matredbig->operator()(neq+ic,coarse) = 1.;
1381  matredbig->operator()(coarse,neq+ic) = 1.;
1382  }
1383  //substruct->fStiffness = Stiffness;
1384  TPZStepSolver<STATE> *InvertedStiffness = new TPZStepSolver<STATE>(Stiffness);
1385  InvertedStiffness->SetMatrix(Stiffness);
1386 
1387  //EBORIN: Uncomment the following line to replace Cholesky by LDLt decomposition
1388  //#ifdef USE_LDLT_DECOMPOSITION
1389 
1390 #ifdef USE_LDLT_DECOMPOSITION
1391  InvertedStiffness->SetDirect(ELDLt);
1392 #else
1393  InvertedStiffness->SetDirect(ECholesky);
1394 #endif
1395  matredbig->SetSolver(InvertedStiffness);
1396 
1397 
1398  TPZStepSolver<STATE> *InvertedInternalStiffness = new TPZStepSolver<STATE>(InternalStiffness);
1399  InvertedInternalStiffness->SetMatrix(InternalStiffness);
1400 #ifdef DUMP_LDLT_MATRICES
1401  InvertedInternalStiffness->SetDirect(ELDLt);
1402 #else
1403  InvertedInternalStiffness->SetDirect(ECholesky);
1404 #endif
1405  matredptr->SetSolver(InvertedInternalStiffness);
1406  matredptr->SetReduced();
1407  TPZMatRed<STATE,TPZFMatrix<STATE> > *matredfull = new TPZMatRed<STATE,TPZFMatrix<STATE> >(*matredptr);
1408  substruct->fMatRed = matredfull;
1409 
1410 
1411  }
1412 }
1413 
1414 #ifdef DUMP_LDLT_MATRICES
1415 
1416 #include "pzbfilestream.h"
1417 pthread_mutex_t dump_matrix_mutex = PTHREAD_MUTEX_INITIALIZER;
1418 unsigned matrix_unique_id = 0;
1419 
1420 void dump_matrix(TPZAutoPointer<TPZMatrix<STATE> > Stiffness)
1421 {
1422  PZ_PTHREAD_MUTEX_LOCK(&dump_matrix_mutex, "dump_matrix");
1423  std::cout << "Dump stiffness matrix at DecomposeBig..." << std::endl;
1424  std::stringstream fname;
1425  fname << "matrix_" << matrix_unique_id++ << ".bin";
1426  TPZBFileStream fs;
1427  fs.OpenWrite(fname.str());
1428  Stiffness->Write(fs, 0);
1429  std::cout << "Dump stiffness matrix at DecomposeBig... [Done]" << std::endl;
1430  PZ_PTHREAD_MUTEX_UNLOCK(&dump_matrix_mutex, "dump_matrix");
1431 }
1432 
1433 #endif
1434 
1435 //EBORIN: consumes tasks from the ThreadDohrmanAssemblyList list. The tasks
1436 // are ThreadDohrmanAssembly::AssembleMatrices
1437 
1438 #ifdef USING_LIBNUMA
1439 #include<numa.h>
1440 class NUMA_mng_t {
1441 
1442 public:
1443  NUMA_mng_t() {
1444  max_node_id = numa_max_node();
1445  next_rr_node = 0;
1446  }
1449  unsigned get_num_nodes() {return (max_node_id+1);}
1451  unsigned get_rr_node_id() {return (next_rr_node++);}
1452 
1453 private:
1454 
1455  unsigned max_node_id;
1457  unsigned next_rr_node;
1458 };
1459 
1460 NUMA_mng_t NUMA;
1461 #endif
1462 
1463 clarg::argBool naa("-naDALora", "NUMA aware Dohrman Assembly List thread work objects re-allocation.", false);
1464 clarg::argInt naat("-naDALorat", "NUMA aware Dohrman Assembly List thread work objects re-allocation threshold.", 0);
1465 
1466 #ifdef USING_LIBNUMA
1467 clarg::argBool nats("-naDALtws", "NUMA aware (node round-robin) Dohrman Assembly List thread work scheduling.", false);
1468 #endif
1469 
1471 {
1472  TPZAutoPointer<TPZMatRed<STATE,TPZFMatrix<STATE> > > matredbig = substruct->fMatRedComplete;
1473  TPZAutoPointer<TPZMatrix<STATE> > Stiffness = matredbig->K00();
1474 
1475  if (Stiffness->MemoryFootprint() > naat.get_value()) {
1476  Stiffness.ReallocForNuma(numa_node);
1477  }
1478 
1479 #ifdef USE_LDLT_DECOMPOSITION
1480  Stiffness->Decompose_LDLt();
1481 #else
1482  Stiffness->Decompose_Cholesky();
1483 #endif
1484 
1485  substruct->Initialize();
1486 }
1487 
1489 {
1490  TPZAutoPointer<TPZMatRed<STATE,TPZFMatrix<STATE> > > matred = substruct->fMatRed;
1491  TPZAutoPointer<TPZMatrix<STATE> > InternalStiffness = matred->K00();
1492 
1493  if (InternalStiffness->MemoryFootprint() > naat.get_value()) {
1494  InternalStiffness.ReallocForNuma(numa_node);
1495  }
1496 
1497 #ifdef USE_LDLT_DECOMPOSITION
1498  InternalStiffness->Decompose_LDLt();
1499 #else
1500  InternalStiffness->Decompose_Cholesky();
1501 #endif
1502 }
1503 
1504 //EComputeMatrix, EDecomposeInternal, EDecomposeBig
1505 template<class TVar>
1506 void ThreadDohrmanAssembly<TVar>::AssembleMatrices(pthread_mutex_t &threadtest, int numa_node)
1507 {
1508  ThreadDohrmanAssembly *threadData = this;
1509  TPZSubCompMesh *submesh = SubMesh(threadData->fMesh,threadData->fSubMeshIndex);
1510  switch (fTask) {
1511  case EComputeMatrix:
1512  ::AssembleMatrices(submesh,threadData->fSubstruct,threadData->fAssembly,&threadtest);
1513  break;
1514  case EDecomposeInternal:
1515  DecomposeInternal(threadData->fSubstruct, numa_node);
1516  break;
1517  case EDecomposeBig:
1518  DecomposeBig(threadData->fSubstruct, numa_node);
1519  break;
1520  default:
1521  DebugStop();
1522  break;
1523  }
1524 #ifdef LOG4CXX
1525  if (fTask == EComputeMatrix)
1526  if (logger->isDebugEnabled())
1527  {
1528  std::stringstream sout;
1529  /* sout << "Submesh for element " << iel << std::endl;
1530  submesh->Print(sout);*/
1531  sout << "Substructure for submesh " << fSubMeshIndex << std::endl;
1532  fSubstruct->Print(sout);
1533  LOGPZ_DEBUG(loggerasm,sout.str())
1534  }
1535 #endif
1536 
1537 }
1538 
1539 template<class TVar>
1541 {
1542  PZ_PTHREAD_MUTEX_INIT(&fAccessElement,NULL,"ThreadDohrmanAssemblyList::ThreadDohrmanAssemblyList()");
1543  PZ_PTHREAD_MUTEX_INIT(&fTestThreads,NULL,"ThreadDohrmanAssemblyList::ThreadDohrmanAssemblyList()");
1544 }
1545 
1546 template<class TVar>
1548 {
1549  PZ_PTHREAD_MUTEX_INIT(&fAccessElement,NULL,"ThreadDohrmanAssemblyList::ThreadDohrmanAssemblyList()");
1550  PZ_PTHREAD_MUTEX_INIT(&fTestThreads,NULL,"ThreadDohrmanAssemblyList::ThreadDohrmanAssemblyList()");
1551 }
1552 
1553 template<class TVar>
1555 {
1556  PZ_PTHREAD_MUTEX_DESTROY(&fAccessElement,"ThreadDohrmanAssemblyList::~ThreadDohrmanAssemblyList()");
1557  PZ_PTHREAD_MUTEX_DESTROY(&fTestThreads,"ThreadDohrmanAssemblyList::~ThreadDohrmanAssemblyList()");
1558 }
1559 
1560 template<class TVar>
1562 {
1563  PZ_PTHREAD_MUTEX_LOCK(&fAccessElement, "ThreadDohrmanAssemblyList::Append()");
1564  fList.push_back(object);
1565  PZ_PTHREAD_MUTEX_UNLOCK(&fAccessElement, "ThreadDohrmanAssemblyList::Append()");
1566 }
1567 
1568 template<class TVar>
1570 {
1572  PZ_PTHREAD_MUTEX_LOCK(&fAccessElement, "ThreadDohrmanAssemblyList::NextObject()");
1573  if (fList.begin() != fList.end()) {
1574  result = *fList.begin();
1575  fList.pop_front();
1576  }
1577  PZ_PTHREAD_MUTEX_UNLOCK(&fAccessElement, "ThreadDohrmanAssemblyList::NextObject()");
1578  return result;
1579 }
1580 
1581 template<class TVar>
1583 {
1586 
1587  /* bind thread and newlly allocated memory to node if -naDALtws is set. */
1588  int node_id = -2 /* Do not realloc */;
1589 
1590 #ifdef USING_LIBNUMA
1591  if (nats.was_set()) {
1592  struct bitmask* nodemask = numa_allocate_nodemask();
1593  numa_bitmask_clearall(nodemask);
1594  numa_bitmask_setbit(nodemask,args->thread_idx%NUMA.get_num_nodes());
1595  numa_bind(nodemask);
1596  numa_free_nodemask(nodemask);
1597  }
1598  if (naa.was_set()) {
1599  node_id = args->thread_idx%NUMA.get_num_nodes();
1600  }
1601 #else
1602  if (naa.was_set()) {
1603  node_id = -1; /* Realloc */
1604  }
1605 #endif
1606 
1607  TPZAutoPointer<ThreadDohrmanAssembly<TVar> > runner = args->list->NextObject();
1608 
1609  while (runner) {
1610  runner->AssembleMatrices(args->list->fTestThreads,node_id);
1611  runner = args->list->NextObject();
1612  }
1613 
1614  return 0;
1615 }
1616 
1617 // Identify the external connects
1619 {
1620  // for each computational element
1621  std::set<int64_t> connectindexes;
1622  int64_t iel;
1623  int64_t nel = fMesh->NElements();
1624  for (iel=0; iel<nel; iel++) {
1625  // if it has a neighbour along its interior, skip
1626  TPZCompEl *cel = fMesh->ElementVec()[iel];
1627  if (!cel) {
1628  continue;
1629  }
1630  TPZGeoEl *gel = cel->Reference();
1631  if (!gel) {
1632  continue;
1633  }
1634  int is;
1635  int ns = gel->NSides();
1636  int dim = gel->Dimension();
1637  TPZStack<TPZCompElSide> compneigh;
1638 
1639  // if there is a neighbour along the side of dimension dim skip
1640  TPZGeoElSide gelside(gel,ns-1);
1641  gelside.ConnectedCompElementList(compneigh,0,0);
1642  if (compneigh.NElements()) {
1643  continue;
1644  }
1645  TPZInterpolatedElement *intel = dynamic_cast<TPZInterpolatedElement *> (cel);
1646  if (!intel) {
1647  continue;
1648  }
1649  // loop over the sides of dimension dim-1
1650  for (is=0; is<ns; is++)
1651  {
1652  // if there is a neighbour of dimension >= dim skip
1653  // the side connects are external
1654  TPZGeoElSide gelside(gel,is);
1655  if (gelside.Dimension() != dim-1) {
1656  continue;
1657  }
1658  compneigh.Resize(0);
1659  gelside.ConnectedCompElementList(compneigh, 0, 0);
1660  int64_t ncomp = compneigh.NElements();
1661  int64_t ic;
1662  for (ic=0; ic<ncomp; ic++) {
1663  TPZCompElSide celside = compneigh[ic];
1664  TPZGeoElSide gelside = celside.Reference();
1665  if (gelside.Element()->Dimension() == dim) {
1666  break;
1667  }
1668  }
1669  // if no neighbour has dimension dim
1670  if (ic == ncomp) {
1671  int nsconnect = intel->NSideConnects(is);
1672  int isc;
1673  for (isc=0; isc<nsconnect; isc++) {
1674  int64_t ind = intel->SideConnectIndex(isc,is);
1675  connectindexes.insert(ind);
1676  }
1677  }
1678  }
1679  }
1680  std::set<int64_t>::iterator it;
1681  fExternalConnectIndexes.Resize(connectindexes.size());
1682  int64_t i = 0;
1683  for (it=connectindexes.begin(); it != connectindexes.end(); it++,i++) {
1684  fExternalConnectIndexes[i] = *it;
1685  }
1686 }
1687 
1688 // Verifies if the subdomains are connected by sides of connectdimension and separate them if not
1689 // returns the new number of subdomains
1690 int TPZDohrStructMatrix::SeparateUnconnected(TPZVec<int> &domain_index, int nsub, int connectdimension)
1691 {
1692  std::map<int,int> domain_index_count;
1693  int64_t iel;
1694  int64_t nel = fMesh->NElements();
1695  for (iel=0; iel<nel; iel++) {
1696  TPZCompEl *cel = fMesh->ElementVec()[iel];
1697  if (!cel) {
1698  continue;
1699  }
1700  int mydomainindex = domain_index[cel->Index()];
1701  domain_index_count[mydomainindex]++;
1702  }
1703  std::set<int> domain_check;
1704 
1705  for (iel=0; iel<nel; iel++) {
1706  TPZCompEl *cel = fMesh->ElementVec()[iel];
1707  if (!cel) {
1708  continue;
1709  }
1710  int mydomainindex = domain_index[cel->Index()];
1711  if (domain_check.find(mydomainindex) != domain_check.end()) {
1712  continue;
1713  }
1714  domain_check.insert(mydomainindex);
1715  TPZGeoEl *gel = cel->Reference();
1716  if (!gel) {
1717  continue;
1718  }
1719 
1720  TPZStack<TPZGeoEl *> gelstack;
1721  gelstack.Push(gel);
1722  std::set<TPZCompEl *> gelcluster;
1723  while (gelstack.NElements())
1724  {
1725  TPZGeoEl *gel = gelstack.Pop();
1726  if (gelcluster.find(gel->Reference()) != gelcluster.end()) {
1727  continue;
1728  }
1729  int beforesize = gelcluster.size();
1730  gelcluster.insert(gel->Reference());
1731  int checksize = gelcluster.size();
1732  if (checksize == beforesize) {
1733  DebugStop();
1734  }
1735 
1736  int nsides = gel->NSides();
1737  int is;
1738  for (is=0; is<nsides; is++) {
1739  int sidedim = gel->SideDimension(is);
1740  if (sidedim != connectdimension) {
1741  continue;
1742  }
1743  TPZGeoElSide gelside(gel,is);
1744  TPZStack<TPZCompElSide> elsidevec;
1745  gelside.ConnectedCompElementList(elsidevec, 0, 0);
1746  int64_t nneigh = elsidevec.NElements();
1747  int64_t neigh;
1748  for (neigh = 0; neigh <nneigh; neigh++) {
1749  TPZCompElSide celside = elsidevec[neigh];
1750  TPZCompEl *celloc = celside.Element();
1751  if (domain_index[celloc->Index()] != mydomainindex) {
1752  continue;
1753  }
1754  if (gelcluster.find(celloc) == gelcluster.end()) {
1755  gelstack.Push(celloc->Reference());
1756  }
1757  }
1758  }
1759  }
1760 
1761  if (gelcluster.size() != (std::set<TPZCompEl *>::size_type)domain_index_count[mydomainindex]) {
1762  if (gelcluster.size() > (std::set<TPZCompEl *>::size_type)domain_index_count[mydomainindex]) {
1763  DebugStop();
1764  }
1765  domain_index_count[mydomainindex] -= gelcluster.size();
1766  domain_index_count[nsub] = gelcluster.size();
1767  std::set<TPZCompEl *>::iterator it;
1768  domain_check.erase(mydomainindex);
1769  domain_check.insert(nsub);
1770  for (it=gelcluster.begin(); it!=gelcluster.end(); it++) {
1771  domain_index[(*it)->Index()]=nsub;
1772  }
1773  nsub++;
1774  }
1775  }
1776 
1777 #ifdef LOG4CXX
1778  if (logger->isDebugEnabled())
1779  {
1780  std::stringstream sout;
1781  sout << "Number of elements per domain ";
1782  std::map<int,int>::iterator it;
1783  int64_t count = 0;
1784  for (it=domain_index_count.begin(); it != domain_index_count.end(); it++) {
1785  if (! (count++ %40)) {
1786  sout << std::endl;
1787  }
1788  sout << it->first << " " << it->second << " " << std::endl;
1789  }
1790  LOGPZ_DEBUG(logger,sout.str())
1791  }
1792 #endif
1793  return nsub;
1794 }
1795 
1796 // Eliminate subdomains who are embedded in other subdomains
1797 // returns the number of subdomains
1798 int TPZDohrStructMatrix::ClusterIslands(TPZVec<int> &domain_index,int nsub,int connectdimension)
1799 {
1800  int meshdim = fMesh->Dimension();
1801  int64_t nel = fMesh->NElements();
1802  int64_t mincount = nel/nsub/20;
1803  // contains for each subdomain the set of neighbouring domains
1804  TPZVec<std::set<int> > domain_neighbours(nsub);
1805  // contains for each domain the number of cells within that domain
1806  std::map<int,int> domain_index_count;
1807  int64_t iel;
1808  for (iel=0; iel<nel; iel++) {
1809  TPZCompEl *cel = fMesh->ElementVec()[iel];
1810  if (!cel) {
1811  continue;
1812  }
1813  int mydomainindex = domain_index[cel->Index()];
1814  // if (mydomainindex == 0) {
1815  // std::stringstream sout;
1816  // cel->Print(sout);
1817  // TPZGeoEl *gel = cel->Reference();
1818  // if (gel) {
1819  // gel->Print(sout);
1820  // }
1821  // LOGPZ_DEBUG(logger, sout.str())
1822  // }
1823  domain_index_count[mydomainindex]++;
1824  TPZGeoEl *gel = cel->Reference();
1825  if (!gel) {
1826  continue;
1827  }
1828  int nsides = gel->NSides();
1829  int geldim = gel->Dimension();
1830  int is;
1831  for (is=0; is<nsides; is++) {
1832  int sidedim = gel->SideDimension(is);
1833  if (sidedim != connectdimension && geldim>=connectdimension) {
1834  continue;
1835  }
1836  if (geldim < connectdimension && is != nsides-1)
1837  {
1838  continue;
1839  }
1840  TPZGeoElSide gelside(gel,is);
1841  TPZStack<TPZCompElSide> elsidevec;
1842  gelside.ConnectedCompElementList(elsidevec, 0, 0);
1843  int64_t nneigh = elsidevec.NElements();
1844  int64_t neigh;
1845  int64_t nneighvalid = 0;
1846  for (neigh = 0; neigh <nneigh; neigh++) {
1847  TPZCompElSide celside = elsidevec[neigh];
1848  TPZCompEl *celloc = celside.Element();
1849  TPZGeoEl *gelloc = celloc->Reference();
1850  if (gelloc->Dimension() != meshdim) {
1851  continue;
1852  }
1853  nneighvalid++;
1854  int celdomain = domain_index[celloc->Index()];
1855  if (celdomain != mydomainindex)
1856  {
1857  domain_neighbours[mydomainindex].insert(celdomain);
1858  }
1859  }
1860  if (nneighvalid == 0)
1861  {
1862  // include the boundary as a ficticious neighbour index
1863  domain_neighbours[mydomainindex].insert(-1);
1864  }
1865  }
1866  }
1867 #ifdef LOG4CXX
1868  if(logger->isDebugEnabled())
1869  {
1870  std::stringstream sout;
1871  for (int64_t i=0; i<domain_neighbours.size(); i++) {
1872  std::set<int>::const_iterator it;
1873  sout << "Domain index " << i << " neighbours ";
1874  for (it=domain_neighbours[i].begin(); it != domain_neighbours[i].end(); it++) {
1875  sout << *it << " ";
1876  }
1877  sout << std::endl;
1878  }
1879  std::map<int,int>::const_iterator it = domain_index_count.begin();
1880  while (it != domain_index_count.end()) {
1881  sout << "Domain index " << it->first << " number of elements " << it->second << std::endl;
1882  it++;
1883  }
1884  LOGPZ_DEBUG(logger, sout.str())
1885 
1886  }
1887 #endif
1888  // compute a destination domain index for each domain (used for clustering domains)
1889  int isub;
1890  TPZManVector<int> domain_dest(nsub,-1);
1891  int64_t count = 0;
1892  for (isub=0; isub < nsub; isub++)
1893  {
1894  // if the subdomain is neighbour to only one subdomain
1895  // this means that the subdomain is isolated (only boundaries as neighbours) (not treated)
1896  // or that the domain is embedded in another domain
1897  if (domain_neighbours[isub].size() == 1 )
1898  {
1899  // merge both subdomains
1900  int target = *(domain_neighbours[isub].begin());
1901  // target == -1 is not treated here
1902  if (target == -1) {
1903  continue;
1904  }
1905  if (domain_dest[target] == -1 && domain_dest[isub] == -1)
1906  {
1907  domain_dest[isub] = count;
1908  domain_dest[target] = count;
1909  count++;
1910  }
1911  else if (domain_dest[target] == -1)
1912  {
1913  domain_dest[target] = domain_dest[isub];
1914  }
1915  else
1916  {
1917  domain_dest[isub] = domain_dest[target];
1918  }
1919 
1920  }
1921  else if(domain_dest[isub] == -1 && domain_index_count[isub] < mincount)
1922  {
1923  // the domain has very little elements
1924  // the domain has at least two neighbouring domains (may include the ficticious -1 domain)
1925  std::map<int,int> sizeDomain;
1926  std::set<int>::iterator it;
1927  for (it = domain_neighbours[isub].begin(); it != domain_neighbours[isub].end(); it++) {
1928  if (*it != -1) {
1929  sizeDomain[domain_index_count[isub]] = *it;
1930  }
1931  }
1932  int domaintargetindex = sizeDomain.rbegin()->second;
1933  int destdomainindexcount = domain_index_count[domaintargetindex];
1934  int domainshrinkcount = domain_index_count[isub];
1935  domain_index_count[domaintargetindex] = destdomainindexcount+domainshrinkcount;
1936  domain_index_count[isub] = 0;
1937  if(domain_dest[domaintargetindex] == -1)
1938  {
1939  domain_dest[domaintargetindex] = count;
1940  domain_dest[isub] = count;
1941  count++;
1942  }
1943  else {
1944  domain_dest[isub] = domain_dest[domaintargetindex];
1945  }
1946 
1947  }
1948  else if (domain_dest[isub] == -1)
1949  {
1950  domain_dest[isub] = count++;
1951  }
1952  }
1953 #ifdef LOG4CXX
1954  if (logger->isDebugEnabled())
1955  {
1956  std::stringstream sout;
1957  int isub;
1958  for (isub=0; isub < nsub; isub++) {
1959  sout << "isub = " << isub << " number of neighbours " << domain_neighbours[isub].size() << " domains ";
1960  std::set<int>::iterator it;
1961  for (it = domain_neighbours[isub].begin(); it != domain_neighbours[isub].end(); it++) {
1962  sout << *it << " ";
1963  }
1964  sout << std::endl;
1965  }
1966  sout << "Destination domain " << domain_dest << std::endl;
1967  LOGPZ_DEBUG(logger,sout.str())
1968  }
1969 #endif
1970  int domsize = domain_index.NElements();
1971  int d;
1972  for (d=0; d<domsize; d++) {
1973  domain_index[d] = domain_dest[domain_index[d]];
1974  }
1975 #ifdef LOG4CXX
1976  if (logger->isDebugEnabled())
1977  {
1978  std::stringstream sout;
1979  sout << "Number of elements per domain ";
1980  std::map<int,int>::iterator it;
1981  int64_t count = 0;
1982  for (it=domain_index_count.begin(); it != domain_index_count.end(); it++) {
1983  if (! (count++ %40)) {
1984  sout << std::endl;
1985  }
1986  sout << it->first << " " << it->second << " ";
1987  }
1988  LOGPZ_DEBUG(logger,sout.str())
1989  }
1990 #endif
1991 
1992  return count;
1993 }
1994 
1995 void TPZDohrStructMatrix::Write( TPZStream &str, int withclassid ) const
1996 {
1998  int hasdohrassembly = 0;
1999  if (fDohrAssembly) {
2000  hasdohrassembly = 1;
2001  }
2002  str.Write(&hasdohrassembly);
2003  if (hasdohrassembly) {
2004  TPZPersistenceManager::WritePointer(fDohrAssembly.operator ->(), &str);
2005  }
2006  str.Write( fExternalConnectIndexes);
2007  str.Write(fCornerEqs);
2008 }
2009 
2010 void TPZDohrStructMatrix::Read(TPZStream &str, void *context )
2011 {
2012  SetMesh(TPZAutoPointerDynamicCast<TPZCompMesh>(TPZPersistenceManager::GetAutoPointer(&str)));
2013  int hasdohrassembly;
2014  str.Read(&hasdohrassembly);
2015  if (hasdohrassembly) {
2016  fDohrAssembly = TPZAutoPointerDynamicCast<TPZDohrAssembly<STATE>>(TPZPersistenceManager::GetAutoPointer(&str));
2017  }
2018  str.Read( fExternalConnectIndexes);
2019  str.Read( fCornerEqs);
2020 }
2021 
2024 {
2025  int64_t nel = cmesh->NElements();
2026  TPZAdmChunkVector<TPZCompEl *> &elvec = cmesh->ElementVec();
2027  bool changed = true;
2028  while(changed)
2029  {
2030  changed = false;
2031  for (int64_t el=0; el<nel; el++) {
2032  TPZCompEl *cel = elvec[el];
2033  if (! cel) {
2034  continue;
2035  }
2036  TPZGeoEl *gel = cel->Reference();
2037  if (!gel) {
2038  continue;
2039  }
2040  int nsides = gel->NSides();
2041  TPZGeoElSide neighbour = gel->Neighbour(nsides-1);
2042  if (neighbour.Element() != gel) {
2043  TPZCompEl *neighcel = neighbour.Element()->Reference();
2044  if (! neighcel) {
2045  continue;
2046  }
2047  int64_t neighindex = neighcel->Index();
2048  if (domainindex[el] != domainindex[neighindex]) {
2049  domainindex[el] = domainindex[neighindex];
2050  changed = true;
2051  }
2052  }
2053  }
2054  }
2055 }
2056 
void IdentifySubCornerEqs(std::map< int, int > &globaltolocal, TPZVec< int > &cornereqs, TPZVec< int > &coarseindex)
Identify the corner equations associated with a substructure.
int64_t NElements() const
Number of computational elements allocated.
Definition: pzcmesh.h:169
Contains a class to record running statistics on CSV tables.
int fNumThreads
Number of threads in Assemble process.
TPZGeoMesh * Reference() const
Returns a pointer to the geometrical mesh associated.
Definition: pzcmesh.h:209
#define PZ_PTHREAD_MUTEX_UNLOCK(mutex, fn)
Definition: pz_pthread.h:79
void Assemble(int isub, const TPZFMatrix< TVar > &local, TPZFMatrix< TVar > &global) const
Sum the values in the local matrix into the global matrix.
REAL ft4identcorner
Total Time for Identifying Corner Nodes = Convert Graph + AnalyseGraph.
Definition: TPZTimeTemp.h:50
void ComputeInternalEquationPermutation(TPZSubCompMesh *sub, TPZVec< int > &scatterpermute, TPZVec< int > &gatherpermute)
Computes the permutation vectors from the subcompmesh ordening to the "internal first" ordering...
Contains the TPZTimeTemp class which takes times.
void CorrectNeighbourDomainIndex(TPZCompMesh *cmesh, TPZVec< int > &domainindex)
Set the domain index of the lower dimension elements equal to the domain index of their neighbour...
int Position(const int block_diagonal) const
Returns the position of first element block dependent on matrix diagonal.
Definition: pzblock.h:177
void AssembleMatrices(pthread_mutex_t &testthread, int numa_node)
void SetElementGraph(TPZVec< int64_t > &elgraph, TPZVec< int64_t > &elgraphindex)
This method declares the element graph to the object.
filename
Definition: stats.py:82
Implements computational element and a side. Computational Element.
Definition: pzcompel.h:632
int Set(const int index, const int dim, const int pos=-1)
Modifies existing block dimensions or creates a new block with given index.
Definition: pzblock.cpp:104
Represents a set of shape functions associated with a computational element/side. Computational Eleme...
Definition: pzconnect.h:30
Definition: pzmatrix.h:52
Contains definitions to LOGPZ_DEBUG, LOGPZ_INFO, LOGPZ_WARN, LOGPZ_ERROR and LOGPZ_FATAL, and the implementation of the inline InitializePZLOG(string) function using log4cxx library or not. It must to be called out of "#ifdef LOG4CXX" scope.
clarg::argInt naat("-naDALorat", "NUMA aware Dohrman Assembly List thread work objects re-allocation threshold.", 0)
void VisualMatrix(TPZFMatrix< TVar > &matrix, const std::string &outfilename)
This function calls the function that create a Data Explorer file or VTK file that allow to visualiz...
TPZAutoPointer< TPZDohrAssembly< STATE > > fDohrAssembly
void SetReduced()
changes the declared dimension of the matrix to fDim1
Definition: pzmatred.h:70
TPZAutoPointer< TPZCompMesh > fMesh
virtual TPZGeoEl * CreateGeoElement(MElementType type, TPZVec< int64_t > &cornerindexes, int matid, int64_t &index, int reftype=1)
Generic method for creating a geometric element. Putting this method centrally facilitates the modifi...
Definition: pzgmesh.cpp:1296
int64_t NodeIndex(int64_t nolocal, TPZCompMesh *super)
Gives the id node of one local node in containing mesh.
Definition: pzsubcmesh.cpp:358
TPZTimeTemp tempo
External variable to TPZTimeTemp (to take time)
Definition: TPZTimeTemp.cpp:11
Implements renumbering for elements of a mesh. Utility.
Definition: pzmetis.h:17
void SimetrizeMatRed()
If fK00 is simetric, only part of the matrix is accessible to external objects.
Definition: pzmatred.cpp:67
clarg::argInt nsub("-nsub", "number of substructs", 4)
int64_t NEquations()
This computes the number of equations associated with non-restrained nodes.
Definition: pzcmesh.cpp:721
int64_t NIndependentConnects()
Number of independent connect objects.
Definition: pzcmesh.cpp:1080
TPZAutoPointer< TPZDohrAssembly< TVar > > fAssembly
static void DecomposeInternal(TPZAutoPointer< TPZDohrSubstructCondense< STATE > > substruct, int numa_node)
TPZGeoElSide Reference() const
Reference to the geometric element.
Definition: pzcompel.cpp:748
TPZAutoPointer< TPZCompMesh > fMesh
virtual void Resequence(TPZVec< int64_t > &perm, TPZVec< int64_t > &iperm)
Definition: pzsloan.cpp:20
static TPZSubCompMesh * SubMesh(TPZAutoPointer< TPZCompMesh > compmesh, int isub)
return a pointer to the isub submesh
Implements assembling by Dohrman algorithm.
std::vector< work_item_t< TVar > > work_items
Defines step solvers class. Solver.
Definition: pzmganalysis.h:17
Contains the TPZRenumbering class which defines the behavior to implementing node sequence numbering ...
Calculate the Times. Utility.
Definition: TPZfTime.h:21
virtual TPZEquationFilter & EquationFilter()
access method for the equation filter
virtual int Resize(const int64_t newRows, const int64_t newCols)
Redimensions a matriz keeping the previous values.
Definition: pzmatrix.h:278
virtual int NCornerNodes() const =0
Returns the number of corner nodes of the element.
Contains the TPZDohrMatrix class which implements a matrix divided into substructures. Also contains the TPZDohrThreadMultData and TPZDohrThreadMultList structs.
void Subdivide(int nParts, TPZVec< int > &Domains)
Subdivides a Graph in nParts.
Definition: pzmetis.cpp:148
int64_t NElements() const
Number of elements of the mesh.
Definition: pzgmesh.h:129
TPZAutoPointer< TPZDohrSubstructCondense< TTVar > > fSubstruct
void IdentifyCornerNodes()
Identify cornernodes.
void SetNumCornerEqs(int nc)
Utility class which represents an element with its side. The Geometric approximation classes Geometry...
Definition: pzgeoelside.h:83
void AddSubstruct(TPZAutoPointer< TSubStruct > substruct)
It adds a substruct.
int64_t NElements() const
Access method to query the number of elements of the vector.
Implements a chunk vector with free store administration. Utility.
Definition: TPZStream.h:39
Contains TPZMatRed class which implements a simple substructuring of a linear system of equations...
void ComputeFillIn(int64_t resolution, TPZFMatrix< REAL > &fillin)
This method will fill the matrix passed as parameter with a representation of the fillin of the globa...
Definition: pzcmesh.cpp:1869
virtual int NSides() const =0
Returns the number of connectivities of the element.
Implements a matrix divided into substructures. Matrix Sub structure.
Definition: tpzdohrmatrix.h:30
virtual int64_t NodeIndex(int i) const =0
Returns the index of the ith node the index is the location of the node in the nodevector of the mesh...
pthread_mutex_t fAccessElement
Mutexes (to choose which submesh is next)
virtual int SideDimension(int side) const =0
Return the dimension of side.
virtual void BuildCornerConnectList(std::set< int64_t > &connectindexes) const
adds the connect indexes associated with base shape functions to the set
Definition: pzcmesh.cpp:2782
virtual void Resize(const int64_t newsize, const T &object)
Resizes the vector object.
Definition: pzmanvector.h:426
Contains the declaration of the VisualMatrix functions to VTK and DX packages.
Iterações do laço podem ser executadas em paralelo. .
TPZAutoPointer< TPZDohrAssembly< TVar > > fAssembly
std::set< int > fCornerEqs
The global equations defining the coarse matrix.
RunStatsTable dohr_dec("-tpz_dohr_dec", "Raw data table statistics for TPZDohrStructMatrix::Assemble decompose (second)")
void SetK00(TPZAutoPointer< TPZMatrix< TVar > > K00)
Sets the matrix pointer of the upper left matrix to K00.
Definition: pzmatred.cpp:134
void IdentifyEqNumbers(TPZSubCompMesh *sub, std::map< int, int > &global, std::map< int, int > &globinv)
void ComputeElGraph(TPZStack< int64_t > &elgraph, TPZVec< int64_t > &elgraphindex)
Computes the connectivity graph of the elements, as appropriate for the TPZRenumbering class...
Definition: pzcmesh.cpp:1091
Contains the TPZDohrStructMatrix class which implements structural matrix divided in sub structures...
void PermuteInternalFirst(TPZVec< int64_t > &permute)
Permutes the potentially internal connects to the first on the list Respect the previous order of th...
Contains the TPZFStructMatrix class which implements Full Structural Matrices.
std::list< TPZAutoPointer< TSubStruct > > & Global()
The matrix class is a placeholder for a list of substructures.
void SetSolver(TPZAutoPointer< TPZMatrixSolver< TVar > > solver)
Definition: pzmatred.cpp:125
Implements SkyLine Structural Matrices. Structural Matrix.
Refines geometrical mesh (all the elements) num times.
Definition: pzstrmatrix.h:35
TPZCompMesh * fMesh
Pointer to the computational mesh from which the matrix will be generated.
#define PZ_PTHREAD_JOIN(thread, val, fn)
Definition: pz_pthread.h:34
static TPZAutoPointer< TPZSavable > GetAutoPointer(const int64_t &objId)
Implements a matrix which computes the preconditioner developed by Dohrmann. Sub Structure.
clarg::argBool naa("-naDALora", "NUMA aware Dohrman Assembly List thread work objects re-allocation.", false)
int64_t size() const
Returns the number of elements of the vector.
Definition: pzvec.h:196
virtual void Resize(const int64_t newsize, const T &object)
Resizes the vector object reallocating the necessary storage, copying the existing objects to the new...
Definition: pzvec.h:373
Contains the TPZBoostGraph class which implements an interface to the BGL for graph operations...
void AssembleTBB(TPZMatrix< STATE > &mat, TPZFMatrix< STATE > &rhs, TPZAutoPointer< TPZGuiInterface > guiInterface)
void Write(TPZStream &str, int withclassid) const override
Writes this object to the TPZStream buffer. Include the classid if withclassid = true.
int64_t SequenceNumber() const
Returns the Sequence number of the connect object.
Definition: pzconnect.h:158
virtual TPZMatrix< STATE > * Create()
void Push(const T object)
Pushes a copy of the object on the stack.
Definition: pzstack.h:80
parallel_assemble_task_t(TPZAutoPointer< TPZDohrAssembly< TVar > > assembly, TPZAutoPointer< TPZCompMesh > mesh)
#define PZ_PTHREAD_MUTEX_LOCK(mutex, fn)
Definition: pz_pthread.h:76
virtual void Write(const bool val)
Definition: TPZStream.cpp:8
virtual void Print(std::ostream &out=std::cout) const
Print the information of the grid to an ostream.
Definition: pzgmesh.cpp:130
Defines the behaviour of all geometric elements. GeometryTPZGeoEl is the common denominator for all g...
Definition: pzgeoel.h:43
TPZAutoPointer< TPZMatrix< STATE > > fDohrPrecond
This abstract class which defines the behavior which derived classes need to implement for implement...
To condense matrix divided in sub structures. Sub Structure.
int64_t Index() const
Returns the index of the element within the element vector of the mesh.
Definition: pzgeoel.h:730
Implements a group of computational elements as a mesh and an element. Computational Mesh...
Definition: pzsubcmesh.h:36
#define DebugStop()
Returns a message to user put a breakpoint in.
Definition: pzerror.h:20
void CornerEqs(unsigned int mincorners, int64_t nelconsider, std::set< int > &eligible, std::set< int > &cornernodes)
Analyzes the graph, finds the corner nodes Number of elements which should be considered for determi...
int ClusterIslands(TPZVec< int > &domain_index, int nsub, int connectdimension)
Eliminates subdomains who are embedded in other subdomains.
Implements a matrix whose nonzero elements are stored in binary tree. Matrix.
Definition: pzfmatrix.h:33
#define LOGPZ_DEBUG(A, B)
Define log for debug info.
Definition: pzlog.h:87
static int64_t NSubMesh(TPZAutoPointer< TPZCompMesh > compmesh)
Return the number of submeshes.
Contains the TPZSkylineStructMatrix class which implements SkyLine Structural Matrices.
void Append(TPZAutoPointer< ThreadDohrmanAssembly< TVar > > object)
int Dimension() const
Returns the dimension of the simulation.
Definition: pzcmesh.h:148
virtual void ComputeNodElCon()
Compute the number of elements connected to each connect object.
Definition: pzcmesh.cpp:668
virtual void SetMatrix(TPZAutoPointer< TPZMatrix< TVar > > Refmat)
Sets a matrix to the current object.
Definition: pzsolve.h:115
virtual void Assemble(TPZMatrix< STATE > &mat, TPZFMatrix< STATE > &rhs, TPZAutoPointer< TPZGuiInterface > guiInterface, unsigned numthreads_assemble, unsigned numthreads_decompose) override
Assemble the global system of equations into the matrix which has already been created.
void parallel_for(int n, body_t &obj)
Definition: pzparallel.h:24
TPZAdmChunkVector< TPZGeoNode > & NodeVec()
Definition: pzgmesh.h:140
Contains the TPZDohrPrecond class which implements a matrix which computes the preconditioner develop...
TPZCompEl * Reference() const
Return a pointer to the element referenced by the geometric element.
Definition: pzgeoel.h:750
static void * ThreadWork(void *voidptr)
static void DecomposeBig(TPZAutoPointer< TPZDohrSubstructCondense< STATE > > substruct, int numa_node)
int HasDependency() const
Returns whether exist dependecy information.
Definition: pzconnect.h:292
virtual TPZMatrix< STATE > * Create() override
This will create a DohrMatrix.
Contains the TPZPairStructMatrix class.
const TPZBlock< STATE > & Block() const
Access the block structure of the solution vector.
Definition: pzcmesh.h:213
#define PZ_PTHREAD_MUTEX_DESTROY(mutex, fn)
Definition: pz_pthread.h:73
Contains the TPZDohrSubstructCondense class which condenses matrix divided in sub structures...
void IdentifyExternalConnectIndexes()
Identify the external connects.
double ReturnTimeDouble()
When called, returns the time since the creation of the object in a double.
Definition: TPZfTime.cpp:35
void SetNumThreads(int numthreads)
Definition: tpzdohrmatrix.h:79
TPZAdmChunkVector< TPZConnect > & ConnectVec()
Return a reference to the connect pointers vector.
Definition: pzcmesh.h:198
T * begin() const
Casting operator. Returns The fStore pointer.
Definition: pzvec.h:450
int64_t Index() const
Returns element index of the mesh fELementVec list.
Definition: pzcompel.h:821
virtual TPZGeoElSide Neighbour(int side)=0
Returns a pointer to the neighbour and the neighbourside along side of the current element...
Contains the TPZfTime class which calculates times.
Contains macros and functions to support performance analysis.
static void PrintGMeshVTK(TPZGeoMesh *gmesh, std::ofstream &file, bool matColor=true)
Default constructor for graphical mesh with VTK format.
int Redim(const int64_t newRows, const int64_t newCols) override
Redimension a matrix and ZERO your elements.
Definition: pzfmatrix.h:616
void Print(TPZVec< int64_t > &grapho, TPZVec< int64_t > &graphoindex, const char *name=0, std::ostream &out=std::cout)
Prints graph.
pthread_mutex_t fAccessElement
Mutexes (to choose which submesh is next)
virtual void Assemble(TPZMatrix< STATE > &mat, TPZFMatrix< STATE > &rhs, TPZAutoPointer< TPZGuiInterface > guiInterface) override
Assemble the global system of equations into the matrix which has already been created.
Definition: pzstrmatrix.cpp:80
virtual TPZConnect & Connect(int i) const
Returns a pointer to the ith node.
Definition: pzcompel.cpp:298
void ConnectedCompElementList(TPZStack< TPZCompElSide > &elsidevec, int onlyinterpolated, int removeduplicates)
Returns all connected computational elements to the current element if onlyinterpolated == 1 only e...
virtual int64_t ConnectIndex(int i) const =0
Returns the index of the ith connectivity of the element.
.. . Sub Structure
int NBlocks() const
Returns number of blocks on diagonal.
Definition: pzblock.h:165
virtual int NConnects() const =0
Returns the number of nodes of the element.
Implements Full Structural Matrices. Structural Matrix.
Definition: pzfstrmatrix.h:19
TPZGeoEl * Element() const
Definition: pzgeoelside.h:162
void ComputePermutationInternalFirst(TPZVec< int64_t > &permute) const
Computes the permutation vector which puts the internal connects to the first on the list Respect th...
TPZAutoPointer< ThreadDohrmanAssembly< TVar > > NextObject()
Returns an object and removes it from the list in a thread safe way.
void BuildConnectivity()
Build the connectivity of the grid.
Definition: pzgmesh.cpp:967
static void AssembleMatrices(TPZSubCompMesh *submesh, TPZAutoPointer< TPZDohrSubstructCondense< STATE > > substruct, TPZAutoPointer< TPZDohrAssembly< STATE > > dohrassembly, pthread_mutex_t *TestThread)
Contains declaration of TPZSubCompMesh class which implements a group of computational elements as a ...
T Pop()
Retrieve an object from the stack.
Definition: pzstack.h:87
virtual void CleanUpUnconnectedNodes()
Delete the nodes which have no elements connected to them.
Definition: pzcmesh.cpp:498
virtual int Dimension() const =0
Returns the dimension of the element.
TPZCompEl * Element() const
Gives a pointer to the reference computational element.
Definition: pzcompel.h:675
Implements a simple substructuring of a linear system of equations, composed of 4 submatrices...
Definition: pzmatred.h:34
TPZAutoPointer< TPZMatrix< TVar > > K00()
Definition: pzmatred.h:112
TPZGeoEl * Reference() const
Return a pointer to the corresponding geometric element if such exists, return 0 otherwise.
Definition: pzcompel.cpp:1137
const SubsList & SubStructures() const
Definition: tpzdohrmatrix.h:64
Contains the TPZMatRedStructMatrix class.
virtual int NSideConnects(int iside) const override=0
Returns the number of dof nodes along side iside.
This class implements a geometric mesh for the pz environment. Geometry.
Definition: pzgmesh.h:48
bool was_set() const
Definition: arglib.h:138
void push_work_item(unsigned submesh_idx, const TPZAutoPointer< TPZDohrSubstructCondense< TVar > > &substruct)
int Dimension() const
the dimension associated with the element/side
int64_t SideConnectIndex(int icon, int is) const
Returns the index of the c th connect object along side is.
Definition: pzintel.cpp:101
TPZManVector< int > fExternalConnectIndexes
The connect indexes which are external.
virtual void ComputeNodElCon() override
Computes the number of elements connected to each connect object.
Definition: pzsubcmesh.cpp:298
Implements computational mesh. Computational Mesh.
Definition: pzcmesh.h:47
pthread_mutex_t fTestThreads
mutex to debug the assembly process
int Size(const int block_diagonal) const
Returns block dimension.
Definition: pzblock.h:171
const T & get_value() const
Definition: arglib.h:177
TPZAutoPointer< TPZDohrSubstructCondense< TVar > > fSubstruct
TPZAdmChunkVector< TPZCompEl * > & ElementVec()
Returns a reference to the element pointers vector.
Definition: pzcmesh.h:183
#define PZ_PTHREAD_CREATE(thread, attr, routine, args, fn)
Definition: pz_pthread.h:31
REAL ft1comput
Time for Computing the system of equations for each substructure.
Definition: TPZTimeTemp.h:44
Contains declaration of TPZInterpolatedElement class which implements computational element of the in...
int64_t NumInternalEquations()
Computes the number of internal equations.
void Fill(const T &copy, const int64_t from=0, const int64_t numelem=-1)
Will fill the elements of the vector with a copy object.
Definition: pzvec.h:460
Contains TPZVerySparseMatrix class which implements a matrix whose nonzero elements are stored in bin...
void OpenWrite(const std::string &fileName)
Defines the interface for saving and reading data. Persistency.
Definition: TPZStream.h:50
int64_t NElements() const
Returns the number of elements of the vector.
Definition: pzvec.h:190
void Initialize()
Initialize the necessary datastructures.
int SeparateUnconnected(TPZVec< int > &domain_index, int nsub, int connectdimension)
Verifies if the subdomains are connected by sides of connectdimension and separate them if not...
Contains the TPZSloan class.
work_item_t(unsigned submesh_idx, const TPZAutoPointer< TPZDohrSubstructCondense< TTVar > > &substruct)
void SetDirect(const DecomposeType decomp)
void InitializeBlock()
Resequence the block object, remove unconnected connect objects and reset the dimension of the soluti...
Definition: pzcmesh.cpp:391
#define PZ_PTHREAD_MUTEX_INIT(mutex, attr, fn)
Definition: pz_pthread.h:70
ThreadDohrmanAssemblyList< T > * list
virtual TPZMatrix< STATE > * CreateAssemble(TPZFMatrix< STATE > &rhs, TPZAutoPointer< TPZGuiInterface > guiInterface, unsigned numthreads_assemble, unsigned numthreads_decompose) override
This will create a DohrMatrix and compute its matrices.
std::list< TPZAutoPointer< ThreadDohrmanAssembly< TVar > > > fList
void Initialize()
Initialize the necessary datastructures.
void ReallocForNuma(int node)
Contains the TPZNodesetCompute class which computes the cardinality of a nodegraph.
Defines the interface of a computational element. Computational Element.
Definition: pzcompel.h:59
Contains the TPZVTKGeoMesh class which implements the graphical mesh to VTK environment to geometric ...
bool IsCondensed() const
Access method to return the indication whether the connect is condensed or not.
Definition: pzconnect.h:223
Interface to sloan subrotines. Utility.
Definition: pzsloan.h:21
RunStatsTable dohr_ass("-tpz_dohr_ass", "Raw data table statistics for TPZDohrStructMatrix::Assemble assemble (first)")
Assemble the global system of equations into the matrix which has already been created.
T * end() const
Returns a pointer to the last+1 element.
Definition: pzvec.h:455
void Read(TPZStream &str, void *context) override
read objects from the stream
static void WritePointer(const TPZSavable *obj, TPZStream *stream)
TPZAutoPointer< TPZCompMesh > fCompMesh
Autopointer control of the computational mesh.
Contains TPZMetis class which implements the renumbering for elements of a mesh to minimize the band...
Contains the TPZRefPatternTools class which defines tools of pattern.
Implements computational element based on an interpolation space. Computational Element.
Definition: pzintel.h:27
void SubStructure(int nsub)
Partition the mesh in submeshes.
void Reset()
Reset method.
int Resequence(const int start=0)
Resequences blocks positioning.
Definition: pzblock.cpp:150
virtual void Read(bool &val)
Definition: TPZStream.cpp:91
Implements structural matrix divided in sub structures. Structural Matrix Sub structure.
void Permute(TPZVec< int64_t > &permute)
Permute the sequence number of the connect objects It is a permute gather operation.
Definition: pzcmesh.cpp:1321