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>
48#include <boost/math/special_functions/fpclassify.hpp>
50namespace bg = boost::geometry;
51namespace bgi = boost::geometry::index;
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 "
72 ConfigOption(
false,
"NotSet",
"string of isocontour to be extracted");
74 "name for isocontour if fieldstr "
75 "specified, default is isocon");
84 "Globally condense contour to unique "
88 "Smooth isocontour (might require "
93 "Number of smoothing cycle, default = "
98 "Postive diffusion coefficient "
99 "(0 < lambda < 1), default = 0.5");
103 "Negative diffusion coefficient "
104 "(0 < mu < 1), default = 0.505");
108 "Remove contours with less than specified number of triangles."
109 "Only valid with GlobalCondense or Smooth options.");
120 bool verbose = (
m_f->m_verbose &&
m_f->m_comm->TreatAsRankZero());
122 vector<IsoSharedPtr> iso;
124 ASSERTL0(
m_f->m_fieldPts.get(),
"Should have m_fieldPts for IsoContour.");
131 cout <<
"\t Process read iso from Field Pts" << endl;
140 string fieldName =
m_config[
"fieldname"].as<
string>();
141 m_f->m_variables.push_back(fieldName);
144 if (
m_f->m_fieldPts->GetNpoints() == 0)
154 fieldid =
m_f->m_fieldPts->GetNFields();
160 string varstr =
"x y z";
161 vector<Array<OneD, const NekDouble>> interpfields;
163 for (
int i = 0; i <
m_f->m_fieldPts->GetDim(); ++i)
165 interpfields.push_back(
m_f->m_fieldPts->GetPts(i));
167 for (
int i = 0; i <
m_f->m_fieldPts->GetNFields(); ++i)
169 varstr +=
" " +
m_f->m_fieldPts->GetFieldName(i);
170 interpfields.push_back(
m_f->m_fieldPts->GetPts(i + 3));
174 std::string str =
m_config[
"fieldstr"].as<
string>();
177 strEval.
Evaluate(ExprId, interpfields, pts);
181 string fieldName =
m_config[
"fieldname"].as<
string>();
183 m_f->m_fieldPts->AddField(pts, fieldName);
188 "fieldid must be specified");
189 fieldid =
m_config[
"fieldid"].as<
int>();
193 "fieldvalue must be specified");
200 ASSERTL0(
false,
"PtsType not supported for isocontour.");
204 bool smoothing =
m_config[
"smooth"].as<
bool>();
205 bool globalcondense =
m_config[
"globalcondense"].as<
bool>();
210 cout <<
"\t Process global condense ..." << endl;
212 int nfields =
m_f->m_fieldPts->GetNFields() +
m_f->m_fieldPts->GetDim();
215 g_iso->GlobalCondense(iso, verbose);
218 iso.push_back(g_iso);
227 cout <<
"\t Process Contour smoothing ..." << endl;
231 int niter =
m_config[
"smoothiter"].as<
int>();
234 for (
int i = 0; i < iso.size(); ++i)
236 iso[i]->Smooth(niter, lambda, -mu);
245 ss << cpuTime <<
"s";
246 cout <<
"\t Process smooth CPU Time: " << setw(8) << left
253 if ((mincontour =
m_config[
"removesmallcontour"].as<int>()))
255 vector<IsoSharedPtr> new_iso;
259 cout <<
"\t Identifying separate regions [." << flush;
261 for (
int i = 0; i < iso.size(); ++i)
263 iso[i]->SeparateRegions(new_iso, mincontour,
m_f->m_verbose);
268 cout <<
"]" << endl << flush;
287 if (((cx[0] - cx[1]) == 0.0) && ((cy[0] - cy[1]) == 0.0) &&
288 ((cz[0] - cz[1]) == 0.0))
290 if (((cx[2] - cx[3]) == 0.0) && ((cy[2] - cy[3]) == 0.0) &&
291 ((cz[2] - cz[3]) == 0.0))
309void ThreeSimilar(
const int i,
const int j,
const int k,
int &pr,
int &ps)
368 ASSERTL0(
false,
"Error in 5-point triangulation in ThreeSimilar");
376 vector<IsoSharedPtr> returnval;
378 int coordim =
m_f->m_fieldPts->GetDim();
379 int nfields =
m_f->m_fieldPts->GetNFields() + coordim;
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);
390 int i, j, k, ii, jj, kk, r, s, n, counter, boolean;
393 for (i = 1; i < nfields; ++i)
395 intfields[i] = intfields[i - 1] + 5;
401 vector<Array<OneD, int>> ptsConn;
402 m_f->m_fieldPts->GetConnectivity(ptsConn);
404 for (
int zone = 0; zone < ptsConn.size(); ++zone)
410 int nelmt = ptsConn[zone].size() / (coordim + 1);
414 for (n = 0, i = 0; i < nelmt; ++i)
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))))
425 for (counter = 0, j = 0; j <= 2; j++)
427 for (k = j + 1; k <= 3; k++)
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]])))
438 NekDouble factor = (val - cj) / (ck - cj);
440 if (fabs(cj - ck) > 1e-12)
443 for (
int f = 0; f < nfields; ++f)
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]]);
464 iso->ResizeFields(3 * n);
466 for (j = 0; j < 3; ++j)
468 iso->SetFields(3 * (n - 1) + j, intfields, j);
473 iso->ResizeFields(3 * n);
475 for (j = 0; j < 3; ++j)
477 iso->SetFields(3 * (n - 2) + j, intfields, j);
478 iso->SetFields(3 * (n - 1) + j, intfields, j + 1);
483 iso->ResizeFields(3 * n);
486 for (ii = 0; ii <= 2; ii++)
488 for (jj = ii + 1; jj <= 3; jj++)
490 for (kk = jj + 1; kk <= 4; kk++)
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)))
502 iso->SetFields(3 * (n - 1), intfields,
504 iso->SetFields(3 * (n - 1) + 1,
506 iso->SetFields(3 * (n - 1) + 2,
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);
537 returnval.push_back(iso);
547 int nfields =
m_f->m_fieldPts->GetNFields() +
m_f->m_fieldPts->GetDim();
556 for (
int i = 0; i < iso.size(); ++i)
558 npts += iso[i]->GetNVert();
567 for (
int i = 0; i < iso.size(); ++i)
569 for (
int j = 0; j < iso[i]->GetNVert(); ++j, ++cnt)
571 newfields[0][cnt] = iso[i]->GetX(j);
572 newfields[1][cnt] = iso[i]->GetY(j);
573 newfields[2][cnt] = iso[i]->GetZ(j);
578 for (
int f = 0; f < nfields - 3; ++f)
583 for (
int i = 0; i < iso.size(); ++i)
585 for (
int j = 0; j < iso[i]->GetNVert(); ++j, ++cnt)
587 newfields[f + 3][cnt] = iso[i]->GetFields(f, j);
592 m_f->m_fieldPts->SetPts(newfields);
595 vector<Array<OneD, int>> ptsConn;
596 m_f->m_fieldPts->GetConnectivity(ptsConn);
599 for (
int i = 0; i < iso.size(); ++i)
601 int ntris = iso[i]->GetNTris();
604 for (
int j = 0; j < 3 * ntris; ++j)
606 conn[j] = cnt + iso[i]->GetVId(j);
608 ptsConn.push_back(conn);
609 cnt += iso[i]->GetNVert();
611 m_f->m_fieldPts->SetConnectivity(ptsConn);
618 "Assume input is from ePtsTriBlock");
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);
629 for (
int c = 0; c < ptsConn.size(); ++c)
635 nelmt = ptsConn[c].size() / 3;
637 iso->SetNTris(nelmt);
638 iso->ResizeVId(3 * nelmt);
642 for (
int i = 0; i < ptsConn[c].size(); ++i)
644 int cid = ptsConn[c][i] - cnt;
646 nvert = max(cid, nvert);
650 iso->SetNVert(nvert);
651 iso->ResizeFields(nvert);
654 for (
int i = 0; i < nvert; ++i)
656 iso->SetFields(i, fieldpts, i + cnt);
659 isovec.push_back(iso);
667 vector<IsoVertex> vert;
682 for (cnt = 0, i = 0; i < 3; ++i)
687 for (
int f = 0; f <
m_fields.size(); ++f)
699 for (j = 0; j < 3; ++j)
705 auto pt =
find(vert.begin(), vert.end(), v);
706 if (pt != vert.end())
708 m_vid[3 * i + j] = pt[0].m_id;
714 for (
int f = 0; f <
m_fields.size(); ++f)
728 for (i = 0, cnt = 0; i <
m_ntris;)
735 for (j = 3 * i; j < 3 * (
m_ntris - 1); ++j)
753 for (
int f = 0; f <
m_fields.size(); ++f)
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)
765 m_fields[f][i] = vert[i].m_fields[f];
772 typedef bg::model::point<NekDouble, 3, bg::cs::cartesian> BPoint;
773 typedef std::pair<BPoint, unsigned int> PointPair;
777 int niso = iso.size();
788 for (i = 0; i < niso; ++i)
799 for (i = 0; i < niso; ++i)
807 vector<vector<int>> isocon;
809 vector<int> global_to_unique_map;
810 global_to_unique_map.resize(
m_nvert);
812 vector<pair<int, int>> global_to_iso_map;
813 global_to_iso_map.resize(
m_nvert);
817 std::vector<PointPair> inPoints;
818 for (i = 0; i < niso; ++i)
820 for (id1 = 0; id1 < iso[i]->m_nvert; ++id1)
822 inPoints.push_back(PointPair(
823 BPoint(iso[i]->
m_x[id1], iso[i]->
m_y[id1], iso[i]->
m_z[id1]),
825 global_to_unique_map[id2] = id2;
826 global_to_iso_map[id2] = make_pair(i, id1);
833 cout <<
"\t Process building tree ..." << endl;
837 bgi::rtree<PointPair, bgi::rstar<16>> rtree;
838 rtree.insert(inPoints.begin(), inPoints.end());
841 int unique_index = 0;
851 BPoint queryPoint = inPoints[i].first;
855 if (global_to_unique_map[i] < unique_index)
861 std::vector<PointPair> result;
862 rtree.query(bgi::nearest(queryPoint, 10),
863 std::back_inserter(result));
868 for (id1 = 0; id1 < result.size(); ++id1)
870 NekDouble dist = bg::distance(queryPoint, result[id1].first);
873 id2 = result[id1].second;
876 if (global_to_unique_map[id2] < unique_index)
878 new_index = global_to_unique_map[id2];
884 new_index = unique_index;
889 global_to_unique_map[i] = new_index;
890 for (
auto &it : samept)
892 global_to_unique_map[it] = new_index;
907 for (n = 0; n < niso; ++n)
909 for (i = 0; i < iso[n]->m_ntris; ++i, nelmt++)
911 for (j = 0; j < 3; ++j)
913 m_vid[3 * nelmt + j] =
914 global_to_unique_map[iso[n]->m_vid[3 * i + j] + cnt];
917 cnt += iso[n]->m_nvert;
927 for (i = 0; i < iso[0]->m_fields.size(); ++i)
932 for (n = 0; n < global_to_unique_map.size(); ++n)
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);
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)
943 m_fields[j][global_to_unique_map[n]] =
944 iso[isoid]->m_fields[j][ptid];
977 vector<vector<int>> adj, vertcon;
978 vector<vector<NekDouble>> wght;
984 for (j = 0; j < 3; ++j)
986 vertcon[
m_vid[3 * i + j]].push_back(i);
997 for (
auto &ipt : vertcon[i])
999 for (j = 0; j < 3; ++j)
1002 if (
m_vid[3 * ipt + j] != i)
1005 for (k = 0; k < adj[i].size(); ++k)
1007 if (adj[i][k] ==
m_vid[3 * ipt + j])
1013 if (k == adj[i].size())
1015 adj[i].push_back(
m_vid[3 * ipt + j]);
1026 for (j = 0; j < adj[i].size(); ++j)
1028 wght[i].push_back(
w);
1037 for (iter = 0; iter < n_iter; iter++)
1042 del_v[0] = del_v[1] = del_v[2] = 0.0;
1043 for (j = 0; j < adj[i].size(); ++j)
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];
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;
1058 del_v[0] = del_v[1] = del_v[2] = 0;
1059 for (j = 0; j < adj[i].size(); ++j)
1062 del_v[0] + (xtemp[adj[i][j]] - xtemp[i]) * wght[i][j];
1064 del_v[1] + (ytemp[adj[i][j]] - ytemp[i]) * wght[i][j];
1066 del_v[2] + (ztemp[adj[i][j]] - ztemp[i]) * wght[i][j];
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;
1088 for (j = 0; j < 3; ++j)
1090 vertcon[
m_vid[3 * i + j]].push_back(i);
1105 k,
m_nvert,
"Separating regions", progcnt);
1108 if (vidregion[k] == -1)
1110 vidregion[k] = ++nregions;
1113 for (
auto &ipt : vertcon[k])
1115 for (i = 0; i < 3; ++i)
1117 if (vidregion[
id =
m_vid[3 * ipt + i]] == -1)
1119 tocheck.push_back(
id);
1120 vidregion[id] = nregions;
1127 while (tocheck.size())
1129 auto cid = tocheck.begin();
1130 while (cid != tocheck.end())
1134 for (
auto &ipt : vertcon[*cid])
1136 for (i = 0; i < 3; ++i)
1138 if (vidregion[
id =
m_vid[3 * ipt + i]] == -1)
1140 tocheck.push_back(
id);
1141 vidregion[id] = nregions;
1147 tocheck.pop_front();
1161 nvert[vidregion[i]] += 1;
1167 nelmt[vidregion[
m_vid[3 * i]]] += 1;
1172 for (
int n = 0; n < nregions; ++n)
1174 if (nelmt[n] > minsize)
1179 iso->m_ntris = nelmt[n];
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]);
1187 iso->m_fields.resize(nfields);
1188 for (i = 0; i < nfields; ++i)
1190 iso->m_fields[i].resize(nvert[n]);
1198 if (vidregion[i] == n)
1207 if (vidregion[
m_vid[3 * i]] == n)
1209 for (j = 0; j < 3; ++j)
1211 iso->m_vid[3 * cnt + j] = vidmap[
m_vid[3 * i + j]];
1213 iso->m_x[vidmap[
m_vid[3 * i + j]]] =
1215 iso->m_y[vidmap[
m_vid[3 * i + j]]] =
1217 iso->m_z[vidmap[
m_vid[3 * i + j]]] =
1220 for (k = 0; k < nfields; ++k)
1222 iso->m_fields[k][vidmap[
m_vid[3 * i + j]]] =
1230 WARNINGL0(cnt == nelmt[n],
"Number of elements do not match");
1231 sep_iso.push_back(iso);
#define ASSERTL0(condition, msg)
#define WARNINGL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
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
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.
std::map< std::string, ConfigOption > m_config
List of configuration values.
std::vector< IsoSharedPtr > ExtractContour(const int fieldid, const NekDouble val)
void SetupIsoFromFieldPts(std::vector< IsoSharedPtr > &isovec)
static ModuleKey className
void ResetFieldPts(std::vector< IsoSharedPtr > &iso)
static std::shared_ptr< Module > create(FieldSharedPtr f)
Creates an instance of this class.
virtual void v_Process(po::variables_map &vm) override
Write mesh to output file.
virtual ~ProcessIsoContour()
Abstract base class for processing modules.
Interpreter class for the evaluation of mathematical expressions.
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.
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< Field > FieldSharedPtr
std::pair< ModuleType, std::string > ModuleKey
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()
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
static const NekDouble kNekZeroTol
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
std::vector< double > w(NPUPPER)
The above copyright notice and this permission notice shall be included.
void Zero(int n, T *x, const int incx)
Zero vector.
Represents a command-line configuration option.