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