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  if(m_f->m_verbose)
110  {
111  if(m_f->m_comm->TreatAsRankZero())
112  {
113  cout << "ProcessIsoContour: Extracting contours..." << endl;
114  }
115  }
116 
117  vector<IsoSharedPtr> iso;
118 
119  if(m_f->m_fieldPts.get()) // assume we have read .dat file to directly input dat file.
120  {
122  }
123  else // extract isocontour from field
124  {
125  if(m_f->m_exp.size() == 0)
126  {
127  return;
128  }
129 
130  // extract all fields to equi-spaced
132 
133  int fieldid;
134  NekDouble value;
135 
136  if(m_config["fieldstr"].m_beenSet) //generate field of interest
137  {
138  fieldid = m_f->m_fieldPts->GetNFields();
139 
140  Array<OneD, NekDouble> pts(m_f->m_fieldPts->GetNpoints());
141 
142  // evaluate new function
144  string varstr = "x y z";
145  vector<Array<OneD, const NekDouble> > interpfields;
146 
147  for(int i = 0; i < m_f->m_fieldPts->GetDim(); ++i)
148  {
149  interpfields.push_back(m_f->m_fieldPts->GetPts(i));
150  }
151  for(int i = 0; i < m_f->m_fieldPts->GetNFields(); ++i)
152  {
153  varstr += " " + m_f->m_fieldPts->GetFieldName(i);
154  interpfields.push_back(m_f->m_fieldPts->GetPts(i+3));
155  }
156 
157  int ExprId = -1;
158  std::string str = m_config["fieldstr"].as<string>();
159  ExprId = strEval.DefineFunction(varstr.c_str(), str);
160 
161  strEval.Evaluate(ExprId, interpfields, pts);
162 
163  // set up field name if provided otherwise called "isocon" from default
164  string fieldName = m_config["fieldname"].as<string>();
165 
166  m_f->m_fieldPts->AddField(pts, fieldName);
167  }
168  else
169  {
170  ASSERTL0(m_config["fieldid"].as<string>() != "NotSet", "fieldid must be specified");
171  fieldid = m_config["fieldid"].as<int>();
172  }
173 
174  ASSERTL0(m_config["fieldvalue"].as<string>() != "NotSet", "fieldvalue must be specified");
175  value = m_config["fieldvalue"].as<NekDouble>();
176 
177  iso = ExtractContour(fieldid,value);
178 
179  }
180 
181  // Process isocontour
182  bool smoothing = m_config["smooth"].m_beenSet;
183  bool globalcondense = m_config["globalcondense"].m_beenSet;
184  if(globalcondense)
185  {
186  int nfields = m_f->m_fieldPts->GetNFields() + m_f->m_fieldPts->GetDim();
188 
189  g_iso->globalcondense(iso,m_f->m_verbose);
190 
191 
192  iso.clear();
193  iso.push_back(g_iso);
194  }
195 
196  if(smoothing)
197  {
198  int niter = m_config["smoothiter"].as<int>();
199  NekDouble lambda = m_config["smoothposdiffusion"].as<NekDouble>();
200  NekDouble mu = m_config["smoothnegdiffusion"].as<NekDouble>();
201  for(int i =0 ; i < iso.size(); ++i)
202  {
203  iso[i]->smooth(niter,lambda,-mu);
204  }
205  }
206 
207  int mincontour = 0;
208  if((mincontour = m_config["removesmallcontour"].as<int>()))
209  {
210  vector<IsoSharedPtr> new_iso;
211 
212  if(m_f->m_comm->TreatAsRankZero())
213  {
214  cout << "Identifying separate regions [." << flush ;
215  }
216  for(int i =0 ; i < iso.size(); ++i)
217  {
218  iso[i]->separate_regions(new_iso,mincontour,m_f->m_verbose);
219  }
220 
221  if(m_f->m_comm->TreatAsRankZero())
222  {
223  cout << "]" << endl << flush ;
224  }
225 
226  // reset iso to new_iso;
227  iso = new_iso;
228  }
229 
230  ResetFieldPts(iso);
231 }
232 
233 
234 /*********************/
235 /* Function TwoPairs */
236 /*********************/
237 
241  int &pr)
242 /* The logic of the following SWITCH statement may only be
243  understood with a "peusdo truth-table" */
244 {
245  if (((cx[0]-cx[1])==0.0)&&
246  ((cy[0]-cy[1])==0.0)&&
247  ((cz[0]-cz[1])==0.0))
248  {
249  if (((cx[2]-cx[3])==0.0)&&
250  ((cy[2]-cy[3])==0.0)&&
251  ((cz[2]-cz[3])==0.0))
252  {
253  pr=4;
254  }
255  else
256  {
257  pr=3;
258  }
259  }
260  else
261  {
262  pr=1;
263  }
264 }
265 
266 
267 /*************************/
268 /* Function ThreeSimilar */
269 /*************************/
270 void ThreeSimilar (const int i, const int j, const int k,
271  int &pr, int &ps)
272 /* The logic of the following SWITCH statement may be
273  understood with a "peusdo truth-table" */
274 {
275  switch (i + j + k)
276  {
277  case (3):
278  pr = 3;
279  ps = 4;
280  break;
281  case (4):
282  pr = 2;
283  ps = 4;
284  break;
285  case (5):
286  if (j == 1)
287  {
288  pr = 2;
289  ps = 3;
290  }
291  else
292  {
293  pr = 1;
294  ps = 4;
295  }
296  break;
297  case (6):
298  if (i == 0)
299  {
300  pr = 1;
301  ps = 3;
302  }
303  else
304  {
305  pr = 0;
306  ps = 4;
307  }
308  break;
309  case (7):
310  if (i == 0)
311  {
312  pr = 1;
313  ps = 2;
314  }
315  else
316  {
317  pr = 0;
318  ps = 3;
319  }
320  break;
321  case (8):
322  pr = 0;
323  ps = 2;
324  break;
325  case (9):
326  pr = 0;
327  ps = 1;
328  break;
329  default:
330  ASSERTL0(false,"Error in 5-point triangulation in ThreeSimilar");
331  break;
332  }
333 }
334 
336  const int fieldid,
337  const NekDouble val)
338 {
339  vector<IsoSharedPtr> returnval;
340 
341  int coordim = m_f->m_fieldPts->GetDim();
342  int nfields = m_f->m_fieldPts->GetNFields() + coordim;
343 
344  ASSERTL0(m_f->m_fieldPts->GetPtsType() == LibUtilities::ePtsTetBlock,
345  "This methods is currently only set up for 3D fields");
346  ASSERTL1(coordim + fieldid < nfields,
347  "field id is larger than number contained in FieldPts");
349  m_f->m_fieldPts->GetPts(fields);
350 
351  Array<OneD, NekDouble> c = fields[coordim + fieldid];
352 
353  int i, j, k, ii, jj, kk, r, s, n, counter, boolean;
354  Array<OneD, Array<OneD, NekDouble> > intfields(nfields);
355  intfields[0] = Array<OneD, NekDouble>(5*nfields);
356  for(i = 1; i < nfields; ++i)
357  {
358  intfields[i] = intfields[i-1] + 5;
359  }
360  Array<OneD, NekDouble> cx = intfields[0];
361  Array<OneD, NekDouble> cy = intfields[1];
362  Array<OneD, NekDouble> cz = intfields[2];
363 
364  vector<Array<OneD, int> > ptsConn;
365  m_f->m_fieldPts->GetConnectivity(ptsConn);
366  for(int zone = 0; zone < ptsConn.size(); ++zone)
367  {
368  IsoSharedPtr iso;
369 
370  iso = MemoryManager<Iso>::AllocateSharedPtr(nfields-3);
371 
372  int nelmt = ptsConn[zone].num_elements()
373  /(coordim+1);
374 
375  Array<OneD, int> conn = ptsConn[zone];
376 
377  for (n = 0, i = 0; i < nelmt; ++i)
378  {
379  // check to see if val is between vertex values
380  if(!(((c[conn[i*4]] >val)&&(c[conn[i*4+1]]>val)&&
381  (c[conn[i*4+2]]>val)&&(c[conn[i*4+3]]>val))||
382  ((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  {
385 
386  // loop over all edges and interpolate if
387  // contour is between vertex values
388  for (counter = 0, j=0; j<=2; j++)
389  {
390  for (k=j+1; k<=3; k++)
391  {
392  if (((c[conn[i*4+j]]>=val)&&
393  (val>=c[conn[i*4+k]]))||
394  ((c[conn[i*4+j]]<=val)&&
395  (val<=c[conn[i*4+k]])))
396  {
397  // linear interpolation of fields
398  // (and coords).
399  NekDouble cj = c[conn[i*4+j]];
400  NekDouble ck = c[conn[i*4+k]];
401  NekDouble factor = (val-cj)/(ck-cj);
402 
403  if(fabs(cj-ck) > 1e-12)
404  {
405  // interpolate coordinates and fields
406  for(int f = 0; f < nfields; ++f)
407  {
408  if(counter == 5)
409  {
410  ASSERTL0(false,"Counter is 5");
411  }
412  intfields[f][counter] =
413  fields[f][conn[4*i+j]] +
414  factor*(fields[f][conn[4*i+k]] -
415  fields[f][conn[4*i+j]]);
416  }
417  ++counter;
418  }
419  }
420  }
421  }
422 
423  switch(counter)
424  {
425  case 3:
426  n+=1;
427  iso->resize_fields(3*n);
428 
429  for(j = 0; j < 3; ++j)
430  {
431  iso->set_fields(3*(n-1)+j,intfields,j);
432  }
433  break;
434  case 4:
435  n+=2;
436  iso->resize_fields(3*n);
437 
438  for(j = 0; j < 3; ++j)
439  {
440  iso->set_fields(3*(n-2)+j,intfields,j);
441  iso->set_fields(3*(n-1)+j,intfields,j+1);
442  }
443  break;
444  case 5:
445  n+=1;
446  iso->resize_fields(3*n);
447 
448  boolean=0;
449  for (ii=0;ii<=2;ii++)
450  {
451  for (jj=ii+1;jj<=3;jj++)
452  {
453  for (kk=jj+1;kk<=4;kk++)
454  {
455  if((((cx[ii]-cx[jj])==0.0)&&
456  ((cy[ii]-cy[jj])==0.0)&&
457  ((cz[ii]-cz[jj])==0.0))&&
458  (((cx[ii]-cx[kk])==0.0)&&
459  ((cy[ii]-cy[kk])==0.0)&&
460  ((cz[ii]-cz[kk])==0.0)))
461  {
462  boolean+=1;
463  ThreeSimilar (ii,jj,kk,r,s);
464 
465  iso->set_fields(3*(n-1) ,intfields,ii);
466  iso->set_fields(3*(n-1)+1,intfields,r);
467  iso->set_fields(3*(n-1)+2,intfields,s);
468  }
469  else
470  {
471  boolean+=0;
472  }
473  }
474  }
475  }
476 
477  if (boolean==0)
478  {
479  TwoPairs (cx,cy,cz,r);
480 
481  iso->set_fields(3*(n-1) ,intfields,0);
482  iso->set_fields(3*(n-1)+1,intfields,2);
483  iso->set_fields(3*(n-1)+2,intfields,r);
484  }
485  break;
486  }
487  }
488  }
489  iso->set_ntris(n);
490 
491  // condense the information in this elemental extraction.
492  iso->condense();
493  returnval.push_back(iso);
494  }
495 
496  return returnval;
497 }
498 
499 // reset m_fieldPts with values from iso;
500 void ProcessIsoContour::ResetFieldPts(vector<IsoSharedPtr> &iso)
501 {
502  int nfields = m_f->m_fieldPts->GetNFields() + m_f->m_fieldPts->GetDim();
503 
504  // set output to triangle block.
505  m_f->m_fieldPts->SetPtsType(LibUtilities::ePtsTriBlock);
506 
507  Array<OneD, Array<OneD, NekDouble> > newfields(nfields);
508 
509  // count up number of points
510  int npts = 0;
511  for(int i =0; i < iso.size(); ++i)
512  {
513  npts += iso[i]->get_nvert();
514  }
515 
516  // set up coordinate in new field
517  newfields[0] = Array<OneD, NekDouble>(npts);
518  newfields[1] = Array<OneD, NekDouble>(npts);
519  newfields[2] = Array<OneD, NekDouble>(npts);
520 
521  int cnt = 0;
522  for(int i =0; i < iso.size(); ++i)
523  {
524  for(int j = 0; j < iso[i]->get_nvert(); ++j,++cnt)
525  {
526  newfields[0][cnt] = iso[i]->get_x(j);
527  newfields[1][cnt] = iso[i]->get_y(j);
528  newfields[2][cnt] = iso[i]->get_z(j);
529  }
530  }
531 
532 
533  // set up fields
534  for(int f = 0; f < nfields-3; ++f)
535  {
536  newfields[f+3] = Array<OneD, NekDouble>(npts);
537 
538  cnt = 0;
539  for(int i =0; i < iso.size(); ++i)
540  {
541  for(int j = 0; j < iso[i]->get_nvert(); ++j,++cnt)
542  {
543  newfields[f+3][cnt] = iso[i]->get_fields(f,j);
544  }
545  }
546  }
547 
548  m_f->m_fieldPts->SetPts(newfields);
549 
550  // set up connectivity data.
551  vector<Array<OneD, int> > ptsConn;
552  m_f->m_fieldPts->GetConnectivity(ptsConn);
553  cnt = 0;
554  ptsConn.clear();
555  for(int i =0; i < iso.size(); ++i)
556  {
557  int ntris = iso[i]->get_ntris();
558  Array<OneD, int> conn(ntris*3);
559 
560  for(int j = 0; j < 3*ntris; ++j)
561  {
562  conn[j] = cnt + iso[i]->get_vid(j);
563  }
564  ptsConn.push_back(conn);
565  cnt += iso[i]->get_nvert();
566  }
567  m_f->m_fieldPts->SetConnectivity(ptsConn);
568 }
569 
570 // reset m_fieldPts with values from iso;
571 void ProcessIsoContour::SetupIsoFromFieldPts(vector<IsoSharedPtr> &isovec)
572 {
573  ASSERTL0(m_f->m_fieldPts->GetPtsType() == LibUtilities::ePtsTriBlock,
574  "Assume input is from ePtsTriBlock");
575 
576  // get information from PtsField
577  int dim = m_f->m_fieldPts->GetDim();
578  int nfields = m_f->m_fieldPts->GetNFields() + dim;
580  m_f->m_fieldPts->GetPts(fieldpts);
581  vector<Array<OneD, int> > ptsConn;
582  m_f->m_fieldPts->GetConnectivity(ptsConn);
583 
584 
585  int cnt = 0;
586  for(int c = 0; c < ptsConn.size(); ++c)
587  {
588  // set up single iso with all the information from PtsField
590 
591  int nelmt = 0;
592  nelmt = ptsConn[c].num_elements()/3;
593 
594  iso->set_ntris(nelmt);
595  iso->resize_vid(3*nelmt);
596 
597  // fill in connectivity values.
598  int nvert = 0;
599  for(int i = 0; i < ptsConn[c].num_elements(); ++i)
600  {
601  int cid = ptsConn[c][i]-cnt;
602  iso->set_vid(i,cid);
603  nvert = max(cid,nvert);
604  }
605  nvert++;
606 
607  iso->set_nvert(nvert);
608  iso->resize_fields(nvert);
609 
610  // fill in points values (including coordinates)
611  for(int i = 0; i < nvert; ++i)
612  {
613  iso->set_fields(i,fieldpts,i+cnt);
614  }
615  cnt += nvert;
616  isovec.push_back(iso);
617  }
618 
619 }
620 
621 
622 void Iso::condense(void)
623 {
624  register int i,j,cnt;
625  IsoVertex v;
626  vector<IsoVertex> vert;
628 
629  if(!m_ntris) return;
630 
631  if(m_condensed) return;
632  m_condensed = true;
633 
634  vert.reserve(m_ntris/6);
635 
637 
638  // fill first 3 points and initialise fields
639  v.m_fields.resize(m_fields.size());
640  for(cnt =0, i = 0; i < 3; ++i)
641  {
642  v.m_x = m_x[i];
643  v.m_y = m_y[i];
644  v.m_z = m_z[i];
645  for(int f = 0; f < m_fields.size(); ++f)
646  {
647  v.m_fields[f] = m_fields[f][i];
648  }
649  v.m_id = cnt;
650  vert.push_back(v);
651  m_vid[i] = v.m_id;
652  ++cnt;
653  }
654 
655  for(i = 1; i < m_ntris; ++i)
656  {
657  for(j = 0; j < 3; ++j)
658  {
659  v.m_x = m_x[3*i+j];
660  v.m_y = m_y[3*i+j];
661  v.m_z = m_z[3*i+j];
662 
663  pt = find(vert.begin(),vert.end(),v);
664  if(pt != vert.end())
665  {
666  m_vid[3*i+j] = pt[0].m_id;
667  }
668  else
669  {
670  v.m_id = cnt;
671 
672  for(int f = 0; f < m_fields.size(); ++f)
673  {
674  v.m_fields[f] = m_fields[f][3*i+j];
675  }
676 
677  vert.push_back(v);
678 
679  m_vid[3*i+j] = v.m_id;
680  ++cnt;
681  }
682  }
683  }
684 
685  // remove elements with multiple vertices
686  for(i = 0,cnt=0; i < m_ntris;)
687  {
688  if((m_vid[3*i] ==m_vid[3*i+1])||
689  (m_vid[3*i] ==m_vid[3*i+2])||
690  (m_vid[3*i+1]==m_vid[3*i+2]))
691  {
692  cnt++;
693  for(j = 3*i; j < 3*(m_ntris-1); ++j)
694  {
695  m_vid[j] = m_vid[j+3];
696  }
697  m_ntris--;
698  }
699  else
700  {
701  ++i;
702  }
703  }
704 
705  m_nvert = vert.size();
706 
707  m_x.resize(m_nvert);
708  m_y.resize(m_nvert);
709  m_z.resize(m_nvert);
710 
711  for(int f = 0; f < m_fields.size(); ++f)
712  {
713  m_fields[f].resize(m_nvert);
714  }
715 
716  for(i = 0; i < m_nvert; ++i)
717  {
718  m_x[i] = vert[i].m_x;
719  m_y[i] = vert[i].m_y;
720  m_z[i] = vert[i].m_z;
721  for(int f = 0; f < m_fields.size(); ++f)
722  {
723  m_fields[f][i] = vert[i].m_fields[f];
724  }
725  }
726 }
727 
728 
730 
731 // define == if point is within 1e-4
732 bool operator == (const IsoVertex& x, const IsoVertex& y)
733 {
734  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) +
735  (x.m_z-y.m_z)*(x.m_z-y.m_z) < SQ_PNT_TOL)? true:false;
736 }
737 
738 // define != if point is outside 1e-4
739 bool operator != (const IsoVertex& x, const IsoVertex& y)
740 {
741  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) +
742  (x.m_z-y.m_z)*(x.m_z-y.m_z) < SQ_PNT_TOL)? 0:1;
743 }
744 
745 
747  NekDouble x2, NekDouble y2, NekDouble z2)
748 {
749  if((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2) < SQ_PNT_TOL)
750  {
751  return true;
752  }
753 
754  return false;
755 }
756 
757 void Iso::globalcondense(vector<IsoSharedPtr> &iso, bool verbose)
758 {
759  int i,j,n;
760  int nvert,nelmt;
761  int niso=iso.size();
762  int id1,id2;
764 
765  if(m_condensed) return;
766  m_condensed = true;
767 
768  vidmap = Array<OneD, Array<OneD, int> > (niso);
769 
770  m_ntris = 0;
771  for(i = 0; i < niso; ++i)
772  {
773  if(iso[i]->m_ntris)
774  {
775  m_ntris += iso[i]->m_ntris;
776  }
777  }
778 
780 
781  m_nvert = 0;
782  for(i = 0; i < niso; ++i)
783  {
784  if(iso[i]->m_ntris)
785  {
786  m_nvert += iso[i]->m_nvert;
787  }
788  }
789 
790  vector< vector<int> > isocon;
791  isocon.resize(niso);
792 
793  // identify which iso are connected by at least one point;
794  // find min x,y,z and max x,y,z and see if overlap to select
795  // which zones should be connected
796  {
797  vector<Array<OneD, NekDouble> > sph(niso);
798  Array<OneD, NekDouble> rng(6);
799  for(i = 0; i < niso; ++i)
800  {
801  sph[i] = Array<OneD, NekDouble>(4);
802 
803  // find max and min of isocontour
804  rng[0] = rng[3] = iso[i]->m_x[0];
805  rng[1] = rng[4] = iso[i]->m_x[1];
806  rng[2] = rng[5] = iso[i]->m_x[2];
807 
808  for(id1 = 1; id1 < iso[i]->m_nvert;++id1)
809  {
810  rng[0] = min(rng[0],iso[i]->m_x[i]);
811  rng[1] = min(rng[1],iso[i]->m_y[i]);
812  rng[2] = min(rng[2],iso[i]->m_z[i]);
813 
814  rng[3] = max(rng[3],iso[i]->m_x[i]);
815  rng[4] = max(rng[4],iso[i]->m_y[i]);
816  rng[5] = max(rng[5],iso[i]->m_z[i]);
817  }
818 
819  // centroid
820  sph[i][0] = (rng[3]+rng[0])/2.0;
821  sph[i][1] = (rng[4]+rng[1])/2.0;
822  sph[i][2] = (rng[5]+rng[2])/2.0;
823 
824  // radius;
825  sph[i][3] = sqrt((rng[3]-rng[0])*(rng[3]-rng[0]) +
826  (rng[4]-rng[1])*(rng[4]-rng[1]) +
827  (rng[5]-rng[2])*(rng[5]-rng[2]));
828  }
829 
830  for(i = 0; i < niso; ++i)
831  {
832  for(j = i; j < niso; ++j)
833  {
834  NekDouble diff=sqrt((sph[i][0]-sph[j][0])*(sph[i][0]-sph[j][0])+
835  (sph[i][1]-sph[j][1])*(sph[i][1]-sph[j][1])+
836  (sph[i][2]-sph[j][2])*(sph[i][2]-sph[j][2]));
837 
838  // if centroid is closer than added radii
839  if(diff < sph[i][3] + sph[j][3])
840  {
841  isocon[i].push_back(j);
842  }
843  }
844  }
845 
846  }
847 
848 
849  for(i = 0; i < niso; ++i)
850  {
851  vidmap[i] = Array<OneD, int>(iso[i]->m_nvert,-1);
852  }
853  nvert = 0;
854  int cnt = 0;
855  // count up amount of checking to be done
856  NekDouble totiso = 0;
857  for(i = 0; i < niso; ++i)
858  {
859  totiso += isocon[i].size();
860  }
861 
862 
863  if(verbose)
864  {
865  cout << "Progress Bar totiso: " << totiso << endl;
866  }
867  for(i = 0; i < niso; ++i)
868  {
869  for(n = 0; n < isocon[i].size(); ++n, ++cnt)
870  {
871 
872  if(verbose && totiso >= 40)
873  {
874  LibUtilities::PrintProgressbar(cnt,totiso,"Condensing verts");
875  }
876 
877  int con = isocon[i][n];
878  for(id1 = 0; id1 < iso[i]->m_nvert; ++id1)
879  {
880 
881  if(verbose && totiso < 40)
882  {
883  LibUtilities::PrintProgressbar(id1,iso[i]->m_nvert,"isocon");
884  }
885 
886  int start = 0;
887  if(con == i)
888  {
889  start = id1+1;
890  }
891  for(id2 = start; id2 < iso[con]->m_nvert; ++id2)
892  {
893 
894  if((vidmap[con][id2] == -1)||(vidmap[i][id1] == -1))
895  {
896  if(same(iso[i]->m_x[id1], iso[i]->m_y[id1],
897  iso[i]->m_z[id1], iso[con]->m_x[id2],
898  iso[con]->m_y[id2],iso[con]->m_z[id2]))
899  {
900  if((vidmap[i][id1] == -1) &&
901  (vidmap[con][id2] != -1))
902  {
903  vidmap[i][id1] = vidmap[con][id2];
904  }
905  else if((vidmap[con][id2] == -1) &&
906  (vidmap[i][id1] != -1))
907  {
908  vidmap[con][id2] = vidmap[i][id1];
909  }
910  else if((vidmap[con][id2] == -1) &&
911  (vidmap[i][id1] == -1))
912  {
913  vidmap[i][id1] = vidmap[con][id2] = nvert++;
914  }
915  }
916  }
917  }
918  }
919  }
920 
921  for(id1 = 0; id1 < iso[i]->m_nvert;++id1)
922  {
923  if(vidmap[i][id1] == -1)
924  {
925  vidmap[i][id1] = nvert++;
926  }
927  }
928  }
929  m_nvert = nvert;
930 
931  nelmt = 0;
932  // reset m_vid;
933  for(n = 0; n < niso; ++n)
934  {
935  for(i = 0; i < iso[n]->m_ntris; ++i,nelmt++)
936  {
937  for(j=0; j < 3;++j)
938  {
939  m_vid[3*nelmt+j] = vidmap[n][iso[n]->m_vid[3*i+j]];
940  }
941  }
942  }
943 
944  m_ntris = nelmt;
945 
946  m_x.resize(m_nvert);
947  m_y.resize(m_nvert);
948  m_z.resize(m_nvert);
949 
950  m_fields.resize(iso[0]->m_fields.size());
951  for(i = 0; i < iso[0]->m_fields.size(); ++i)
952  {
953  m_fields[i].resize(m_nvert);
954  }
955 
956  // reset coordinate and fields.
957  for(n = 0; n < niso; ++n)
958  {
959  for(i = 0; i < iso[n]->m_nvert; ++i)
960  {
961  m_x[vidmap[n][i]] = iso[n]->m_x[i];
962  m_y[vidmap[n][i]] = iso[n]->m_y[i];
963  m_z[vidmap[n][i]] = iso[n]->m_z[i];
964 
965  for(j = 0; j < m_fields.size(); ++j)
966  {
967  m_fields[j][vidmap[n][i]] = iso[n]->m_fields[j][i];
968  }
969  }
970  }
971  cout << endl;
972 }
973 
974 void Iso::smooth(int n_iter, NekDouble lambda, NekDouble mu)
975 {
976  int iter,i,j;
977  NekDouble del_v[3];
978  NekDouble w;
979  Array<OneD, NekDouble> xtemp, ytemp, ztemp;
980  vector< vector<int> > adj,vertcon;
983 
984  // determine elements around each vertex
985  vertcon.resize(m_nvert);
986  for(i = 0; i < m_ntris; ++i)
987  {
988  for(j = 0; j < 3; ++j)
989  {
990  vertcon[m_vid[3*i+j]].push_back(i);
991  }
992  }
993 
994  // determine vertices around each vertex
995  adj.resize(m_nvert);
996 
997  for(i =0; i < m_nvert; ++i)
998  {
999  for(ipt = vertcon[i].begin(); ipt != vertcon[i].end(); ++ipt)
1000  {
1001  for(j = 0; j < 3; ++j)
1002  {
1003  // make sure not adding own vertex
1004  if(m_vid[3*(*ipt)+j] != i)
1005  {
1006  // check to see if vertex has already been added
1007  for(iad = adj[i].begin(); iad != adj[i].end();++iad)
1008  {
1009  if(*iad == (m_vid[3*(*ipt)+j])) break;
1010  }
1011 
1012  if(iad == adj[i].end())
1013  {
1014  adj[i].push_back(m_vid[3*(*ipt)+j]);
1015  }
1016  }
1017  }
1018  }
1019  }
1020 
1024 
1025  // smooth each point
1026  for (iter=0;iter<n_iter;iter++)
1027  {
1028  // compute first weighted average
1029  for(i=0;i< m_nvert;++i)
1030  {
1031  w = 1.0/(NekDouble)(adj[i].size());
1032 
1033  del_v[0] = del_v[1] = del_v[2] = 0.0;
1034 
1035  for(iad = adj[i].begin(); iad != adj[i].end(); ++iad)
1036  {
1037  del_v[0] = del_v[0] + (m_x[*iad]-m_x[i])*w;
1038  del_v[1] = del_v[1] + (m_y[*iad]-m_y[i])*w;
1039  del_v[2] = del_v[2] + (m_z[*iad]-m_z[i])*w;
1040  }
1041 
1042  xtemp[i] = m_x[i] + del_v[0] * lambda;
1043  ytemp[i] = m_y[i] + del_v[1] * lambda;
1044  ztemp[i] = m_z[i] + del_v[2] * lambda;
1045  }
1046 
1047  // compute second weighted average
1048  for(i=0;i< m_nvert;++i)
1049  {
1050 
1051  w = 1.0/(NekDouble)(adj[i].size());
1052  del_v[0] = del_v[1] = del_v[2] = 0;
1053 
1054  for(iad = adj[i].begin(); iad != adj[i].end(); ++iad)
1055  {
1056  del_v[0] = del_v[0] + (m_x[*iad]-m_x[i])*w;
1057  del_v[1] = del_v[1] + (m_y[*iad]-m_y[i])*w;
1058  del_v[2] = del_v[2] + (m_z[*iad]-m_z[i])*w;
1059  }
1060 
1061  m_x[i] = xtemp[i] + del_v[0] * mu;
1062  m_y[i] = ytemp[i] + del_v[1] * mu;
1063  m_z[i] = ztemp[i] + del_v[2] * mu;
1064  }
1065  }
1066 }
1067 
1068 
1069  void Iso::separate_regions(vector<IsoSharedPtr> &sep_iso, int minsize, bool verbose)
1070  {
1071  int i,j,k,id;
1072  Array<OneD, vector<int> >vertcon(m_nvert);
1074  list<int> tocheck;
1075  list<int>::iterator cid;
1076 
1077  Array<OneD, bool> viddone(m_nvert,false);
1078 
1079  // make list of connecting tris around each vertex
1080  for(i = 0; i < m_ntris; ++i)
1081  {
1082  for(j = 0; j < 3; ++j)
1083  {
1084  vertcon[m_vid[3*i+j]].push_back(i);
1085  }
1086  }
1087 
1088  Array<OneD, int> vidregion(m_nvert,-1);
1089 
1090  int nregions = -1;
1091 
1092 
1093  // check all points are assigned to a region
1094  for(k = 0; k < m_nvert; ++k)
1095  {
1096  if(verbose)
1097  {
1098  LibUtilities::PrintProgressbar(k,m_nvert,"Separating regions");
1099  }
1100 
1101  if(vidregion[k] == -1)
1102  {
1103  vidregion[k] = ++nregions;
1104 
1105  // find all elmts around this.. vertex that need to be checked
1106  for(ipt = vertcon[k].begin(); ipt != vertcon[k].end(); ++ipt)
1107  {
1108  for(i = 0; i < 3; ++i)
1109  {
1110  if(vidregion[id = m_vid[3*(ipt[0])+i]] == -1)
1111  {
1112  tocheck.push_back(id);
1113  vidregion[id] = nregions;
1114  }
1115  }
1116  }
1117  viddone[k] = 1;
1118 
1119  // check all other neighbouring vertices
1120  while(tocheck.size())
1121  {
1122  cid = tocheck.begin();
1123  while(cid != tocheck.end())
1124  {
1125  if(!viddone[*cid])
1126  {
1127  for(ipt = vertcon[*cid].begin(); ipt != vertcon[*cid].end(); ++ipt)
1128  {
1129  for(i = 0; i < 3; ++i)
1130  {
1131  if(vidregion[id = m_vid[3*(ipt[0])+i]] == -1)
1132  {
1133  tocheck.push_back(id);
1134  vidregion[id] = nregions;
1135  }
1136  }
1137  }
1138  viddone[*cid] = 1;
1139  ++cid;
1140  tocheck.pop_front();
1141  }
1142  }
1143  }
1144  }
1145  }
1146  nregions++;
1147 
1148 
1149  Array<OneD, int> nvert(nregions,0);
1150  Array<OneD, int> nelmt(nregions,0);
1151 
1152  // count nverts
1153  for(i = 0; i < m_nvert; ++i)
1154  {
1155  nvert[vidregion[i]] +=1;
1156  }
1157 
1158  // count nelmts
1159  for(i = 0; i < m_ntris; ++i)
1160  {
1161  nelmt[vidregion[m_vid[3*i]]] +=1;
1162  }
1163 
1164  Array<OneD, int> vidmap(m_nvert);
1165  // generate new list of isocontour
1166  for(int n = 0; n < nregions; ++n)
1167  {
1168  if(nelmt[n] > minsize)
1169  {
1170  int nfields = m_fields.size();
1172 
1173  iso->m_ntris = nelmt[n];
1174  iso->m_vid = Array<OneD, int>(3*nelmt[n]);
1175 
1176  iso->m_nvert = nvert[n];
1177  iso->m_x.resize(nvert[n]);
1178  iso->m_y.resize(nvert[n]);
1179  iso->m_z.resize(nvert[n]);
1180 
1181  iso->m_fields.resize(nfields);
1182  for(i = 0; i < nfields; ++i)
1183  {
1184  iso->m_fields[i].resize(nvert[n]);
1185  }
1186 
1187 
1188  int cnt = 0;
1189  // generate vid map;
1190  Vmath::Zero(m_nvert,vidmap,1);
1191  for(i = 0; i < m_nvert; ++i)
1192  {
1193  if(vidregion[i] == n)
1194  {
1195  vidmap[i] = cnt++;
1196  }
1197  }
1198 
1199  cnt = 0;
1200  for(i = 0; i < m_ntris; ++i)
1201  {
1202  if(vidregion[m_vid[3*i]] == n)
1203  {
1204  for(j = 0; j < 3; ++j)
1205  {
1206  iso->m_vid[3*cnt+j] = vidmap[m_vid[3*i+j]];
1207 
1208  iso->m_x[vidmap[m_vid[3*i+j]]] = m_x[m_vid[3*i+j]];
1209  iso->m_y[vidmap[m_vid[3*i+j]]] = m_y[m_vid[3*i+j]];
1210  iso->m_z[vidmap[m_vid[3*i+j]]] = m_z[m_vid[3*i+j]];
1211 
1212  for(k = 0; k < nfields; ++k)
1213  {
1214  iso->m_fields[k][vidmap[m_vid[3*i+j]]] = m_fields[k][m_vid[3*i+j]];
1215  }
1216  }
1217  cnt++;
1218  }
1219  }
1220 
1221  WARNINGL0(cnt == nelmt[n],"Number of elements do not match");
1222  sep_iso.push_back(iso);
1223  }
1224  }
1225  }
1226 }
1227 }
1228 
1229 
#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:698
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