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