NeoPZ
tpznodesetcompute.cpp
Go to the documentation of this file.
1 
5 //
6 // C++ Implementation: tpznodesetcompute
7 //
8 // Description:
9 //
10 //
11 // Author: Philippe R. B. Devloo <phil@fec.unicamp.br>, (C) 2004
12 //
13 // Copyright: See COPYING file that comes with this distribution
14 //
15 //
16 #include "tpznodesetcompute.h"
17 #include "pzstack.h"
18 #include "pzblock.h"
19 #include <set>
20 #include <map>
21 #include <algorithm>
22 #include <iterator>
23 #include <fstream>
24 #include "pzlog.h"
25 
26 #ifdef LOG4CXX
27 static LoggerPtr logger(Logger::getLogger("pz.mesh.nodesetcompute"));
28 #endif
29 
30 //static std::ofstream out("nodeset.txt");
31 
33 {
34  fMaxSeqNum = -1;
35  fMaxLevel = -1;
36 }
37 
38 
40 {
41 }
42 
43 
48 {
49  fMaxSeqNum = -1;
50  fMaxLevel = -1;
51  int64_t nnodes = fNodegraphindex.NElements()-1;
52  fSeqNumber.Resize(nnodes);
53  this->fLevel.Resize(nnodes);
54  fSeqNumber.Fill(-1);
55  fIsIncluded.Resize(nnodes);
56  fIsIncluded.Fill(0);
57  fLevel.Fill(0);
58  TPZVec<std::set<int64_t> > nodeset(nnodes);
59  int64_t in;
60  for(in=0; in<nnodes; in++)
61  {
62  if(!(in%1000))
63  {
64  std::cout << "*";
65  std::cout.flush();
66  }
67  AnalyseNode(in,nodeset);
68  }
69  std::cout << std::endl;
70 
71 }
72 
77 void TPZNodesetCompute::AnalyseNode(int64_t node, TPZVec< std::set<int64_t> > &nodeset)
78 {
79  if(fSeqNumber[node] != -1) return;
80  if(! nodeset[node].size())
81  {
82  nodeset[node].insert(&fNodegraph[fNodegraphindex[node]],&fNodegraph[fNodegraphindex[node+1]]);
83  nodeset[node].insert(node);
84  }
85  int minlevel = 0;
86  std::set<int64_t>::iterator it;
87  TPZStack<int64_t> equalnodes;
88  for(it = nodeset[node].begin(); it != nodeset[node].end(); it++)
89  {
90  int64_t othernode = *it;
91  if(othernode == node) continue;
92  // build the data structure of the connected node
93  if(! nodeset[othernode].size())
94  {
95  nodeset[othernode].insert(&fNodegraph[fNodegraphindex[othernode]],&fNodegraph[fNodegraphindex[othernode+1]]);
96  nodeset[othernode].insert(othernode);
97  }
98  // the other node is included in my connectivity
99  bool inc = includes(nodeset[node].begin(),nodeset[node].end(),nodeset[othernode].begin(),nodeset[othernode].end());
100  // the other node has a different connectivity
101  bool diff = nodeset[node] != nodeset[othernode];
102  if( inc && diff)
103  {
104  // Analyse the connectivity graph of the other node
105  // Its graph is smaller than mine
106  fIsIncluded[othernode] = 1;
107  AnalyseNode(othernode,nodeset);
108  minlevel = minlevel < fLevel[othernode]+1 ? fLevel[othernode]+1 : minlevel;
109 #ifdef LOG4CXX
110  if(fLevel[othernode] >= 0)
111  {
112  std::stringstream sout;
113  sout << "The level of " << node << " is increased because of " << othernode << " ";
114  sout << "Level of othernode " << fLevel[othernode] << " Seqnumber othernode " << fSeqNumber[othernode];
115  LOGPZ_DEBUG(logger,sout.str())
116  }
117 #endif
118  }
119  else if(!diff)
120  {
121  // The graphs are equal. These nodes should be grouped
122  if(fIsIncluded[node])
123  {
124  fIsIncluded[othernode] = 1;
125  }
126  equalnodes.Push(othernode);
127  }
128  // the other node has been analysed (and is probably not equal...)
129  if(inc && diff && fSeqNumber[othernode] != -1)
130  {
131  fIsIncluded[othernode] = 1;
132  minlevel = minlevel < fLevel[othernode]+1 ? fLevel[othernode]+1 : minlevel;
133  } else if(!diff && fSeqNumber[othernode] != -1)
134  {
135  // the level should be at least the level of the other node
136  minlevel = minlevel < fLevel[othernode] ? fLevel[othernode] : minlevel;
137  // should not happen because if the nodes are equal, they both have the same sequence number
138  DebugStop();
139  }
140  }
141  // assign a sequence number to the node
142  fMaxSeqNum++;
143  fSeqNumber[node] = fMaxSeqNum;
144 #ifdef LOG4CXX
145  {
146  std::stringstream sout;
147  sout << "Assigning Seq Number " << fMaxSeqNum << " and level " << minlevel << " to nodes " << node << " " << equalnodes;
148  LOGPZ_DEBUG(logger,sout.str())
149  }
150 #endif
151  fSeqCard.Push(1);
152  // the maximum level of the set of nodes
153  fMaxLevel = fMaxLevel < minlevel ? minlevel : fMaxLevel;
154  // assign the level of the node
155  fLevel[node] = minlevel;
156  nodeset[node].erase(node);
157 
158  // memory clean up
159  for(it = nodeset[node].begin(); it != nodeset[node].end(); it++)
160  {
161  int64_t othernode = *it;
162  int level = fLevel[othernode];
163  int64_t seq = fSeqNumber[othernode];
164  if(seq != -1 && level <= minlevel)
165  {
166  nodeset[othernode].clear();
167  if(othernode == node)
168  {
169  LOGPZ_ERROR(logger," othernode equal to node!!")
170  DebugStop();
171  break;
172  }
173  }
174  }
175  nodeset[node].clear();
176  // initialize the datastructure of the nodes which have the same connectivity
177  int64_t neq = equalnodes.NElements();
178  int64_t ieq;
179  for(ieq=0; ieq<neq; ieq++)
180  {
181  fSeqNumber[equalnodes[ieq]] = fMaxSeqNum;
182  fLevel[equalnodes[ieq]] = minlevel;
183  // I think this is overkill : this nodeset should already be empty...
184  nodeset[equalnodes[ieq]].clear();
185  // the number of nodes associated with this sequence number
186  fSeqCard[fMaxSeqNum]++;
187  }
188 }
189 
191 {
192  int64_t nnodes = fSeqNumber.NElements();
193  blockgraphindex.Resize(fSeqCard.NElements()+1);
194  blockgraph.Resize(nnodes);
195  int64_t seq = 0;
196  blockgraphindex[0] = 0;
197  blockgraphindex[1] = 0;
198  for(seq=2; seq<=fSeqCard.NElements(); seq++)
199  {
200  blockgraphindex[seq] = blockgraphindex[seq-1]+fSeqCard[seq-2];
201  }
202  int64_t in;
203  for(in = 0; in< nnodes; in++)
204  {
205  int64_t seqn = fSeqNumber[in];
206  blockgraph[blockgraphindex[seqn+1]] = in;
207  blockgraphindex[seqn+1]++;
208  }
209 }
210 
212 {
213  std::map<int64_t,int64_t> vertices;
214  int64_t nnodes = fSeqNumber.NElements();
215  int64_t in;
216  for(in=0; in<nnodes; in++)
217  {
218  if(fLevel[in] == this->fMaxLevel) vertices[fSeqNumber[in]] = in;
219  }
220  int64_t nvert = vertices.size();
221  blockgraphindex.Resize(nvert+1);
222  blockgraphindex[0] = 0;
223  int iv = 1;
224  std::map<int64_t,int64_t>::iterator it;
225  for(it=vertices.begin(); it != vertices.end(); it++)
226  {
227  int node = (*it).second;
228  blockgraph.Push(node);
229  std::set<int64_t> vertexset;
230  std::set<int> included;
231  std::set<int> notincluded;
232  // The set will contain the connectivity of the node
233  BuildNodeSet(node,vertexset);
234  included.insert((*it).first);
235  std::set<int64_t>::iterator versetit;
236  for(versetit = vertexset.begin(); versetit != vertexset.end(); versetit++)
237  {
238  int64_t linkednode = *versetit;
239  if(linkednode == node) continue;
240  int64_t seq = fSeqNumber[linkednode];
241 
242  // if the sequence number of the equation is already included in the nodeset of the vertex, put it in the blockgraph
243  // this node has equal connectivity with other node
244  if(included.count(seq))
245  {
246  blockgraph.Push(linkednode);
247  }
248  // if the seq number is recognized as not to be included stop analysing
249  // this node has equal connectivity with other node
250  else if(notincluded.count(seq))
251  {
252  continue;
253  }
254  // the equation hasn t been analysed yet
255  else
256  {
257  std::set<int64_t> locset;
258  BuildNodeSet(linkednode,locset);
259  // if its nodeset is included in the vertexset
260  if(includes(vertexset.begin(),vertexset.end(),locset.begin(),locset.end()))
261  {
262  included.insert(seq);
263  blockgraph.Push(linkednode);
264  }
265  // else this sequence number should not be analysed anymore
266  else
267  {
268  notincluded.insert(seq);
269  }
270  }
271  }
272  blockgraphindex[iv] = blockgraph.NElements();
273  iv++;
274  }
275 }
276 
277 void TPZNodesetCompute::BuildNodeSet(int64_t node, std::set<int64_t> &nodeset)
278 {
279  nodeset.clear();
280  nodeset.insert(&fNodegraph[fNodegraphindex[node]],&fNodegraph[fNodegraphindex[node+1]]);
281  nodeset.insert(node);
282 }
283 
288 void TPZNodesetCompute::AnalyseForElements(std::set<int64_t> &vertices, std::set< std::set<int64_t> > &elements)
289 {
290 
291  if(!vertices.size()) return;
292  std::set<int64_t> elem;
293  std::set<int64_t>::iterator intit,diffit;
294  {
295  std::stringstream sout;
296  sout << __PRETTY_FUNCTION__ << " Original set of nodes ";
297  Print(sout,vertices,0);
298  LOGPZ_DEBUG(logger,sout.str())
299  }
300  for(intit = vertices.begin(); intit != vertices.end(); intit++)
301  {
302  std::set<int64_t> locset,diffset,interset,unionset,loclocset;
303  // locset = all nodes connected to a vertex
304  BuildNodeSet(*intit,locset);
305  // only diffset with nodes which have no connection with lower nodes interest us
306  if(*locset.begin() < *vertices.begin()) continue;
307  // diffset contains all vertices in the mesh, except for those in the influence zone of intit????
308  set_difference(vertices.begin(),vertices.end(),locset.begin(),locset.end(),inserter(diffset,diffset.begin()));
309  // the influence zone of the vertex includes other vertices
310  if(diffset.size())
311  {
312 #ifdef LOG4CXX
313  {
314  std::stringstream sout;
315  sout << "Difference after taking the intersection with " << *intit;
316  Print(sout,diffset," Difference set");
317  LOGPZ_DEBUG(logger,sout.str())
318  }
319 #endif
320  // some unions need to be made before calling this method
321  for(diffit=diffset.begin(); diffit!= diffset.end(); diffit++)
322  {
323 
324  loclocset.clear();
325  // locset now will contain the influence zone of each vertex node in diffset
326  BuildNodeSet(*diffit,loclocset);
327  if(*loclocset.begin() < *vertices.begin()) continue;
328  unionset.insert(loclocset.begin(),loclocset.end());
329  }
330  // locset now contains the union of all influence zones of vertices influenced by intit
331  diffset.clear();
332  // diffset will now contain only vertex nodes
333  set_intersection(unionset.begin(),unionset.end(),vertices.begin(),vertices.end(),inserter(diffset,diffset.begin()));
334 #ifdef LOG4CXX
335  {
336  std::stringstream sout;
337  Print(sout,diffset,"First set to be reanalised");
338  LOGPZ_DEBUG(logger,sout.str())
339  }
340 #endif
341  set_intersection(vertices.begin(),vertices.end(),locset.begin(),locset.end(),inserter(interset,interset.begin()));
342 #ifdef LOG4CXX
343  {
344  std::stringstream sout;
345  Print(sout,interset,"Second set to be reanalised");
346  LOGPZ_DEBUG(logger,sout.str())
347  }
348 #endif
349  AnalyseForElements(diffset,elements);
350  AnalyseForElements(interset,elements);
351  return;
352  }
353  }
354 
355  intit = vertices.begin();
356  BuildNodeSet(*intit,elem);
357  intit++;
358 // elem = vertices;
359  // this code doesnt make sense!!!
360  for(;intit != vertices.end(); intit++)
361  {
362  std::set<int64_t> locset,interset;
363  BuildNodeSet(*intit,locset);
364  set_intersection(elem.begin(),elem.end(),locset.begin(),locset.end(),inserter(interset,interset.begin()));
365  elem = interset;
366  }
367  if(vertices != elem)
368  {
369 #ifdef LOG4CXX
370  {
371  std::stringstream sout;
372  sout << "Discarding a vertex set as incomplete";
373  Print(sout,vertices,0);
374  LOGPZ_DEBUG(logger,sout.str())
375  }
376 #endif
377  }
378  else if(elem.size())
379  {
380 #ifdef LOG4CXX
381  {
382  std::stringstream sout;
383  Print(sout,elem,"Inserted element");
384  LOGPZ_DEBUG(logger,sout.str())
385  }
386 #endif
387  elements.insert(elem);
388  }
389 }
390 
392 {
393 #ifdef LOG4CXX
394  {
395  std::stringstream sout;
396  sout << __PRETTY_FUNCTION__ << " entering build element graph\n";
397  LOGPZ_DEBUG(logger,sout.str())
398  }
399 #endif
400  blockgraph.Resize(0);
401  blockgraphindex.Resize(1);
402  blockgraphindex[0] = 0;
403  int64_t in;
404  int64_t nnodes = this->fNodegraphindex.NElements()-1;
405  std::set<int64_t> nodeset;
406  for(in=0; in<nnodes; in++)
407  {
408  std::set< std::set<int64_t> > elements;
409  BuildNodeSet(in,nodeset);
410 #ifdef LOG4CXX
411  {
412  std::stringstream sout;
413  sout << "Nodeset for " << in << ' ';
414  Print(sout,nodeset,"Nodeset");
415  LOGPZ_DEBUG(logger,sout.str())
416  }
417 #endif
418  SubstractLowerNodes(in,nodeset);
419 #ifdef LOG4CXX
420  {
421  std::stringstream sout;
422  Print(sout,nodeset,"LowerNodes result");
423  LOGPZ_DEBUG(logger,sout.str())
424  }
425 #endif
426  AnalyseForElements(nodeset,elements);
427  std::set< std::set<int64_t> >::iterator itel;
428  for(itel = elements.begin(); itel != elements.end(); itel++)
429  {
430  std::set<int64_t>::const_iterator it;
431  for(it = (*itel).begin(); it!= (*itel).end(); it++)
432  {
433  blockgraph.Push(*it);
434  }
435  blockgraphindex.Push(blockgraph.NElements());
436  }
437  }
438 }
439 
440 void TPZNodesetCompute::SubstractLowerNodes(int64_t node, std::set<int64_t> &nodeset)
441 {
442  std::set<int64_t> lownode,lownodeset,unionset;
443  std::set<int64_t>::iterator it;
444 #ifdef LOG4CXX
445  {
446  std::stringstream sout;
447  sout << __PRETTY_FUNCTION__;
448  Print(sout,nodeset," Incoming nodeset");
449  LOGPZ_DEBUG(logger,sout.str())
450  }
451 #endif
452  for(it=nodeset.begin(); it != nodeset.end() && *it < node; it++)
453  {
454  BuildNodeSet(*it,lownodeset);
455  unionset.insert(lownodeset.begin(),lownodeset.end());
456  lownodeset.clear();
457  }
458  set_difference(nodeset.begin(),nodeset.end(),unionset.begin(),unionset.end(),
459  inserter(lownode,lownode.begin()));
460 #ifdef LOG4CXX
461  {
462  std::stringstream sout;
463  Print(sout,lownode," What is left after substracting the influence of lower numbered nodes ");
464  LOGPZ_DEBUG(logger,sout.str())
465  }
466 #endif
467  unionset.clear();
468  for(it=lownode.begin(); it!=lownode.end(); it++)
469  {
470  BuildNodeSet(*it,lownodeset);
471  unionset.insert(lownodeset.begin(),lownodeset.end());
472  lownodeset.clear();
473  }
474  lownode.clear();
475  set_intersection(unionset.begin(),unionset.end(),nodeset.begin(),nodeset.end(),
476  inserter(lownode,lownode.begin()));
477 #ifdef LOG4CXX
478  {
479  std::stringstream sout;
480  Print(sout,lownode," Resulting lower nodeset");
481  LOGPZ_DEBUG(logger,sout.str())
482  }
483 #endif
484  nodeset = lownode;
485 }
486 
487 void TPZNodesetCompute::Print(std::ostream &file) const
488 {
489  file << "TPZNodesetCompute\n";
490  file << "Node graph\n";
492  file << "Node sequence number and level\n";
493  int64_t nnode = fNodegraphindex.NElements()-1;
494  int64_t in;
495  for(in=0; in<nnode; in++) file << in << "/" << fSeqNumber[in] << "/" << fLevel[in] << " ";
496  file << std::endl;
497 }
498 
499 void TPZNodesetCompute::Print(std::ostream &file, const TPZVec<int64_t> &graphindex, const TPZVec<int64_t> &graph)
500 {
501  int64_t nnode = graphindex.NElements()-1;
502  int64_t in;
503  for(in =0; in<nnode; in++)
504  {
505  file << "Node Number " << in;
506  int64_t first = graphindex[in];
507  int64_t last = graphindex[in+1];
508  int64_t jn;
509  for(jn = first; jn< last; jn++) file << " " << graph[jn];
510  file << std::endl;
511  }
512 }
513 
514 void TPZNodesetCompute::Print(std::ostream &file, const std::set<int64_t> &nodeset, const char *text)
515 {
516  if(text) file << text;
517  std::set<int64_t>::const_iterator it;
518  for(it=nodeset.begin(); it!=nodeset.end(); it++) file << *it << ' ';
519  file << std::endl;
520 }
521 
526  TPZVec<int64_t> &expgraph, TPZVec<int64_t> &expgraphindex)
527 {
528  int64_t expgraphsize = 0;
529  int64_t nbl = graph.NElements();
530  expgraphindex.Resize(graphindex.NElements());
531  int64_t ibl;
532  for(ibl=0; ibl<nbl; ibl++)
533  {
534  expgraphsize += block.Size(graph[ibl]);
535  }
536  expgraph.Resize(expgraphsize);
537  int64_t counter = 0;
538  int64_t numblocks = graphindex.NElements()-1;
539  expgraphindex[0] = counter;
540  int64_t blcounter = 0;
541  for(ibl=0; ibl < numblocks; ibl++)
542  {
543  int64_t first = graphindex[ibl];
544  int64_t last = graphindex[ibl+1];
545  int64_t ieq;
546  for(ieq = first; ieq<last; ieq++)
547  {
548  int64_t blsize = block.Size(graph[ieq]);
549  int64_t pos = block.Position(graph[ieq]);
550  int64_t b;
551  for(b=0; b<blsize; b++)
552  {
553  expgraph[counter++] = pos+b;
554  }
555  }
556  if(expgraphindex[blcounter] != counter) expgraphindex[++blcounter] = counter;
557  }
558  expgraphindex.Resize(blcounter+1);
559 }
560 
564 int TPZNodesetCompute::ColorGraph(TPZVec<int64_t> &graph, TPZVec<int64_t> &graphindex, int64_t neq,
565  TPZVec<int> &colors)
566 {
567  TPZVec<int> eqcolor(neq);
568  int color = 0;
569  bool hasuncolored = true;
570  int64_t nblocks = graphindex.NElements()-1;
571  colors.Resize(nblocks);
572  colors.Fill(-1);
573  while(hasuncolored)
574  {
575  hasuncolored = false;
576  eqcolor.Fill(-1);
577  int64_t ibl;
578  for(ibl=0; ibl<nblocks; ibl++)
579  {
580  if(colors[ibl] != -1) continue;
581  int64_t first = graphindex[ibl];
582  int64_t last = graphindex[ibl+1];
583  int64_t ieq;
584  for(ieq=first; ieq<last; ieq++)
585  {
586  if(eqcolor[graph[ieq]] == color) break;
587  }
588  if(ieq != last)
589  {
590  hasuncolored = true;
591  }
592  else
593  {
594  colors[ibl] = color;
595  for(ieq=first; ieq<last; ieq++)
596  {
597  eqcolor[graph[ieq]] = color;
598  }
599  }
600  }
601  color++;
602  }
603  return color;
604 }
void AnalyseNode(int64_t node, TPZVec< std::set< int64_t > > &nodeset)
This method will analyse the set inclusion of the current node, calling the method recursively if an...
void AnalyseGraph()
Group the node graph as passed by the parameters.
int Position(const int block_diagonal) const
Returns the position of first element block dependent on matrix diagonal.
Definition: pzblock.h:177
void Print(std::ostream &file) const
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.
TPZManVector< int64_t > fNodegraphindex
This class implements a simple vector storage scheme for a templated class T. Utility.
Definition: pzgeopoint.h:19
static int ColorGraph(TPZVec< int64_t > &graph, TPZVec< int64_t > &graphindex, int64_t neq, TPZVec< int > &colors)
Color the graph into mutually independent blocks.
TPZVec< int > fLevel
Inclusion relation ship between nodes.
virtual void Resize(const int64_t newsize, const T &object)
Resizes the vector object.
Definition: pzmanvector.h:426
void BuildNodeGraph(TPZVec< int64_t > &blockgraph, TPZVec< int64_t > &blockgraphindex)
Build the graph which groups the equations of each node.
void BuildNodeSet(int64_t node, std::set< int64_t > &nodeset)
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
TPZStack< int64_t > fSeqCard
Number of nodes associated with each sequence number.
TPZManVector< int64_t > fNodegraph
The node graph as passed on by the finite element mesh His node graph is organized by sequence numbe...
void Push(const T object)
Pushes a copy of the object on the stack.
Definition: pzstack.h:80
#define DebugStop()
Returns a message to user put a breakpoint in.
Definition: pzerror.h:20
#define LOGPZ_DEBUG(A, B)
Define log for debug info.
Definition: pzlog.h:87
virtual void clear()
Empty the vector, make its size zero.
Definition: pzvec.h:444
#define LOGPZ_ERROR(A, B)
Define log for errors (cout)
Definition: pzlog.h:93
void BuildVertexGraph(TPZStack< int64_t > &blockgraph, TPZVec< int64_t > &blockgraphindex)
build the graph which builds the equations linked to vertices
A simple stack.
int64_t fMaxSeqNum
Counter for the condensed node graph.
TPZVec< int64_t > fSeqNumber
Sequence number associated with each node after condensing.
void BuildElementGraph(TPZStack< int64_t > &blockgraph, TPZStack< int64_t > &blockgraphindex)
Build the graph which groups the equations grouped by elements.
TPZVec< int > fIsIncluded
Vector indicating whether a node connectivity is included in another one.
void AnalyseForElements(std::set< int64_t > &vertices, std::set< std::set< int64_t > > &elements)
Look for elements formed by vertices, intersecting with the intersectvertices, one by one...
void SubstractLowerNodes(int64_t node, std::set< int64_t > &nodeset)
working a set of vertex nodes with nodes which have to be intersected (tested)
static void ExpandGraph(TPZVec< int64_t > &graph, TPZVec< int64_t > &graphindex, TPZBlock< STATE > &block, TPZVec< int64_t > &expgraph, TPZVec< int64_t > &expgraphindex)
Expand the graph acording to the block structure.
int Size(const int block_diagonal) const
Returns block dimension.
Definition: pzblock.h:171
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
int64_t NElements() const
Returns the number of elements of the vector.
Definition: pzvec.h:190
Contains the TPZNodesetCompute class which computes the cardinality of a nodegraph.