Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ProcessIsoContour.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ProcessIsoContour.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Generate isocontours from field data.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 #include <string>
36 #include <iostream>
37 using namespace std;
38 
39 #include "ProcessIsoContour.h"
40 
44 #include <boost/math/special_functions/fpclassify.hpp>
45 
46 namespace Nektar
47 {
48 namespace Utilities
49 {
50 
51 ModuleKey ProcessIsoContour::className =
53  ModuleKey(eProcessModule, "isocontour"),
54  ProcessIsoContour::create,
55  "Extract an isocontour of fieldid variable and at "
56  "value fieldvalue, Optionally fieldstr can be "
57  "specified for a string defiition or smooth for "
58  "smoothing");
59 
60 ProcessIsoContour::ProcessIsoContour(FieldSharedPtr f) :
62 {
63 
64  m_config["fieldstr"] = ConfigOption(false, "NotSet",
65  "string of isocontour to be extracted");
66  m_config["fieldname"] = ConfigOption(false, "isocon",
67  "name for isocontour if fieldstr "
68  "specified, default is isocon");
69 
70  m_config["fieldid"] = ConfigOption(false, "NotSet",
71  "field id to extract");
72 
73  m_config["fieldvalue"] = ConfigOption(false, "NotSet",
74  "field value to extract");
75 
76  m_config["globalcondense"] = ConfigOption(true, "NotSet",
77  "Globally condense contour to unique "
78  "values");
79 
80  m_config["smooth"] = ConfigOption(true, "NotSet",
81  "Smooth isocontour (might require "
82  "globalcondense)");
83 
84  m_config["smoothiter"] = ConfigOption(false, "100",
85  "Number of smoothing cycle, default = "
86  "100");
87 
88  m_config["smoothposdiffusion"] = ConfigOption(false,"0.5",
89  "Postive diffusion coefficient "
90  "(0 < lambda < 1), default = 0.5");
91 
92  m_config["smoothnegdiffusion"] = ConfigOption(false,"0.495",
93  "Negative diffusion coefficient "
94  "(0 < mu < 1), default = 0.495");
95 
96  m_config["removesmallcontour"] = ConfigOption(false,"0",
97  "Remove contours with less than specified number of triangles."
98  "Only valid with GlobalCondense or Smooth options.");
99 
100 
101 }
102 
104 {
105 }
106 
107 void ProcessIsoContour::Process(po::variables_map &vm)
108 {
109  int rank = m_f->m_comm->GetRank();
110 
111  if(m_f->m_verbose)
112  {
113  if(rank == 0)
114  {
115  cout << "ProcessIsoContour: Extracting contours..." << endl;
116  }
117  }
118 
119  vector<IsoSharedPtr> iso;
120 
121  if(m_f->m_fieldPts.get()) // assume we have read .dat file to directly input dat file.
122  {
124  }
125  else // extract isocontour from field
126  {
127  if(m_f->m_exp.size() == 0)
128  {
129  return;
130  }
131 
132  // extract all fields to equi-spaced
134 
135  int fieldid;
136  NekDouble value;
137 
138  if(m_config["fieldstr"].m_beenSet) //generate field of interest
139  {
140  fieldid = m_f->m_fieldPts->GetNFields();
141 
142  Array<OneD, NekDouble> pts(m_f->m_fieldPts->GetNpoints());
143 
144  // evaluate new function
146  string varstr = "x y z";
147  vector<Array<OneD, const NekDouble> > interpfields;
148 
149  for(int i = 0; i < m_f->m_fieldPts->GetDim(); ++i)
150  {
151  interpfields.push_back(m_f->m_fieldPts->GetPts(i));
152  }
153  for(int i = 0; i < m_f->m_fieldPts->GetNFields(); ++i)
154  {
155  varstr += " " + m_f->m_fieldPts->GetFieldName(i);
156  interpfields.push_back(m_f->m_fieldPts->GetPts(i+3));
157  }
158 
159  int ExprId = -1;
160  std::string str = m_config["fieldstr"].as<string>();
161  ExprId = strEval.DefineFunction(varstr.c_str(), str);
162 
163  strEval.Evaluate(ExprId, interpfields, pts);
164 
165  // set up field name if provided otherwise called "isocon" from default
166  string fieldName = m_config["fieldname"].as<string>();
167 
168  m_f->m_fieldPts->AddField(pts, fieldName);
169  }
170  else
171  {
172  ASSERTL0(m_config["fieldid"].as<string>() != "NotSet", "fieldid must be specified");
173  fieldid = m_config["fieldid"].as<int>();
174  }
175 
176  ASSERTL0(m_config["fieldvalue"].as<string>() != "NotSet", "fieldvalue must be specified");
177  value = m_config["fieldvalue"].as<NekDouble>();
178 
179  iso = ExtractContour(fieldid,value);
180 
181  }
182 
183  // Process isocontour
184  bool smoothing = m_config["smooth"].m_beenSet;
185  bool globalcondense = m_config["globalcondense"].m_beenSet;
186  if(globalcondense)
187  {
188  int nfields = m_f->m_fieldPts->GetNFields() + m_f->m_fieldPts->GetDim();
190 
191  g_iso->globalcondense(iso,m_f->m_verbose);
192 
193 
194  iso.clear();
195  iso.push_back(g_iso);
196  }
197 
198  if(smoothing)
199  {
200  int niter = m_config["smoothiter"].as<int>();
201  NekDouble lambda = m_config["smoothposdiffusion"].as<NekDouble>();
202  NekDouble mu = m_config["smoothnegdiffusion"].as<NekDouble>();
203  for(int i =0 ; i < iso.size(); ++i)
204  {
205  iso[i]->smooth(niter,lambda,-mu);
206  }
207  }
208 
209  int mincontour = 0;
210  if((mincontour = m_config["removesmallcontour"].as<int>()))
211  {
212  vector<IsoSharedPtr> new_iso;
213 
214  if(rank == 0)
215  {
216  cout << "Identifying separate regions [." << flush ;
217  }
218  for(int i =0 ; i < iso.size(); ++i)
219  {
220  iso[i]->separate_regions(new_iso,mincontour,m_f->m_verbose);
221  }
222 
223  if(rank == 0)
224  {
225  cout << "]" << endl << flush ;
226  }
227 
228  // reset iso to new_iso;
229  iso = new_iso;
230  }
231 
232  ResetFieldPts(iso);
233 }
234 
235 
236 /*********************/
237 /* Function TwoPairs */
238 /*********************/
239 
243  int &pr)
244 /* The logic of the following SWITCH statement may only be
245  understood with a "peusdo truth-table" */
246 {
247  if (((cx[0]-cx[1])==0.0)&&
248  ((cy[0]-cy[1])==0.0)&&
249  ((cz[0]-cz[1])==0.0))
250  {
251  if (((cx[2]-cx[3])==0.0)&&
252  ((cy[2]-cy[3])==0.0)&&
253  ((cz[2]-cz[3])==0.0))
254  {
255  pr=4;
256  }
257  else
258  {
259  pr=3;
260  }
261  }
262  else
263  {
264  pr=1;
265  }
266 }
267 
268 
269 /*************************/
270 /* Function ThreeSimilar */
271 /*************************/
272 void ThreeSimilar (const int i, const int j, const int k,
273  int &pr, int &ps)
274 /* The logic of the following SWITCH statement may be
275  understood with a "peusdo truth-table" */
276 {
277  switch (i + j + k)
278  {
279  case (3):
280  pr = 3;
281  ps = 4;
282  break;
283  case (4):
284  pr = 2;
285  ps = 4;
286  break;
287  case (5):
288  if (j == 1)
289  {
290  pr = 2;
291  ps = 3;
292  }
293  else
294  {
295  pr = 1;
296  ps = 4;
297  }
298  break;
299  case (6):
300  if (i == 0)
301  {
302  pr = 1;
303  ps = 3;
304  }
305  else
306  {
307  pr = 0;
308  ps = 4;
309  }
310  break;
311  case (7):
312  if (i == 0)
313  {
314  pr = 1;
315  ps = 2;
316  }
317  else
318  {
319  pr = 0;
320  ps = 3;
321  }
322  break;
323  case (8):
324  pr = 0;
325  ps = 2;
326  break;
327  case (9):
328  pr = 0;
329  ps = 1;
330  break;
331  default:
332  ASSERTL0(false,"Error in 5-point triangulation in ThreeSimilar");
333  break;
334  }
335 }
336 
338  const int fieldid,
339  const NekDouble val)
340 {
341  vector<IsoSharedPtr> returnval;
342 
343  int coordim = m_f->m_fieldPts->GetDim();
344  int nfields = m_f->m_fieldPts->GetNFields() + coordim;
345 
346  ASSERTL0(m_f->m_fieldPts->GetPtsType() == LibUtilities::ePtsTetBlock,
347  "This methods is currently only set up for 3D fields");
348  ASSERTL1(coordim + fieldid < nfields,
349  "field id is larger than number contained in FieldPts");
351  m_f->m_fieldPts->GetPts(fields);
352 
353  Array<OneD, NekDouble> c = fields[coordim + fieldid];
354 
355  int i, j, k, ii, jj, kk, r, s, n, counter, boolean;
356  Array<OneD, Array<OneD, NekDouble> > intfields(nfields);
357  intfields[0] = Array<OneD, NekDouble>(5*nfields);
358  for(i = 1; i < nfields; ++i)
359  {
360  intfields[i] = intfields[i-1] + 5;
361  }
362  Array<OneD, NekDouble> cx = intfields[0];
363  Array<OneD, NekDouble> cy = intfields[1];
364  Array<OneD, NekDouble> cz = intfields[2];
365 
366  vector<Array<OneD, int> > ptsConn;
367  m_f->m_fieldPts->GetConnectivity(ptsConn);
368  for(int zone = 0; zone < ptsConn.size(); ++zone)
369  {
370  IsoSharedPtr iso;
371 
372  iso = MemoryManager<Iso>::AllocateSharedPtr(nfields-3);
373 
374  int nelmt = ptsConn[zone].num_elements()
375  /(coordim+1);
376 
377  Array<OneD, int> conn = ptsConn[zone];
378 
379  for (n = 0, i = 0; i < nelmt; ++i)
380  {
381  // check to see if val is between vertex values
382  if(!(((c[conn[i*4]] >val)&&(c[conn[i*4+1]]>val)&&
383  (c[conn[i*4+2]]>val)&&(c[conn[i*4+3]]>val))||
384  ((c[conn[i*4 ]]<val)&&(c[conn[i*4+1]]<val)&&
385  (c[conn[i*4+2]]<val)&&(c[conn[i*4+3]]<val))))
386  {
387 
388  // loop over all edges and interpolate if
389  // contour is between vertex values
390  for (counter = 0, j=0; j<=2; j++)
391  {
392  for (k=j+1; k<=3; k++)
393  {
394  if (((c[conn[i*4+j]]>=val)&&
395  (val>=c[conn[i*4+k]]))||
396  ((c[conn[i*4+j]]<=val)&&
397  (val<=c[conn[i*4+k]])))
398  {
399  // linear interpolation of fields
400  // (and coords).
401  NekDouble cj = c[conn[i*4+j]];
402  NekDouble ck = c[conn[i*4+k]];
403  NekDouble factor = (val-cj)/(ck-cj);
404 
405  if(fabs(cj-ck) > 1e-12)
406  {
407  // interpolate coordinates and fields
408  for(int f = 0; f < nfields; ++f)
409  {
410  if(counter == 5)
411  {
412  ASSERTL0(false,"Counter is 5");
413  }
414  intfields[f][counter] =
415  fields[f][conn[4*i+j]] +
416  factor*(fields[f][conn[4*i+k]] -
417  fields[f][conn[4*i+j]]);
418  }
419  ++counter;
420  }
421  }
422  }
423  }
424 
425  switch(counter)
426  {
427  case 3:
428  n+=1;
429  iso->resize_fields(3*n);
430 
431  for(j = 0; j < 3; ++j)
432  {
433  iso->set_fields(3*(n-1)+j,intfields,j);
434  }
435  break;
436  case 4:
437  n+=2;
438  iso->resize_fields(3*n);
439 
440  for(j = 0; j < 3; ++j)
441  {
442  iso->set_fields(3*(n-2)+j,intfields,j);
443  iso->set_fields(3*(n-1)+j,intfields,j+1);
444  }
445  break;
446  case 5:
447  n+=1;
448  iso->resize_fields(3*n);
449 
450  boolean=0;
451  for (ii=0;ii<=2;ii++)
452  {
453  for (jj=ii+1;jj<=3;jj++)
454  {
455  for (kk=jj+1;kk<=4;kk++)
456  {
457  if((((cx[ii]-cx[jj])==0.0)&&
458  ((cy[ii]-cy[jj])==0.0)&&
459  ((cz[ii]-cz[jj])==0.0))&&
460  (((cx[ii]-cx[kk])==0.0)&&
461  ((cy[ii]-cy[kk])==0.0)&&
462  ((cz[ii]-cz[kk])==0.0)))
463  {
464  boolean+=1;
465  ThreeSimilar (ii,jj,kk,r,s);
466 
467  iso->set_fields(3*(n-1) ,intfields,ii);
468  iso->set_fields(3*(n-1)+1,intfields,r);
469  iso->set_fields(3*(n-1)+2,intfields,s);
470  }
471  else
472  {
473  boolean+=0;
474  }
475  }
476  }
477  }
478 
479  if (boolean==0)
480  {
481  TwoPairs (cx,cy,cz,r);
482 
483  iso->set_fields(3*(n-1) ,intfields,0);
484  iso->set_fields(3*(n-1)+1,intfields,2);
485  iso->set_fields(3*(n-1)+2,intfields,r);
486  }
487  break;
488  }
489  }
490  }
491  iso->set_ntris(n);
492 
493  // condense the information in this elemental extraction.
494  iso->condense();
495  returnval.push_back(iso);
496  }
497 
498  return returnval;
499 }
500 
501 // reset m_fieldPts with values from iso;
502 void ProcessIsoContour::ResetFieldPts(vector<IsoSharedPtr> &iso)
503 {
504  int nfields = m_f->m_fieldPts->GetNFields() + m_f->m_fieldPts->GetDim();
505 
506  // set output to triangle block.
507  m_f->m_fieldPts->SetPtsType(LibUtilities::ePtsTriBlock);
508 
509  Array<OneD, Array<OneD, NekDouble> > newfields(nfields);
510 
511  // count up number of points
512  int npts = 0;
513  for(int i =0; i < iso.size(); ++i)
514  {
515  npts += iso[i]->get_nvert();
516  }
517 
518  // set up coordinate in new field
519  newfields[0] = Array<OneD, NekDouble>(npts);
520  newfields[1] = Array<OneD, NekDouble>(npts);
521  newfields[2] = Array<OneD, NekDouble>(npts);
522 
523  int cnt = 0;
524  for(int i =0; i < iso.size(); ++i)
525  {
526  for(int j = 0; j < iso[i]->get_nvert(); ++j,++cnt)
527  {
528  newfields[0][cnt] = iso[i]->get_x(j);
529  newfields[1][cnt] = iso[i]->get_y(j);
530  newfields[2][cnt] = iso[i]->get_z(j);
531  }
532  }
533 
534 
535  // set up fields
536  for(int f = 0; f < nfields-3; ++f)
537  {
538  newfields[f+3] = Array<OneD, NekDouble>(npts);
539 
540  cnt = 0;
541  for(int i =0; i < iso.size(); ++i)
542  {
543  for(int j = 0; j < iso[i]->get_nvert(); ++j,++cnt)
544  {
545  newfields[f+3][cnt] = iso[i]->get_fields(f,j);
546  }
547  }
548  }
549 
550  m_f->m_fieldPts->SetPts(newfields);
551 
552  // set up connectivity data.
553  vector<Array<OneD, int> > ptsConn;
554  m_f->m_fieldPts->GetConnectivity(ptsConn);
555  cnt = 0;
556  ptsConn.clear();
557  for(int i =0; i < iso.size(); ++i)
558  {
559  int ntris = iso[i]->get_ntris();
560  Array<OneD, int> conn(ntris*3);
561 
562  for(int j = 0; j < 3*ntris; ++j)
563  {
564  conn[j] = cnt + iso[i]->get_vid(j);
565  }
566  ptsConn.push_back(conn);
567  cnt += iso[i]->get_nvert();
568  }
569  m_f->m_fieldPts->SetConnectivity(ptsConn);
570 }
571 
572 // reset m_fieldPts with values from iso;
573 void ProcessIsoContour::SetupIsoFromFieldPts(vector<IsoSharedPtr> &isovec)
574 {
575  ASSERTL0(m_f->m_fieldPts->GetPtsType() == LibUtilities::ePtsTriBlock,
576  "Assume input is from ePtsTriBlock");
577 
578  // get information from PtsField
579  int dim = m_f->m_fieldPts->GetDim();
580  int nfields = m_f->m_fieldPts->GetNFields() + dim;
582  m_f->m_fieldPts->GetPts(fieldpts);
583  vector<Array<OneD, int> > ptsConn;
584  m_f->m_fieldPts->GetConnectivity(ptsConn);
585 
586 
587  int cnt = 0;
588  for(int c = 0; c < ptsConn.size(); ++c)
589  {
590  // set up single iso with all the information from PtsField
592 
593  int nelmt = 0;
594  nelmt = ptsConn[c].num_elements()/3;
595 
596  iso->set_ntris(nelmt);
597  iso->resize_vid(3*nelmt);
598 
599  // fill in connectivity values.
600  int nvert = 0;
601  for(int i = 0; i < ptsConn[c].num_elements(); ++i)
602  {
603  int cid = ptsConn[c][i]-cnt;
604  iso->set_vid(i,cid);
605  nvert = max(cid,nvert);
606  }
607  nvert++;
608 
609  iso->set_nvert(nvert);
610  iso->resize_fields(nvert);
611 
612  // fill in points values (including coordinates)
613  for(int i = 0; i < nvert; ++i)
614  {
615  iso->set_fields(i,fieldpts,i+cnt);
616  }
617  cnt += nvert;
618  isovec.push_back(iso);
619  }
620 
621 }
622 
623 
624 void Iso::condense(void)
625 {
626  register int i,j,cnt;
627  IsoVertex v;
628  vector<IsoVertex> vert;
630 
631  if(!m_ntris) return;
632 
633  if(m_condensed) return;
634  m_condensed = true;
635 
636  vert.reserve(m_ntris/6);
637 
639 
640  // fill first 3 points and initialise fields
641  v.m_fields.resize(m_fields.size());
642  for(cnt =0, i = 0; i < 3; ++i)
643  {
644  v.m_x = m_x[i];
645  v.m_y = m_y[i];
646  v.m_z = m_z[i];
647  for(int f = 0; f < m_fields.size(); ++f)
648  {
649  v.m_fields[f] = m_fields[f][i];
650  }
651  v.m_id = cnt;
652  vert.push_back(v);
653  m_vid[i] = v.m_id;
654  ++cnt;
655  }
656 
657  for(i = 1; i < m_ntris; ++i)
658  {
659  for(j = 0; j < 3; ++j)
660  {
661  v.m_x = m_x[3*i+j];
662  v.m_y = m_y[3*i+j];
663  v.m_z = m_z[3*i+j];
664 
665  pt = find(vert.begin(),vert.end(),v);
666  if(pt != vert.end())
667  {
668  m_vid[3*i+j] = pt[0].m_id;
669  }
670  else
671  {
672  v.m_id = cnt;
673 
674  for(int f = 0; f < m_fields.size(); ++f)
675  {
676  v.m_fields[f] = m_fields[f][3*i+j];
677  }
678 
679  vert.push_back(v);
680 
681  m_vid[3*i+j] = v.m_id;
682  ++cnt;
683  }
684  }
685  }
686 
687  // remove elements with multiple vertices
688  for(i = 0,cnt=0; i < m_ntris;)
689  {
690  if((m_vid[3*i] ==m_vid[3*i+1])||
691  (m_vid[3*i] ==m_vid[3*i+2])||
692  (m_vid[3*i+1]==m_vid[3*i+2]))
693  {
694  cnt++;
695  for(j = 3*i; j < 3*(m_ntris-1); ++j)
696  {
697  m_vid[j] = m_vid[j+3];
698  }
699  m_ntris--;
700  }
701  else
702  {
703  ++i;
704  }
705  }
706 
707  m_nvert = vert.size();
708 
709  m_x.resize(m_nvert);
710  m_y.resize(m_nvert);
711  m_z.resize(m_nvert);
712 
713  for(int f = 0; f < m_fields.size(); ++f)
714  {
715  m_fields[f].resize(m_nvert);
716  }
717 
718  for(i = 0; i < m_nvert; ++i)
719  {
720  m_x[i] = vert[i].m_x;
721  m_y[i] = vert[i].m_y;
722  m_z[i] = vert[i].m_z;
723  for(int f = 0; f < m_fields.size(); ++f)
724  {
725  m_fields[f][i] = vert[i].m_fields[f];
726  }
727  }
728 }
729 
730 
732 
733 // define == if point is within 1e-4
734 bool operator == (const IsoVertex& x, const IsoVertex& y)
735 {
736  return ((x.m_x-y.m_x)*(x.m_x-y.m_x) + (x.m_y-y.m_y)*(x.m_y-y.m_y) +
737  (x.m_z-y.m_z)*(x.m_z-y.m_z) < SQ_PNT_TOL)? true:false;
738 }
739 
740 // define != if point is outside 1e-4
741 bool operator != (const IsoVertex& x, const IsoVertex& y)
742 {
743  return ((x.m_x-y.m_x)*(x.m_x-y.m_x) + (x.m_y-y.m_y)*(x.m_y-y.m_y) +
744  (x.m_z-y.m_z)*(x.m_z-y.m_z) < SQ_PNT_TOL)? 0:1;
745 }
746 
747 
749  NekDouble x2, NekDouble y2, NekDouble z2)
750 {
751  if((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2) < SQ_PNT_TOL)
752  {
753  return true;
754  }
755 
756  return false;
757 }
758 
759 void Iso::globalcondense(vector<IsoSharedPtr> &iso, bool verbose)
760 {
761  int i,j,n;
762  int nvert,nelmt;
763  int niso=iso.size();
764  int id1,id2;
766 
767  if(m_condensed) return;
768  m_condensed = true;
769 
770  vidmap = Array<OneD, Array<OneD, int> > (niso);
771 
772  m_ntris = 0;
773  for(i = 0; i < niso; ++i)
774  {
775  if(iso[i]->m_ntris)
776  {
777  m_ntris += iso[i]->m_ntris;
778  }
779  }
780 
782 
783  m_nvert = 0;
784  for(i = 0; i < niso; ++i)
785  {
786  if(iso[i]->m_ntris)
787  {
788  m_nvert += iso[i]->m_nvert;
789  }
790  }
791 
792  vector< vector<int> > isocon;
793  isocon.resize(niso);
794 
795  // identify which iso are connected by at least one point;
796  // find min x,y,z and max x,y,z and see if overlap to select
797  // which zones should be connected
798  {
799  vector<Array<OneD, NekDouble> > sph(niso);
800  Array<OneD, NekDouble> rng(6);
801  for(i = 0; i < niso; ++i)
802  {
803  sph[i] = Array<OneD, NekDouble>(4);
804 
805  // find max and min of isocontour
806  rng[0] = rng[3] = iso[i]->m_x[0];
807  rng[1] = rng[4] = iso[i]->m_x[1];
808  rng[2] = rng[5] = iso[i]->m_x[2];
809 
810  for(id1 = 1; id1 < iso[i]->m_nvert;++id1)
811  {
812  rng[0] = min(rng[0],iso[i]->m_x[i]);
813  rng[1] = min(rng[1],iso[i]->m_y[i]);
814  rng[2] = min(rng[2],iso[i]->m_z[i]);
815 
816  rng[3] = max(rng[3],iso[i]->m_x[i]);
817  rng[4] = max(rng[4],iso[i]->m_y[i]);
818  rng[5] = max(rng[5],iso[i]->m_z[i]);
819  }
820 
821  // centroid
822  sph[i][0] = (rng[3]+rng[0])/2.0;
823  sph[i][1] = (rng[4]+rng[1])/2.0;
824  sph[i][2] = (rng[5]+rng[2])/2.0;
825 
826  // radius;
827  sph[i][3] = sqrt((rng[3]-rng[0])*(rng[3]-rng[0]) +
828  (rng[4]-rng[1])*(rng[4]-rng[1]) +
829  (rng[5]-rng[2])*(rng[5]-rng[2]));
830  }
831 
832  for(i = 0; i < niso; ++i)
833  {
834  for(j = i; j < niso; ++j)
835  {
836  NekDouble diff=sqrt((sph[i][0]-sph[j][0])*(sph[i][0]-sph[j][0])+
837  (sph[i][1]-sph[j][1])*(sph[i][1]-sph[j][1])+
838  (sph[i][2]-sph[j][2])*(sph[i][2]-sph[j][2]));
839 
840  // if centroid is closer than added radii
841  if(diff < sph[i][3] + sph[j][3])
842  {
843  isocon[i].push_back(j);
844  }
845  }
846  }
847 
848  }
849 
850 
851  for(i = 0; i < niso; ++i)
852  {
853  vidmap[i] = Array<OneD, int>(iso[i]->m_nvert,-1);
854  }
855  nvert = 0;
856  int cnt = 0;
857  // count up amount of checking to be done
858  NekDouble totiso = 0;
859  for(i = 0; i < niso; ++i)
860  {
861  totiso += isocon[i].size();
862  }
863 
864 
865  if(verbose)
866  {
867  cout << "Progress Bar totiso: " << totiso << endl;
868  }
869  for(i = 0; i < niso; ++i)
870  {
871  for(n = 0; n < isocon[i].size(); ++n, ++cnt)
872  {
873 
874  if(verbose && totiso >= 40)
875  {
876  LibUtilities::PrintProgressbar(cnt,totiso,"Condensing verts");
877  }
878 
879  int con = isocon[i][n];
880  for(id1 = 0; id1 < iso[i]->m_nvert; ++id1)
881  {
882 
883  if(verbose && totiso < 40)
884  {
885  LibUtilities::PrintProgressbar(id1,iso[i]->m_nvert,"isocon");
886  }
887 
888  int start = 0;
889  if(con == i)
890  {
891  start = id1+1;
892  }
893  for(id2 = start; id2 < iso[con]->m_nvert; ++id2)
894  {
895 
896  if((vidmap[con][id2] == -1)||(vidmap[i][id1] == -1))
897  {
898  if(same(iso[i]->m_x[id1], iso[i]->m_y[id1],
899  iso[i]->m_z[id1], iso[con]->m_x[id2],
900  iso[con]->m_y[id2],iso[con]->m_z[id2]))
901  {
902  if((vidmap[i][id1] == -1) &&
903  (vidmap[con][id2] != -1))
904  {
905  vidmap[i][id1] = vidmap[con][id2];
906  }
907  else if((vidmap[con][id2] == -1) &&
908  (vidmap[i][id1] != -1))
909  {
910  vidmap[con][id2] = vidmap[i][id1];
911  }
912  else if((vidmap[con][id2] == -1) &&
913  (vidmap[i][id1] == -1))
914  {
915  vidmap[i][id1] = vidmap[con][id2] = nvert++;
916  }
917  }
918  }
919  }
920  }
921  }
922 
923  for(id1 = 0; id1 < iso[i]->m_nvert;++id1)
924  {
925  if(vidmap[i][id1] == -1)
926  {
927  vidmap[i][id1] = nvert++;
928  }
929  }
930  }
931  m_nvert = nvert;
932 
933  nelmt = 0;
934  // reset m_vid;
935  for(n = 0; n < niso; ++n)
936  {
937  for(i = 0; i < iso[n]->m_ntris; ++i,nelmt++)
938  {
939  for(j=0; j < 3;++j)
940  {
941  m_vid[3*nelmt+j] = vidmap[n][iso[n]->m_vid[3*i+j]];
942  }
943  }
944  }
945 
946  m_ntris = nelmt;
947 
948  m_x.resize(m_nvert);
949  m_y.resize(m_nvert);
950  m_z.resize(m_nvert);
951 
952  m_fields.resize(iso[0]->m_fields.size());
953  for(i = 0; i < iso[0]->m_fields.size(); ++i)
954  {
955  m_fields[i].resize(m_nvert);
956  }
957 
958  // reset coordinate and fields.
959  for(n = 0; n < niso; ++n)
960  {
961  for(i = 0; i < iso[n]->m_nvert; ++i)
962  {
963  m_x[vidmap[n][i]] = iso[n]->m_x[i];
964  m_y[vidmap[n][i]] = iso[n]->m_y[i];
965  m_z[vidmap[n][i]] = iso[n]->m_z[i];
966 
967  for(j = 0; j < m_fields.size(); ++j)
968  {
969  m_fields[j][vidmap[n][i]] = iso[n]->m_fields[j][i];
970  }
971  }
972  }
973  cout << endl;
974 }
975 
976 void Iso::smooth(int n_iter, NekDouble lambda, NekDouble mu)
977 {
978  int iter,i,j;
979  NekDouble del_v[3];
980  NekDouble w;
981  Array<OneD, NekDouble> xtemp, ytemp, ztemp;
982  vector< vector<int> > adj,vertcon;
985 
986  // determine elements around each vertex
987  vertcon.resize(m_nvert);
988  for(i = 0; i < m_ntris; ++i)
989  {
990  for(j = 0; j < 3; ++j)
991  {
992  vertcon[m_vid[3*i+j]].push_back(i);
993  }
994  }
995 
996  // determine vertices around each vertex
997  adj.resize(m_nvert);
998 
999  for(i =0; i < m_nvert; ++i)
1000  {
1001  for(ipt = vertcon[i].begin(); ipt != vertcon[i].end(); ++ipt)
1002  {
1003  for(j = 0; j < 3; ++j)
1004  {
1005  // make sure not adding own vertex
1006  if(m_vid[3*(*ipt)+j] != i)
1007  {
1008  // check to see if vertex has already been added
1009  for(iad = adj[i].begin(); iad != adj[i].end();++iad)
1010  {
1011  if(*iad == (m_vid[3*(*ipt)+j])) break;
1012  }
1013 
1014  if(iad == adj[i].end())
1015  {
1016  adj[i].push_back(m_vid[3*(*ipt)+j]);
1017  }
1018  }
1019  }
1020  }
1021  }
1022 
1026 
1027  // smooth each point
1028  for (iter=0;iter<n_iter;iter++)
1029  {
1030  // compute first weighted average
1031  for(i=0;i< m_nvert;++i)
1032  {
1033  w = 1.0/(NekDouble)(adj[i].size());
1034 
1035  del_v[0] = del_v[1] = del_v[2] = 0.0;
1036 
1037  for(iad = adj[i].begin(); iad != adj[i].end(); ++iad)
1038  {
1039  del_v[0] = del_v[0] + (m_x[*iad]-m_x[i])*w;
1040  del_v[1] = del_v[1] + (m_y[*iad]-m_y[i])*w;
1041  del_v[2] = del_v[2] + (m_z[*iad]-m_z[i])*w;
1042  }
1043 
1044  xtemp[i] = m_x[i] + del_v[0] * lambda;
1045  ytemp[i] = m_y[i] + del_v[1] * lambda;
1046  ztemp[i] = m_z[i] + del_v[2] * lambda;
1047  }
1048 
1049  // compute second weighted average
1050  for(i=0;i< m_nvert;++i)
1051  {
1052 
1053  w = 1.0/(NekDouble)(adj[i].size());
1054  del_v[0] = del_v[1] = del_v[2] = 0;
1055 
1056  for(iad = adj[i].begin(); iad != adj[i].end(); ++iad)
1057  {
1058  del_v[0] = del_v[0] + (m_x[*iad]-m_x[i])*w;
1059  del_v[1] = del_v[1] + (m_y[*iad]-m_y[i])*w;
1060  del_v[2] = del_v[2] + (m_z[*iad]-m_z[i])*w;
1061  }
1062 
1063  m_x[i] = xtemp[i] + del_v[0] * mu;
1064  m_y[i] = ytemp[i] + del_v[1] * mu;
1065  m_z[i] = ztemp[i] + del_v[2] * mu;
1066  }
1067  }
1068 }
1069 
1070 
1071  void Iso::separate_regions(vector<IsoSharedPtr> &sep_iso, int minsize, bool verbose)
1072  {
1073  int i,j,k,id;
1074  Array<OneD, vector<int> >vertcon(m_nvert);
1076  list<int> tocheck;
1077  list<int>::iterator cid;
1078 
1079  Array<OneD, bool> viddone(m_nvert,false);
1080 
1081  // make list of connecting tris around each vertex
1082  for(i = 0; i < m_ntris; ++i)
1083  {
1084  for(j = 0; j < 3; ++j)
1085  {
1086  vertcon[m_vid[3*i+j]].push_back(i);
1087  }
1088  }
1089 
1090  Array<OneD, int> vidregion(m_nvert,-1);
1091 
1092  int nregions = -1;
1093 
1094 
1095  // check all points are assigned to a region
1096  for(k = 0; k < m_nvert; ++k)
1097  {
1098  if(verbose)
1099  {
1100  LibUtilities::PrintProgressbar(k,m_nvert,"Separating regions");
1101  }
1102 
1103  if(vidregion[k] == -1)
1104  {
1105  vidregion[k] = ++nregions;
1106 
1107  // find all elmts around this.. vertex that need to be checked
1108  for(ipt = vertcon[k].begin(); ipt != vertcon[k].end(); ++ipt)
1109  {
1110  for(i = 0; i < 3; ++i)
1111  {
1112  if(vidregion[id = m_vid[3*(ipt[0])+i]] == -1)
1113  {
1114  tocheck.push_back(id);
1115  vidregion[id] = nregions;
1116  }
1117  }
1118  }
1119  viddone[k] = 1;
1120 
1121  // check all other neighbouring vertices
1122  while(tocheck.size())
1123  {
1124  cid = tocheck.begin();
1125  while(cid != tocheck.end())
1126  {
1127  if(!viddone[*cid])
1128  {
1129  for(ipt = vertcon[*cid].begin(); ipt != vertcon[*cid].end(); ++ipt)
1130  {
1131  for(i = 0; i < 3; ++i)
1132  {
1133  if(vidregion[id = m_vid[3*(ipt[0])+i]] == -1)
1134  {
1135  tocheck.push_back(id);
1136  vidregion[id] = nregions;
1137  }
1138  }
1139  }
1140  viddone[*cid] = 1;
1141  ++cid;
1142  tocheck.pop_front();
1143  }
1144  }
1145  }
1146  }
1147  }
1148  nregions++;
1149 
1150 
1151  Array<OneD, int> nvert(nregions,0);
1152  Array<OneD, int> nelmt(nregions,0);
1153 
1154  // count nverts
1155  for(i = 0; i < m_nvert; ++i)
1156  {
1157  nvert[vidregion[i]] +=1;
1158  }
1159 
1160  // count nelmts
1161  for(i = 0; i < m_ntris; ++i)
1162  {
1163  nelmt[vidregion[m_vid[3*i]]] +=1;
1164  }
1165 
1166  Array<OneD, int> vidmap(m_nvert);
1167  // generate new list of isocontour
1168  for(int n = 0; n < nregions; ++n)
1169  {
1170  if(nelmt[n] > minsize)
1171  {
1172  int nfields = m_fields.size();
1174 
1175  iso->m_ntris = nelmt[n];
1176  iso->m_vid = Array<OneD, int>(3*nelmt[n]);
1177 
1178  iso->m_nvert = nvert[n];
1179  iso->m_x.resize(nvert[n]);
1180  iso->m_y.resize(nvert[n]);
1181  iso->m_z.resize(nvert[n]);
1182 
1183  iso->m_fields.resize(nfields);
1184  for(i = 0; i < nfields; ++i)
1185  {
1186  iso->m_fields[i].resize(nvert[n]);
1187  }
1188 
1189 
1190  int cnt = 0;
1191  // generate vid map;
1192  Vmath::Zero(m_nvert,vidmap,1);
1193  for(i = 0; i < m_nvert; ++i)
1194  {
1195  if(vidregion[i] == n)
1196  {
1197  vidmap[i] = cnt++;
1198  }
1199  }
1200 
1201  cnt = 0;
1202  for(i = 0; i < m_ntris; ++i)
1203  {
1204  if(vidregion[m_vid[3*i]] == n)
1205  {
1206  for(j = 0; j < 3; ++j)
1207  {
1208  iso->m_vid[3*cnt+j] = vidmap[m_vid[3*i+j]];
1209 
1210  iso->m_x[vidmap[m_vid[3*i+j]]] = m_x[m_vid[3*i+j]];
1211  iso->m_y[vidmap[m_vid[3*i+j]]] = m_y[m_vid[3*i+j]];
1212  iso->m_z[vidmap[m_vid[3*i+j]]] = m_z[m_vid[3*i+j]];
1213 
1214  for(k = 0; k < nfields; ++k)
1215  {
1216  iso->m_fields[k][vidmap[m_vid[3*i+j]]] = m_fields[k][m_vid[3*i+j]];
1217  }
1218  }
1219  cnt++;
1220  }
1221  }
1222 
1223  WARNINGL0(cnt == nelmt[n],"Number of elements do not match");
1224  sep_iso.push_back(iso);
1225  }
1226  }
1227  }
1228 }
1229 }
1230 
1231 
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:188
pair< ModuleType, string > ModuleKey
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
virtual void Process()=0
vector< NekDouble > m_x
map< string, ConfigOption > m_config
List of configuration values.
STL namespace.
FieldSharedPtr m_f
Field object.
void separate_regions(vector< boost::shared_ptr< Iso > > &iso, int minsize, bool verbose)
void smooth(int n_iter, NekDouble lambda, NekDouble mu)
boost::shared_ptr< Iso > IsoSharedPtr
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:194
bool operator!=(const IsoVertex &x, const IsoVertex &y)
static std::string npts
Definition: InputFld.cpp:43
void SetupIsoFromFieldPts(vector< IsoSharedPtr > &isovec)
void TwoPairs(Array< OneD, NekDouble > &cx, Array< OneD, NekDouble > &cy, Array< OneD, NekDouble > &cz, int &pr)
double NekDouble
boost::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:695
vector< vector< NekDouble > > m_fields
This class defines evaluator of analytic (symbolic) mathematical expressions. Expressions are allowed...
Represents a command-line configuration option.
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
bool operator==(TriFaceIDs const &p1, TriFaceIDs const &p2)
vector< NekDouble > m_z
vector< IsoSharedPtr > ExtractContour(const int fieldid, const NekDouble val)
Array< OneD, int > m_vid
vector< NekDouble > m_y
void globalcondense(vector< boost::shared_ptr< Iso > > &iso, bool verbose)
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:315
void ResetFieldPts(vector< IsoSharedPtr > &iso)
bool same(NekDouble x1, NekDouble y1, NekDouble z1, NekDouble x2, NekDouble y2, NekDouble z2)
void ThreeSimilar(const int i, const int j, const int k, int &pr, int &ps)
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:359
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:218
This processing module interpolates one field to another.
void PrintProgressbar(const int position, const int goal, const string message)
Prints a progressbar.
Definition: Progressbar.hpp:69
ModuleFactory & GetModuleFactory()
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215