19 #include "GmshConfig.h"
35 #if defined(HAVE_POST)
40 #if defined(WIN32) && !defined(__CYGWIN__)
53 for(
auto it =
options.begin(); it !=
options.end(); ++it)
delete it->second;
60 auto it =
options.find(optionName);
62 Msg::Error(
"Field option '%s' does not exist", optionName.c_str());
70 for(
auto it = begin(); it != end(); it++) {
delete it->second; }
77 if(it == end())
return nullptr;
83 if(find(
id) != end()) {
84 Msg::Error(
"Field id %i is already defined",
id);
88 Msg::Error(
"Unknown field type \"%s\"", type_name.c_str());
92 if(!
f)
return nullptr;
104 while(it != end() && it->first < i) it++;
105 if(it == end() || it->first != i)
break;
107 return std::max(i, 1);
113 return rbegin()->first;
122 Msg::Error(
"Cannot delete field id %i, it does not exist",
id);
153 "True for ASCII input files, false for binary files (4 bite "
154 "signed integers for n, double precision floating points for v, D and O)",
158 "the last values of the grid are used.");
160 _outsideValue,
"Value of the field outside the grid (only used if the "
161 "\"SetOutsideValue\" option is true).");
165 return "Linearly interpolate between data provided on a 3D rectangular "
166 "structured grid.\n\n"
167 "The format of the input file is:\n\n"
171 " v(0,0,0) v(0,0,1) v(0,0,2) ... \n"
172 " v(0,1,0) v(0,1,1) v(0,1,2) ... \n"
173 " v(0,2,0) v(0,2,1) v(0,2,2) ... \n"
175 " v(1,0,0) ... ... \n\n"
176 "where O are the coordinates of the first node, D are the distances "
177 "between nodes in each direction, n are the numbers of nodes in "
178 "each direction, and v are the values on each node.";
180 const char *
getName() {
return "Structured"; }
185 using Field::operator();
196 if(!
input.is_open()) {
200 input.exceptions(std::ifstream::eofbit | std::ifstream::failbit |
201 std::ifstream::badbit);
203 input.read((
char *)
_o, 3 *
sizeof(
double));
204 input.read((
char *)
_d, 3 *
sizeof(
double));
205 input.read((
char *)
_n, 3 *
sizeof(
int));
206 int nt =
_n[0] *
_n[1] *
_n[2];
208 Msg::Error(
"Field %i: invalid number of data points %d x %d x %d",
209 this->
id, _n[0],
_n[1],
_n[2]);
213 _data =
new double[nt];
214 input.read((
char *)
_data, nt *
sizeof(
double));
219 int nt =
_n[0] *
_n[1] *
_n[2];
221 Msg::Error(
"Field %i: invalid number of data points %d x %d x %d",
222 this->
id, _n[0],
_n[1],
_n[2]);
226 _data =
new double[nt];
227 for(
int i = 0; i < nt; i++) input >>
_data[i];
232 Msg::Error(
"Field %i: error reading file '%s'", this->
id,
235 for(
int i = 0; i < 3; i++) {
237 if(
_n[i] == 1 && !
_d[i])
_d[i] = 1.;
239 if(!
_d[0] || !
_d[1] || !
_d[2]) {
240 Msg::Error(
"Field %i: Dx, Dy and Dz should be non zero", this->
id);
245 if(_errorStatus)
return MAX_LC;
249 double xyz[3] = {x, y,
z};
250 for(
int i = 0; i < 3; i++) {
251 id[0][i] = (int)floor((xyz[i] -
_o[i]) /
_d[i]);
252 id[1][i] =
id[0][i] + 1;
255 id[0][i] = std::max(std::min(
id[0][i],
_n[i] - 1), 0);
256 id[1][i] = std::max(std::min(
id[1][i],
_n[i] - 1), 0);
257 xi[i] = (xyz[i] - (
_o[i] +
id[0][i] *
_d[i])) /
_d[i];
258 xi[i] = std::max(std::min(xi[i], 1.), 0.);
261 for(
int i = 0; i < 2; i++)
262 for(
int j = 0; j < 2; j++)
263 for(
int k = 0; k < 2; k++) {
264 v +=
_data[
id[i][0] *
_n[1] *
_n[2] +
id[j][1] *
_n[2] +
id[k][2]] *
265 (i * xi[0] + (1 - i) * (1 - xi[0])) *
266 (j * xi[1] + (1 - j) * (1 - xi[1])) *
267 (k * xi[2] + (1 - k) * (1 - xi[2]));
281 return "Evaluate Field[InField] in geographic coordinates (longitude, "
283 " F = Field[InField](atan(y / x), asin(z / sqrt(x^2 + y^2 + z^2))";
294 _fromStereo,
"If = 1, the mesh is in stereographic coordinates: "
295 "xi = 2Rx/(R+z), eta = 2Ry/(R+z)");
297 _stereoRadius,
"Radius of the sphere of the stereograpic coordinates");
304 using Field::operator();
317 x = 4 * r2 * xi / (4 * r2 + xi * xi + eta * eta);
318 y = 4 * r2 * eta / (4 * r2 + xi * xi + eta * eta);
320 (4 * r2 + xi * xi + eta * eta);
333 return "Return VIn inside the box, and VOut outside. The box is defined "
335 " Xmin <= x <= XMax &&\n"
336 " YMin <= y <= YMax &&\n"
337 " ZMin <= z <= ZMax\n\n"
338 "If Thickness is > 0, the mesh size is interpolated between VIn and "
339 "VOut in a layer around the box of the prescribed thickness.";
361 _thick,
"Thickness of a transition layer outside the box");
364 using Field::operator();
372 double nx[3] = {x1[0] - x0[0], x1[1] - x0[1], x1[2] - x0[2]};
373 double ny[3] = {y1[0] - x0[0], y1[1] - x0[1], y1[2] - x0[2]};
374 double nz[3] = {z1[0] - x0[0], z1[1] - x0[1], z1[2] - x0[2]};
375 double pvect[3] = {xp - x0[0], yp - x0[1], zp - x0[2]};
378 if(tempX) projX /= tempX;
381 if(tempY) projY /= tempY;
384 if(tempZ) projZ /= tempZ;
385 if(projX < 0.0) projX = 0.0;
386 if(projX > 1.0) projX = 1.0;
387 if(projY < 0.0) projY = 0.0;
388 if(projY > 1.0) projY = 1.0;
389 if(projZ < 0.0) projZ = 0.0;
390 if(projZ > 1.0) projZ = 1.0;
391 double psbox[3] = {x0[0] + projX * nx[0] + projY * ny[0] + projZ * nz[0],
392 x0[1] + projX * nx[1] + projY * ny[1] + projZ * nz[1],
393 x0[2] + projX * nx[2] + projY * ny[2] + projZ * nz[2]};
395 sqrt(std::pow((psbox[0] - xp), 2) + std::pow((psbox[1] - yp), 2) +
396 std::pow((psbox[2] - zp), 2));
402 if(x >=
_xMin && x <= _xMax && y >=
_yMin && y <= _yMax && z >=
_zMin &&
425 return "Return VIn inside a frustrated cylinder, and VOut outside. "
426 "The cylinder is defined by\n\n"
427 " ||dX||^2 < R^2 &&\n"
428 " (X-X0).A < ||A||^2\n"
429 " dX = (X - X0) - ((X - X0).A)/(||A||^2) . A";
455 using Field::operator();
469 return ((dx * dx + dy * dy + dz * dz <
_r *
_r) && fabs(adx) < 1) ?
_vIn :
483 return "Return VIn inside a spherical ball, and VOut outside. "
484 "The ball is defined by\n\n"
485 " ||dX||^2 < R^2 &&\n"
486 " dX = (X - XC)^2 + (Y-YC)^2 + (Z-ZC)^2\n\n"
487 "If Thickness is > 0, the mesh size is interpolated between VIn and "
488 "VOut in a layer around the ball of the prescribed thickness.";
505 _thick,
"Thickness of a transition layer outside the ball");
508 using Field::operator();
514 double d = sqrt(dx * dx + dy * dy + dz * dz);
518 double dist = d -
_r;
535 return "Interpolate mesh sizes on a extended cylinder frustrum defined "
536 "by inner (R1i and R2i) and outer (R1o and R2o) radii and two "
537 "endpoints P1 and P2."
538 "The field value F for a point P is given by :\n\n"
539 " u = P1P . P1P2 / ||P1P2|| \n"
540 " r = || P1P - u*P1P2 || \n"
541 " Ri = (1 - u) * R1i + u * R2i \n"
542 " Ro = (1 - u) * R1o + u * R2o \n"
543 " v = (r - Ri) / (Ro - Ri) \n"
544 " F = (1 - v) * ((1 - u) * v1i + u * v2i) + "
545 " v * ((1 - u) * v1o + u * v2o)\n"
546 "with (u, v) in [0, 1] x [0, 1].";
600 using Field::operator();
609 double l12 = sqrt(x12 * x12 + y12 * y12 + z12 * z12);
611 double l = (dx * x12 + dy * y12 + dz * z12) / l12;
612 double r = sqrt(dx * dx + dy * dy + dz * dz - l * l);
615 double ri = (1 - u) *
_r1i + u *
_r2i;
616 double ro = (1 - u) *
_r1o + u *
_r2o;
617 double v = (r - ri) / (ro - ri);
620 if(u >= 0 && u <= 1 && v >= 0 && v <= 1) {
635 virtual const char *
getName() {
return "Threshold"; }
638 return "Return F = SizeMin if Field[InField] <= DistMin, "
639 "F = SizeMax if Field[InField] >= DistMax, and "
640 "the interpolation between SizeMin and SizeMax if DistMin < "
641 "Field[InField] < DistMax.";
655 "value, usually a distance");
657 _dMin,
"Value up to which the mesh size will be SizeMin");
659 _dMax,
"Value after which the mesh size will be SizeMax");
666 "True to interpolate between SizeMin and LcMax using a sigmoid, "
667 "false to interpolate linearly");
669 _stopAtDistMax,
"True to not impose mesh size outside DistMax (i.e., "
670 "F = a very big value if Field[InField] > DistMax)");
680 using Field::operator();
689 double d = (*field)(x, y,
z);
692 r = std::max(std::min(r, 1.), 0.);
695 double s = exp(12. * r - 6.) / (1. + exp(12. * r - 6.));
714 return "Compute the finite difference gradient of Field[InField]:\n\n"
715 " F = (Field[InField](X + Delta/2) - "
716 " Field[InField](X - Delta/2)) / Delta";
727 "Component of the gradient to evaluate: 0 for X, 1 for Y, 2 for Z, "
735 using Field::operator();
747 return ((*field)(x +
_delta / 2, y,
z) - (*field)(x -
_delta / 2, y,
z)) /
750 return ((*field)(x, y +
_delta / 2,
z) - (*field)(x, y -
_delta / 2,
z)) /
753 return ((*field)(x, y,
z +
_delta / 2) - (*field)(x, y,
z -
_delta / 2)) /
756 gx = ((*field)(x +
_delta / 2, y,
z) - (*field)(x -
_delta / 2, y,
z)) /
758 gy = ((*field)(x, y +
_delta / 2,
z) - (*field)(x, y -
_delta / 2,
z)) /
760 gz = ((*field)(x, y,
z +
_delta / 2) - (*field)(x, y,
z -
_delta / 2)) /
762 return sqrt(gx * gx + gy * gy + gz * gz);
764 Msg::Error(
"Field %i: unknown kind (%i) of gradient", this->
id, _kind);
779 return "Compute the curvature of Field[InField]:\n\n"
780 " F = div(norm(grad(Field[InField])))";
800 double n = sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
805 using Field::operator();
821 return (grad[0][0] - grad[1][0] + grad[2][1] - grad[3][1] + grad[4][2] -
833 const char *
getName() {
return "MaxEigenHessian"; }
836 return "Compute the maximum eigenvalue of the Hessian matrix of "
837 "Field[InField], with the gradients evaluated by finite "
839 " F = max(eig(grad(grad(Field[InField]))))";
854 using Field::operator();
863 double mat[3][3], eig[3];
864 mat[1][0] = mat[0][1] = (*field)(x +
_delta / 2, y +
_delta / 2,
z) +
868 mat[2][0] = mat[0][2] = (*field)(x +
_delta / 2, y,
z +
_delta / 2) +
872 mat[2][1] = mat[1][2] = (*field)(x, y +
_delta / 2,
z +
_delta / 2) +
876 double f = (*field)(x, y,
z);
877 mat[0][0] = (*field)(x +
_delta, y,
z) + (*field)(x -
_delta, y,
z) - 2 *
f;
878 mat[1][1] = (*field)(x, y +
_delta,
z) + (*field)(x, y -
_delta,
z) - 2 *
f;
879 mat[2][2] = (*field)(x, y,
z +
_delta) + (*field)(x, y,
z -
_delta) - 2 *
f;
894 return "Compute finite difference the Laplacian of Field[InField]:\n\n"
895 " F = G(x+d,y,z) + G(x-d,y,z) +\n"
896 " G(x,y+d,z) + G(x,y-d,z) +\n"
897 " G(x,y,z+d) + G(x,y,z-d) - 6 * G(x,y,z),\n\n"
898 "where G = Field[InField] and d = Delta.";
912 using Field::operator();
924 6 * (*field)(x, y,
z)) /
938 return "Return the mean value\n\n"
939 " F = (G(x + delta, y, z) + G(x - delta, y, z) +\n"
940 " G(x, y + delta, z) + G(x, y - delta, z) +\n"
941 " G(x, y, z + delta) + G(x, y, z - delta) +\n"
942 " G(x, y, z)) / 7,\n\n"
943 "where G = Field[InField].";
958 using Field::operator();
991 while(i <
f.size()) {
995 while(i + 1 + j <
f.size() &&
f[i + 1 + j] >=
'0' &&
996 f[i + 1 + j] <=
'9') {
1001 _fields.insert(atoi(
id.c_str()));
1006 std::vector<std::string> expressions(1), variables(3 +
_fields.size());
1013 std::ostringstream sstream;
1014 sstream <<
"F" << *it;
1015 variables[i++] = sstream.str();
1019 if(expressions.empty()) {
1029 std::vector<double> values(3 +
_fields.size()), res(1);
1037 values[i++] = (*field)(x, y,
z);
1044 if(
_f->
eval(values, res))
1059 for(
int i = 0; i < 6; i++)
_f[i] =
nullptr;
1063 for(
int i = 0; i < 6; i++)
1064 if(
_f[i])
delete _f[i];
1071 while(i <
f.size()) {
1075 while(i + 1 + j <
f.size() &&
f[i + 1 + j] >=
'0' &&
1076 f[i + 1 + j] <=
'9') {
1080 _fields[iFunction].insert(atoi(
id.c_str()));
1084 std::vector<std::string> expressions(1),
1085 variables(3 +
_fields[iFunction].size());
1091 for(
auto it =
_fields[iFunction].begin(); it !=
_fields[iFunction].end();
1093 std::ostringstream sstream;
1094 sstream <<
"F" << *it;
1095 variables[i++] = sstream.str();
1097 if(
_f[iFunction])
delete _f[iFunction];
1099 if(expressions.empty()) {
1100 delete _f[iFunction];
1101 _f[iFunction] =
nullptr;
1108 const int index[6][2] = {{0, 0}, {1, 1}, {2, 2}, {0, 1}, {0, 2}, {1, 2}};
1109 for(
int iFunction = 0; iFunction < 6; iFunction++) {
1111 metr(index[iFunction][0], index[iFunction][1]) =
MAX_LC;
1113 std::vector<double> values(3 +
_fields[iFunction].size()), res(1);
1118 for(
auto it =
_fields[iFunction].begin();
1119 it !=
_fields[iFunction].end(); it++) {
1122 values[i++] = (*field)(x, y,
z);
1129 if(
_f[iFunction]->eval(values, res))
1130 metr(index[iFunction][0], index[iFunction][1]) = res[0];
1132 metr(index[iFunction][0], index[iFunction][1]) =
MAX_LC;
1150 using Field::operator();
1154 #pragma omp critical
1158 Msg::Error(
"Field %i: invalid matheval expression \"%s\"", this->
id,
1169 return "Evaluate a mathematical expression. The expression can contain "
1170 "x, y, z for spatial coordinates, F0, F1, ... for field values, and "
1171 "mathematical functions.";
1184 _f[0] =
"F2 + Sin(z)";
1185 _f[1] =
"F2 + Sin(z)";
1186 _f[2] =
"F2 + Sin(z)";
1187 _f[3] =
"F2 + Sin(z)";
1188 _f[4] =
"F2 + Sin(z)";
1189 _f[5] =
"F2 + Sin(z)";
1221 #pragma omp critical
1224 for(
int i = 0; i < 6; i++) {
1226 Msg::Error(
"Field %i: invalid matheval expression \"%s\"", this->
id,
1237 #pragma omp critical
1240 for(
int i = 0; i < 6; i++) {
1242 Msg::Error(
"Field %i: invalid matheval expression \"%s\"", this->
id,
1254 return "Evaluate a metric expression. The expressions can contain "
1255 "x, y, z for spatial coordinates, F0, F1, ... for field values, and "
1256 "mathematical functions.";
1260 #if defined(WIN32) && !defined(__CYGWIN__)
1278 _hIn = _hOut =
nullptr;
1281 bool started()
const {
return _hIn; }
1282 bool start(
const char *command)
1285 HANDLE hChildStd_OUT_Wr, hChildStd_IN_Rd;
1286 PROCESS_INFORMATION piProcInfo;
1287 SECURITY_ATTRIBUTES saAttr;
1288 saAttr.nLength =
sizeof(SECURITY_ATTRIBUTES);
1289 saAttr.bInheritHandle =
TRUE;
1290 saAttr.lpSecurityDescriptor =
nullptr;
1291 if(!CreatePipe(&_hIn, &hChildStd_OUT_Wr, &saAttr, 0))
1293 if(!CreatePipe(&hChildStd_IN_Rd, &_hOut, &saAttr, 0))
1295 if(!CreatePipe(&_hIn, &hChildStd_OUT_Wr, &saAttr, 0))
1297 if(!SetHandleInformation(_hIn, HANDLE_FLAG_INHERIT, 0))
1299 STARTUPINFO siStartInfo;
1300 BOOL bSuccess =
FALSE;
1301 ZeroMemory(&piProcInfo,
sizeof(PROCESS_INFORMATION));
1302 ZeroMemory(&siStartInfo,
sizeof(STARTUPINFO));
1303 siStartInfo.cb =
sizeof(STARTUPINFO);
1304 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1305 siStartInfo.hStdOutput = hChildStd_OUT_Wr;
1306 siStartInfo.hStdInput = hChildStd_IN_Rd;
1307 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
1308 bSuccess = CreateProcess(
nullptr, (
char *)command,
nullptr,
nullptr,
TRUE,
1309 0,
nullptr,
nullptr, &siStartInfo, &piProcInfo);
1311 Msg::Error(
"Child process creation failed %i", GetLastError());
1312 _hIn = _hOut =
nullptr;
1315 CloseHandle(piProcInfo.hProcess);
1316 CloseHandle(piProcInfo.hThread);
1319 bool read(
void *data,
size_t size)
1321 if(!_hIn)
return false;
1323 ReadFile(_hIn, data, size, &nSuccess,
nullptr);
1324 return nSuccess == size;
1326 bool write(
void *data,
size_t size)
1328 if(!_hOut)
return false;
1330 WriteFile(_hOut, data, size, &nSuccess,
nullptr);
1331 return nSuccess == size;
1356 int p_stdin[2], p_stdout[2];
1357 if(pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return false;
1363 dup2(p_stdin[0], 0);
1365 dup2(p_stdout[1], 1);
1366 execl(
"/bin/sh",
"sh",
"-c", command,
nullptr);
1371 _fdIn = p_stdout[0];
1376 return ::read(
_fdIn, data, size) == (ssize_t)size;
1380 return ::write(
_fdOut, data, size) == (ssize_t)size;
1393 double xyz[3] = {std::numeric_limits<double>::quiet_NaN(),
1394 std::numeric_limits<double>::quiet_NaN(),
1395 std::numeric_limits<double>::quiet_NaN()};
1410 using Field::operator();
1413 double xyz[3] = {x, y,
z};
1420 if(!
_pipes.
write((
void *)xyz, 3 *
sizeof(
double)) ||
1426 const char *
getName() {
return "ExternalProcess"; }
1429 return "**This Field is experimental**\n"
1430 "Call an external process that received coordinates triple (x,y,z) "
1431 "as binary double precision numbers on stdin and is supposed to "
1433 "field value on stdout as a binary double precision number.\n"
1434 "NaN,NaN,NaN is sent as coordinate to indicate the end of the "
1437 "Example of client (python2):\n"
1442 "if sys.platform == \"win32\" :\n"
1444 " msvcrt.setmode(0, os.O_BINARY)\n"
1445 " msvcrt.setmode(1, os.O_BINARY)\n"
1447 " xyz = struct.unpack(\"ddd\", os.read(0,24))\n"
1448 " if math.isnan(xyz[0]):\n"
1450 " f = 0.001 + xyz[1]*0.009\n"
1451 " os.write(1,struct.pack(\"d\",f))\n"
1453 "Example of client (python3):\n"
1458 " xyz = struct.unpack(\"ddd\", sys.stdin.buffer.read(24))\n"
1459 " if math.isnan(xyz[0]):\n"
1461 " f = 0.001 + xyz[1]*0.009\n"
1462 " sys.stdout.buffer.write(struct.pack(\"d\",f))\n"
1463 " sys.stdout.flush()\n"
1465 "Example of client (c, unix):\n"
1466 "#include <unistd.h>\n"
1467 "int main(int argc, char **argv) {\n"
1469 " while(read(STDIN_FILENO, &xyz, 3*sizeof(double)) == "
1470 "3*sizeof(double)) {\n"
1471 " if (xyz[0] != xyz[0]) break; //nan\n"
1472 " double f = 0.001 + 0.009 * xyz[1];\n"
1473 " write(STDOUT_FILENO, &f, sizeof(double));\n"
1478 "Example of client (c, windows):\n"
1479 "#include <stdio.h>\n"
1481 "#include <fcntl.h>\n"
1482 "int main(int argc, char **argv) {\n"
1484 " setmode(fileno(stdin),O_BINARY);\n"
1485 " setmode(fileno(stdout),O_BINARY);\n"
1486 " while(read(fileno(stdin), &xyz, 3*sizeof(double)) == "
1487 "3*sizeof(double)) {\n"
1488 " if (xyz[0] != xyz[0])\n"
1490 " double f = f = 0.01 + 0.09 * xyz[1];\n"
1491 " write(fileno(stdout), &f, sizeof(double));\n"
1522 return "Evaluate Field[InField] in parametric coordinates:\n\n"
1523 " F = Field[InField](FX,FY,FZ)\n\n"
1524 "See the MathEval Field help to get a description of valid FX, FY "
1525 "and FZ expressions.";
1527 using Field::operator();
1531 for(
int i = 0; i < 3; i++) {
1532 if(!
_expr[i].set_function(
_f[i]))
1533 Msg::Error(
"Field %i: invalid matheval expression \"%s\"", this->
id,
1550 #if defined(HAVE_POST)
1552 class PostViewField :
public Field {
1554 int _viewIndex, _viewTag;
1555 bool _cropNegativeValues, _useClosest;
1562 _cropNegativeValues =
true;
1565 options[
"ViewIndex"] =
1567 options[
"ViewTag"] =
1570 _cropNegativeValues,
"return MAX_LC instead of a negative value (this "
1571 "option is needed for backward compatibility with "
1572 "the BackgroundMesh option");
1573 options[
"UseClosest"] =
1575 "no exact match is found");
1584 PView *getView()
const
1590 Msg::Error(
"View with tag %d does not exist", _viewTag);
1594 if(_viewIndex < 0 || _viewIndex >= (
int)
PView::list.size()) {
1595 Msg::Error(
"View with index %d does not exist", _viewIndex);
1602 "Cannot use view based on current mesh for background mesh: you might"
1603 " want to use a list-based view (.pos file) instead");
1610 PView *v = getView();
1616 PView *v = getView();
1624 PView *v = getView();
1626 double dist = _useClosest ? -1. : 0.;
1630 Msg::Warning(
"No vector element found containing point "
1631 "(%g,%g,%g) in PostView field (for norm)", x, y,
z);
1634 l = sqrt(values[0] * values[0] + values[1] * values[1] +
1635 values[2] * values[2]);
1640 Msg::Warning(
"No scalar element found containing point "
1641 "(%g,%g,%g) in PostView field", x, y,
z);
1645 Msg::Warning(
"No vector or scalar value found in PostView field");
1648 if(l <= 0 && _cropNegativeValues)
return MAX_LC;
1653 PView *vie = getView();
1660 double dist = _useClosest ? -1. : 0.;
1664 Msg::Warning(
"No vector element found containing point "
1665 "(%g,%g,%g) in PostView field", x, y,
z);
1668 v =
SVector3(values[0], values[1], values[2]);
1672 Msg::Warning(
"No vector value found in PostView field");
1678 PView *v = getView();
1680 double dist = _useClosest ? -1. : 0.;
1681 double l[9] = {0., 0., 0., 0., 0., 0., 0., 0., 0.};
1683 Msg::Warning(
"No tensor element found containing point "
1684 "(%g,%g,%g) in PostView field", x, y,
z);
1698 const char *
getName() {
return "PostView"; }
1701 return "Evaluate the post processing view with index ViewIndex, or "
1702 "with tag ViewTag if ViewTag is positive.";
1721 return "Take the intersection of a list of possibly anisotropic fields.";
1731 if(
f && *it !=
id) {
1732 if(
f->isotropic()) {
1733 double l = (*f)(x, y,
z, ge);
1737 (*f)(x, y,
z, ff, ge);
1752 if(
f && *it !=
id) {
1753 if(!
f->isotropic()) { (*f)(x, y,
z, m, ge); }
1755 double L = (*f)(x, y,
z, ge);
1756 for(
int i = 0; i < 3; i++) m(i, i) = 1. / (L * L);
1764 double val = sqrt(1. /
S(2));
1765 return std::min(v, val);
1783 return "Take the intersection of 2 anisotropic fields according to "
1795 if(
f && *it !=
id) {
1796 if(
f->isotropic()) {
1797 double l = (*f)(x, y,
z, ge);
1801 (*f)(x, y,
z, ff, ge);
1819 if(
f && *it !=
id) {
1820 if(!
f->isotropic()) { (*f)(x, y,
z, m, ge); }
1822 double L = (*f)(x, y,
z, ge);
1823 for(
int i = 0; i < 3; i++) m(i, i) = 1. / (L * L);
1834 return sqrt(1. /
S(2));
1836 const char *
getName() {
return "IntersectAniso"; }
1852 return "Take the minimum value of a list of fields.";
1854 using Field::operator();
1857 #pragma omp critical
1864 if(
f && *it !=
id)
_fields.push_back(
f);
1873 v = std::min(v, (*
f)(x, y,
z, ge));
1876 (*f)(x, y,
z, ff, ge);
1880 v = std::min(v, sqrt(1. /
S(2)));
1901 return "Take the maximum value of a list of fields.";
1903 using Field::operator();
1906 #pragma omp critical
1913 if(
f && *it !=
id)
_fields.push_back(
f);
1922 v = std::max(v, (*
f)(x, y,
z, ge));
1925 (*f)(x, y,
z, ff, ge);
1929 v = std::max(v, sqrt(1. /
S(0)));
1971 return "Restrict the application of a field to a given list of geometrical "
1972 "points, curves, surfaces or volumes (as well as their boundaries "
1973 "if IncludeBoundary is set).";
1975 using Field::operator();
1984 if(!ge)
return (*
f)(x, y,
z);
1993 return (*
f)(x, y,
z);
1995 if(ge->dim() <= 2) {
1996 std::list<GRegion *> volumes = ge->regions();
1997 for(
auto v : volumes) {
2002 if(ge->dim() <= 1) {
2003 std::vector<GFace *> surfaces = ge->faces();
2004 for(
auto s : surfaces) {
2009 if(ge->dim() == 0) {
2010 std::vector<GEdge *> curves = ge->edges();
2011 for(
auto c : curves) {
2045 return "Return VIn when inside the entities (and on their boundary if "
2046 "IncludeBoundary is set), and VOut outside.";
2048 using Field::operator();
2062 if(ge->dim() <= 2) {
2063 std::list<GRegion *> volumes = ge->regions();
2064 for(
auto v : volumes) {
2069 if(ge->dim() <= 1) {
2070 std::vector<GFace *> surfaces = ge->faces();
2071 for(
auto s : surfaces) {
2076 if(ge->dim() == 0) {
2077 std::vector<GEdge *> curves = ge->edges();
2078 for(
auto c : curves) {
2098 #if defined(HAVE_ANN)
2100 class AttractorAnisoCurveField :
public Field {
2102 ANNkd_tree *_kdTree;
2103 ANNpointArray _zeroNodes;
2106 std::list<int> _curveTags;
2107 double _dMin, _dMax, _lMinTangent, _lMaxTangent, _lMinNormal, _lMaxNormal;
2109 std::vector<SVector3> _tg;
2112 AttractorAnisoCurveField() : _kdTree(
nullptr), _zeroNodes(
nullptr)
2114 _index =
new ANNidx[1];
2115 _dist =
new ANNdist[1];
2117 updateNeeded =
true;
2126 _curveTags,
"Tags of curves in the geometric model", &updateNeeded);
2128 _sampling,
"Number of sampling points on each curve",
2131 _dMin,
"Minimum distance, below this distance from the curves, "
2132 "prescribe the minimum mesh sizes");
2134 _dMax,
"Maxmium distance, above this distance from the curves, prescribe "
2135 "the maximum mesh sizes");
2137 _lMinTangent,
"Minimum mesh size in the direction tangeant to the "
2140 _lMaxTangent,
"Maximum mesh size in the direction tangeant to the "
2143 _lMinNormal,
"Minimum mesh size in the direction normal to the "
2146 _lMaxNormal,
"Maximum mesh size in the direction normal to the "
2150 options[
"EdgesList"] =
2152 options[
"NNodesByEdge"] =
2153 new FieldOptionInt(_sampling,
"[Deprecated]", &updateNeeded,
true);
2158 options[
"lMinTangent"] =
2160 options[
"lMaxTangent"] =
2162 options[
"lMinNormal"] =
2164 options[
"lMaxNormal"] =
2166 options[
"NumPointsPerCurve"] =
2167 new FieldOptionInt(_sampling,
"[Deprecated]", &updateNeeded,
true);
2172 virtual bool isotropic()
const {
return false; }
2173 ~AttractorAnisoCurveField()
2175 if(_kdTree)
delete _kdTree;
2176 if(_zeroNodes) annDeallocPts(_zeroNodes);
2180 const char *
getName() {
return "AttractorAnisoCurve"; }
2183 return "Compute the distance to the given curves and specify the mesh size "
2184 "independently in the direction normal and parallel to the nearest "
2185 "curve. For efficiency each curve is replaced by a set of Sampling "
2186 "points, to which the distance is actually computed.";
2191 annDeallocPts(_zeroNodes);
2194 int totpoints = _sampling * _curveTags.size();
2195 if(totpoints) { _zeroNodes = annAllocPts(totpoints, 3); }
2196 _tg.resize(totpoints);
2198 for(
auto it = _curveTags.begin(); it != _curveTags.end(); ++it) {
2201 for(
int i = 0; i < _sampling; i++) {
2202 double u = (double)i / (_sampling - 1);
2204 double t = b.
low() + u * (b.
high() - b.
low());
2207 _zeroNodes[k][0] = gp.
x();
2208 _zeroNodes[k][1] = gp.y();
2209 _zeroNodes[k][2] = gp.z();
2219 _kdTree =
new ANNkd_tree(_zeroNodes, totpoints, 3);
2220 updateNeeded =
false;
2225 if(updateNeeded)
update();
2226 double xyz[3] = {x, y,
z};
2227 #pragma omp critical // avoid crash (still incorrect) - use Distance instead
2228 _kdTree->annkSearch(xyz, 1, _index, _dist);
2229 double d = sqrt(_dist[0]);
2230 double lTg = d < _dMin ? _lMinTangent :
2231 d > _dMax ? _lMaxTangent :
2232 _lMinTangent + (_lMaxTangent - _lMinTangent) *
2233 (d - _dMin) / (_dMax - _dMin);
2234 double lN = d < _dMin ? _lMinNormal :
2235 d > _dMax ? _lMaxNormal :
2236 _lMinNormal + (_lMaxNormal - _lMinNormal) *
2237 (d - _dMin) / (_dMax - _dMin);
2242 metr =
SMetric3(1 / lTg / lTg, 1 / lN / lN, 1 / lN / lN, t, n0, n1);
2246 if(updateNeeded)
update();
2247 double xyz[3] = {X, Y, Z};
2248 #pragma omp critical // avoid crash (still incorrect) - use Distance instead
2249 _kdTree->annkSearch(xyz, 1, _index, _dist);
2250 double d = sqrt(_dist[0]);
2251 return std::max(d, 0.05);
2270 int i = x > 0.5 ? 1 : 0;
2271 int j = y > 0.5 ? 1 : 0;
2272 int k =
z > 0.5 ? 1 : 0;
2273 return sub[i * 4 + j * 2 + k].
evaluate(2 * x - i, 2 * y - j, 2 *
z - k);
2276 void init(
double x0,
double y0,
double z0,
double l,
Field &field,
2281 {field(x0, y0, z0), field(x0, y0, z0 + l), field(x0, y0 + l, z0),
2282 field(x0, y0 + l, z0 + l), field(x0 + l, y0, z0), field(x0 + l, y0, z0 + l),
2283 field(x0 + l, y0 + l, z0), field(x0 + l, y0 + l, z0 + l)};
2286 double vc = field(x0+l/2,y0+l/2,z0+l/2);
2287 for (
int i = 0; i < 8; ++i){
2288 dmax = std::max(dmax, std::abs(vc-v[i]));
2289 vmin = std::min(vmin, v[i]);
2293 double vc = field(x0 + l / 2, y0 + l / 2, z0 + l / 2);
2295 bool split = level > 0;
2299 for(
int i = 0; i <=
NSAMPLE; ++i) {
2300 for(
int j = 0; j <=
NSAMPLE; ++j) {
2301 for(
int k = 0; k <=
NSAMPLE; ++k) {
2302 double w = field(x0 + i * dl, y0 + j * dl, z0 + k * dl);
2303 dmax = std::max(dmax, std::abs(vc - w));
2304 vmin = std::min(vmin, w);
2305 split |= (dmax / vmin > 0.2 && vmin < l);
2316 sub[0].
init(x0, y0, z0, l2, field, level - 1);
2317 sub[1].
init(x0, y0, z0 + l2, l2, field, level - 1);
2318 sub[2].
init(x0, y0 + l2, z0, l2, field, level - 1);
2319 sub[3].
init(x0, y0 + l2, z0 + l2, l2, field, level - 1);
2320 sub[4].
init(x0 + l2, y0, z0, l2, field, level - 1);
2321 sub[5].
init(x0 + l2, y0, z0 + l2, l2, field, level - 1);
2322 sub[6].
init(x0 + l2, y0 + l2, z0, l2, field, level - 1);
2323 sub[7].
init(x0 + l2, y0 + l2, z0 + l2, l2, field, level - 1);
2324 _data = (
void *)sub;
2328 _data = (
void *)
new double;
2329 *(
double *)
_data = vc;
2340 void print(
double x0,
double y0,
double z0,
double l, FILE *
f)
2343 fprintf(
f,
"SP(%g, %g, %g) {%g};\n", x0 + l / 2, y0 + l / 2, z0 + l / 2,
2349 sub[0].
print(x0, y0, z0, l2,
f);
2350 sub[1].
print(x0, y0, z0 + l2, l2,
f);
2351 sub[2].
print(x0, y0 + l2, z0, l2,
f);
2352 sub[3].
print(x0, y0 + l2, z0 + l2, l2,
f);
2353 sub[4].
print(x0 + l2, y0, z0, l2,
f);
2354 sub[5].
print(x0 + l2, y0, z0 + l2, l2,
f);
2355 sub[6].
print(x0 + l2, y0 + l2, z0, l2,
f);
2356 sub[7].
print(x0 + l2, y0 + l2, z0 + l2, l2,
f);
2382 return "Pre compute another field on an octree to speed-up evalution.";
2402 _l0 = std::max(std::max(d.
x(), d.
y()), d.
z());
2412 (Z - xmin.
z()) /
_l0);
2428 const double d0 = p1[0] -
derived().pts[idx_p2].x();
2429 const double d1 = p1[1] -
derived().pts[idx_p2].y();
2430 const double d2 = p1[2] -
derived().pts[idx_p2].z();
2431 return d0 * d0 + d1 * d1 + d2 * d2;
2436 return derived().pts[idx].x();
2438 return derived().pts[idx].y();
2440 return derived().pts[idx].z();
2468 _surfaceTags,
"Tags of surfaces in the geometric model "
2469 "(only OpenCASCADE and discrete surfaces are currently supported)",
2472 _sampling,
"Linear (i.e. per dimension) number of sampling points to "
2490 options[
"NumPointsPerCurve"] =
2512 return "Compute the distance to the given points, curves or surfaces. "
2513 "For efficiency, curves and surfaces are replaced by a set "
2514 "of points (sampled according to Sampling), to which the distance "
2515 "is actually computed.";
2555 for(
int i = 1; i < NNN - 1; i++) {
2556 double u = (double)i / (NNN - 1);
2558 double t = b.
low() + u * (b.
high() - b.
low());
2572 double maxDist =
f->bounds().diag() /
_sampling;
2573 std::vector<SPoint2> uvpoints;
2574 f->fillPointCloud(maxDist, &
_pc.
pts, &uvpoints);
2575 for(std::size_t i = 0; i < uvpoints.size(); i++)
2591 using Field::operator();
2595 double pt[3] = {X, Y, Z};
2600 return sqrt(outDistSqr);
2624 _distMax,
"Maximum distance of the size extension");
2626 _sizeMax,
"Mesh size outside DistMax");
2628 _power,
"Power exponent used to interpolate the mesh size");
2638 return "Compute an extension of the mesh sizes from the given boundary "
2639 "curves (resp. surfaces) inside the surfaces (resp. volumes) "
2640 "being meshed. If the mesh size on the boundary, computed "
2641 "as the local average length of the edges of the boundary elements, "
2642 "is denoted by SizeBnd, the extension is computed as:\n\n"
2643 " F = f * SizeBnd + (1 - f) * SizeMax, if d < DistMax\n\n"
2644 " F = SizeMax, if d >= DistMax\n\n"
2645 "where d denotes the distance to the boundary and "
2646 "f = ((DistMax - d) / DistMax)^Power.";
2656 for(
auto e : ge->
lines) {
2684 double s = e->getEdge(0).
length() + e->getEdge(1).
length() +
2702 using Field::operator();
2706 if(ge->dim() != 2 && ge->dim() != 3)
return MAX_LC;
2709 #pragma omp critical
2718 #pragma omp critical
2728 double pt[3] = {X, Y, Z};
2730 std::size_t index = 0;
2731 double dist2 = 0., sbnd = 0.;
2732 res.
init(&index, &dist2);
2742 double d = sqrt(dist2);
2751 if(ge && ge->getMeshSizeFactor() != 1.0)
2752 sbnd /= ge->getMeshSizeFactor();
2763 return "Insert a 2D boundary layer mesh next to some curves in the model.";
2781 "Tags of curves in the geometric model for which a boundary "
2786 "Tags of points in the geometric model for which a fan "
2791 "Number of elements in the fan for each fan node. "
2792 "If not present default value Mesh.BoundaryLayerFanElements",
2796 "Tags of points in the geometric model for which a boundary "
2802 _hWallNNodes,
"Mesh size normal to the curve, per point (overwrites "
2803 "Size when defined)");
2811 iRecombine,
"Generate recombined elements in the boundary layer");
2815 tgtAnisoRatio,
"Threshold angle for creating a mesh fan in the boundary "
2818 betaLaw,
"Use Beta Law instead of geometric progression ");
2823 options[
"ExcludedSurfacesList"] =
2825 "Tags of surfaces in the geometric model where the "
2826 "boundary layer should not be constructed",
2918 std::vector<GEdge *> ed = gf->
edges();
2919 std::vector<GEdge *>
const &embedded_edges = gf->
embeddedEdges();
2920 ed.insert(ed.begin(), embedded_edges.begin(), embedded_edges.end());
2922 for(
auto it = ed.begin(); it != ed.end(); ++it) {
2924 int iE = (*it)->tag();
2929 std::vector<GFace *>
fc = (*it)->faces();
2931 for(
auto it =
fc.begin(); it !=
fc.end(); it++) {
2932 if((*it)->meshAttributes.extrude &&
2949 Msg::Error(
"Only 2D Boundary Layers are supported (curve %d is adjacet "
2956 if((*it)->getBeginVertex())
2957 _pointTags.push_back((*it)->getBeginVertex()->tag());
2958 if((*it)->getEndVertex())
2959 _pointTags.push_back((*it)->getEndVertex()->tag());
2979 double dist = 1.e22;
2982 double cdist = (*(*it))(x, y,
z);
2983 if(cdist < dist) { dist = cdist; }
2993 return std::min(
hFar, lc);
3000 double xpk = 0., ypk = 0., zpk = 0.;
3001 double distk = 1.e22;
3009 sqrt((x - xp) * (x - xp) + (y - yp) * (y - yp) + (
z - zp) * (
z - zp));
3022 const double ll1 = (distk * (
ratio - 1) +
hWallN) / (1. + 0.5 * (
ratio - 1));
3023 double lc_n = std::min(ll1,
hFar);
3048 double lc_n = std::min(ll1,
hFar);
3058 if(pp.first.dim == 0) {
3069 else if(pp.first.dim == 1) {
3078 const double b = lc_t;
3079 const double h = lc_n;
3083 sqrt(1. + (4. * crv * crv * b * b * b * b / (h * h *
beta *
beta))));
3105 const double b = lc_t;
3106 const double h = lc_n;
3107 double oneOverD2_min =
3110 sqrt(1. + (4. * cmin * cmin * b * b * b * b / (h * h *
beta *
beta))));
3111 double oneOverD2_max =
3114 sqrt(1. + (4. * cmax * cmax * b * b * b * b / (h * h *
beta *
beta))));
3115 double dmin = sqrt(1. / oneOverD2_min);
3116 double dmax = sqrt(1. / oneOverD2_max);
3145 std::vector<SMetric3> hop;
3149 double cdist = (*(*it))(x, y,
z);
3150 SPoint3 CLOSEST = (*it)->getAttractorInfo().second;
3153 (*this)(*it, cdist, x, y,
z, localMetric, ge);
3154 hop.push_back(localMetric);
3157 if(!
iIntersect) (*this)(*it, cdist, x, y,
z, localMetric, ge);
3165 for(std::size_t i = 0; i < hop.size(); i++)
3180 #if defined(HAVE_POST)
3201 #if defined(HAVE_ANN)
3214 for(; it != end(); ++it) it->second->update();
3221 for(
auto it = begin(); it != end(); it++)
delete it->second;
3233 #if defined(HAVE_POST)
3235 Msg::Error(
"No mesh available to create the view: please mesh your model!");
3238 std::map<int, std::vector<double> > d;
3239 std::vector<GEntity *> entities;
3241 for(std::size_t i = 0; i < entities.size(); i++) {
3242 for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); j++) {
3243 MVertex *v = entities[i]->mesh_vertices[j];
3244 d[v->
getNum()].push_back((*
this)(v->
x(), v->
y(), v->
z(), entities[i]));
3247 std::ostringstream oss;
3248 oss <<
"Field " <<
id;
3255 #if defined(HAVE_POST)
3256 void Field::putOnView(
PView *view,
int comp)
3262 for(
int nod = 0; nod < data->
getNumNodes(0, ent, ele); nod++) {
3264 data->
getNode(0, ent, ele, nod, x, y,
z);
3265 double val = (*this)(x, y,
z);
3267 data->
setValue(0, ent, ele, nod, comp, val);
3271 std::ostringstream oss;
3272 oss <<
"Field " <<
id;
3284 f->options[
"ViewIndex"]->numericalValue(iView);
3297 auto it = sizes.begin();
3302 bool ok = (itcbs->first)(x, y,
z, itcbs->second, (*it));
3303 if(!ok) {
Msg::Warning(
"GenericField error from callback"); }
3309 bool ok = (itcbs->first)(x, y,
z, ge, itcbs->second, (*it));
3310 if(!ok) {
Msg::Warning(
"GenericField error from callback"); }
3314 return (*std::min_element(sizes.begin(), sizes.end()));