netgen/libsrc/meshing/python_mesh.cpp

1825 lines
70 KiB
C++
Raw Normal View History

2014-08-31 19:05:24 +06:00
#ifdef NG_PYTHON
#include <regex>
2014-10-08 21:48:48 +06:00
#include <../general/ngpython.hpp>
#include <core/python_ngcore.hpp>
#include "python_mesh.hpp"
2014-08-30 06:15:59 +06:00
#include <mystdlib.h>
#include "meshing.hpp"
// #include <csg.hpp>
// #include <geometry2d.hpp>
2016-07-10 21:07:36 +05:00
#include <../interface/writeuser.hpp>
#include <../include/nginterface.h>
2021-10-13 21:24:05 +05:00
#include <../general/gzstream.h>
class ClearSolutionClass
{
public:
ClearSolutionClass() { }
~ClearSolutionClass() { Ng_ClearSolutionData(); }
};
2014-08-30 06:15:59 +06:00
2020-07-29 20:18:12 +05:00
#ifdef NG_MPI4PY
#include <mpi4py.h>
struct mpi4py_comm {
mpi4py_comm() = default;
mpi4py_comm(MPI_Comm value) : value(value) {}
operator MPI_Comm () { return value; }
MPI_Comm value;
};
namespace pybind11 { namespace detail {
template <> struct type_caster<mpi4py_comm> {
public:
PYBIND11_TYPE_CASTER(mpi4py_comm, _("mpi4py_comm"));
// Python -> C++
bool load(handle src, bool) {
PyObject *py_src = src.ptr();
// Check that we have been passed an mpi4py communicator
if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) {
// Convert to regular MPI communicator
value.value = *PyMPIComm_Get(py_src);
} else {
return false;
}
return !PyErr_Occurred();
}
// C++ -> Python
static handle cast(mpi4py_comm src,
return_value_policy /* policy */,
handle /* parent */)
{
// Create an mpi4py handle
return PyMPIComm_New(src.value);
}
};
}} // namespace pybind11::detail
#endif // NG_MPI4PY
2014-08-30 06:15:59 +06:00
using namespace netgen;
Cleanup CMake build system - Use CMAKE_INSTALL_PREFIX instead of INSTALL_DIR - Allow finer control of install directories - Use compiled TCL code by default - Fix RPATH usage on Linux and MacOSX ### Allow finer control of install directories The following variables can be set to either absolute or relative paths NG_INSTALL_DIR_PYTHON: Python files NG_INSTALL_DIR_BIN: Executables NG_INSTALL_DIR_LIB: Libraries NG_INSTALL_DIR_INCLUDE: header files NG_INSTALL_DIR_CMAKE: CMake files NG_INSTALL_DIR_RES: Resources ### Use compiled TCL code by default The tcl files contained in Netgen are stored in onetcl.cpp as c-string. This way it's not necessary to install tcl files or set NETGENDIR ### Fix RPATH usage on Linux and MacOSX The Netgen installation should be completely relocatable now. Squashed commit of the following: commit 201eda5e62726bd87d76beb13c3e5643cd4c7810 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 21:10:08 2017 +0200 cleanup commit b4cd46a9d2f390b40c5223c8d9971f576b979644 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:47:46 2017 +0200 fix commit 6506a834dbee2fd7b6df3b3f3709d0b27344356f Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:41:45 2017 +0200 allow gui test to fail commit 56c5fc131f61259e6fb67b60f7fff955d2e8d2da Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:26:18 2017 +0200 add python3-tk to docker images commit 4d1b5aac1d028867339819599708a08f2098bbd6 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:22:18 2017 -0700 windows fix commit 92b5f8a95491ba3508143d7f1b94359edc0655ce Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:08:08 2017 -0700 fix for windows commit 3f7bf51434ef3b637b3563930ddb61d04af645cb Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 19:28:13 2017 +0200 fixes, test for gui commit ef1d0164a50fadf374e3b1e43a745b5f69a16ad6 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 19:06:55 2017 +0200 fixes commit 67645bb896012149c23c851b03287199c21fa129 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 17:24:58 2017 +0200 netgen config commit b587b77a282768719cffc366c56d82a1746e0be0 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 16:53:47 2017 +0200 remove comments commit 2b34cc78818afa1cf21484bd0976413a91db0851 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 05:03:00 2017 -0700 fix windows commit 9e98efa54065624e264eaf1acf74b44ef022a68d Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 13:42:11 2017 +0200 fixes commit 394b470a07d73431079f80caa36c7c7042077f40 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 12:24:40 2017 +0200 fix rpath issue commit 6787eae384a8592f90598258ccd8207cd499d9fc Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:37:05 2017 +0200 some more fixes with install dir commit fcf22659c60300e8d39d12e14b21c58a062e739c Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 01:34:06 2017 -0700 some fixes commit ede1f0c462978bb70d3b4e2251cb555a592e82e3 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 10:16:34 2017 +0200 fixes commit b6a1259876a77f54e419a44f1b44d03d5bb49b82 Merge: c79f9a3 6627b0b Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Wed May 24 09:35:50 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit c79f9a3421d4d2937c31dab4a601ce09d52b0e54 Merge: 99c3550 030ad1d Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 22 17:52:24 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit 99c35500850e08fdc847013bb384169b1483acb4 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 19 14:37:28 2017 +0200 fix rpath commit 8215e9748d9ee225266bc941da1ca252aebd27de Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Thu May 18 13:29:41 2017 +0200 remove INSTALL_DIR, rename var to NETGEN_INSTALL_DIR_INCLUDE, install libngpy to python package folder commit 23d028c4cf7572de9e2e277cda8f6b07b6b1d9f9 Merge: 57027c8 f72a247 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Thu May 18 12:03:59 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit 57027c8c706ff755bdf26887884bbdeca129fe8f Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 12 17:32:05 2017 +0200 New CMake option: USE_INTERNAL_TCL (ON by default) This option uses the tcl code compiled in onetcl.cpp instead of separate tcl files by default. When set at configure time, no tcl files will be installed anymore. commit 27ce5b7edd66d64e2453f5045f5ac08c313f7608 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 12 17:16:52 2017 +0200 WIP: Cleanup of CMake files - Fix RPATH on Linux (TODO: other platforms) - New variables to specify install behaviour: NG_INSTALL_DIR_BIN NG_INSTALL_DIR_LIB NG_INSTALL_DIR_CMAKE NG_INSTALL_DIR_INCLUDE
2017-05-30 00:19:34 +05:00
extern const char *ngscript[];
2014-12-19 19:03:36 +05:00
namespace netgen
{
extern bool netgen_executable_started;
2014-12-19 19:03:36 +05:00
extern shared_ptr<NetgenGeometry> ng_geometry;
2019-04-10 17:13:12 +05:00
extern void Optimize2d (Mesh & mesh, MeshingParameters & mp);
2014-12-19 19:03:36 +05:00
}
2014-08-30 06:15:59 +06:00
2015-10-22 20:26:43 +05:00
void TranslateException (const NgException & ex)
{
string err = string("Netgen exception: ")+ex.What();
PyErr_SetString(PyExc_RuntimeError, err.c_str());
}
2014-08-30 06:15:59 +06:00
static Transformation<3> global_trafo(Vec<3> (0,0,0));
2014-08-30 06:15:59 +06:00
2020-07-29 20:18:12 +05:00
2016-11-04 16:14:52 +05:00
DLL_HEADER void ExportNetgenMeshing(py::module &m)
2014-08-30 06:15:59 +06:00
{
2020-07-29 20:18:12 +05:00
#ifdef NG_MPI4PY
import_mpi4py();
#endif // NG_MPI4PY
py::register_exception<NgException>(m, "NgException");
m.attr("_netgen_executable_started") = py::cast(netgen::netgen_executable_started);
Cleanup CMake build system - Use CMAKE_INSTALL_PREFIX instead of INSTALL_DIR - Allow finer control of install directories - Use compiled TCL code by default - Fix RPATH usage on Linux and MacOSX ### Allow finer control of install directories The following variables can be set to either absolute or relative paths NG_INSTALL_DIR_PYTHON: Python files NG_INSTALL_DIR_BIN: Executables NG_INSTALL_DIR_LIB: Libraries NG_INSTALL_DIR_INCLUDE: header files NG_INSTALL_DIR_CMAKE: CMake files NG_INSTALL_DIR_RES: Resources ### Use compiled TCL code by default The tcl files contained in Netgen are stored in onetcl.cpp as c-string. This way it's not necessary to install tcl files or set NETGENDIR ### Fix RPATH usage on Linux and MacOSX The Netgen installation should be completely relocatable now. Squashed commit of the following: commit 201eda5e62726bd87d76beb13c3e5643cd4c7810 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 21:10:08 2017 +0200 cleanup commit b4cd46a9d2f390b40c5223c8d9971f576b979644 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:47:46 2017 +0200 fix commit 6506a834dbee2fd7b6df3b3f3709d0b27344356f Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:41:45 2017 +0200 allow gui test to fail commit 56c5fc131f61259e6fb67b60f7fff955d2e8d2da Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 20:26:18 2017 +0200 add python3-tk to docker images commit 4d1b5aac1d028867339819599708a08f2098bbd6 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:22:18 2017 -0700 windows fix commit 92b5f8a95491ba3508143d7f1b94359edc0655ce Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:08:08 2017 -0700 fix for windows commit 3f7bf51434ef3b637b3563930ddb61d04af645cb Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 19:28:13 2017 +0200 fixes, test for gui commit ef1d0164a50fadf374e3b1e43a745b5f69a16ad6 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 19:06:55 2017 +0200 fixes commit 67645bb896012149c23c851b03287199c21fa129 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 17:24:58 2017 +0200 netgen config commit b587b77a282768719cffc366c56d82a1746e0be0 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 16:53:47 2017 +0200 remove comments commit 2b34cc78818afa1cf21484bd0976413a91db0851 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 05:03:00 2017 -0700 fix windows commit 9e98efa54065624e264eaf1acf74b44ef022a68d Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 13:42:11 2017 +0200 fixes commit 394b470a07d73431079f80caa36c7c7042077f40 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 12:24:40 2017 +0200 fix rpath issue commit 6787eae384a8592f90598258ccd8207cd499d9fc Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 11:37:05 2017 +0200 some more fixes with install dir commit fcf22659c60300e8d39d12e14b21c58a062e739c Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 01:34:06 2017 -0700 some fixes commit ede1f0c462978bb70d3b4e2251cb555a592e82e3 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 29 10:16:34 2017 +0200 fixes commit b6a1259876a77f54e419a44f1b44d03d5bb49b82 Merge: c79f9a3 6627b0b Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Wed May 24 09:35:50 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit c79f9a3421d4d2937c31dab4a601ce09d52b0e54 Merge: 99c3550 030ad1d Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Mon May 22 17:52:24 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit 99c35500850e08fdc847013bb384169b1483acb4 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 19 14:37:28 2017 +0200 fix rpath commit 8215e9748d9ee225266bc941da1ca252aebd27de Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Thu May 18 13:29:41 2017 +0200 remove INSTALL_DIR, rename var to NETGEN_INSTALL_DIR_INCLUDE, install libngpy to python package folder commit 23d028c4cf7572de9e2e277cda8f6b07b6b1d9f9 Merge: 57027c8 f72a247 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Thu May 18 12:03:59 2017 +0200 Merge remote-tracking branch 'origin/master' into cmake_cleanup commit 57027c8c706ff755bdf26887884bbdeca129fe8f Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 12 17:32:05 2017 +0200 New CMake option: USE_INTERNAL_TCL (ON by default) This option uses the tcl code compiled in onetcl.cpp instead of separate tcl files by default. When set at configure time, no tcl files will be installed anymore. commit 27ce5b7edd66d64e2453f5045f5ac08c313f7608 Author: Matthias Hochsteger <matthias.hochsteger@tuwien.ac.at> Date: Fri May 12 17:16:52 2017 +0200 WIP: Cleanup of CMake files - Fix RPATH on Linux (TODO: other platforms) - New variables to specify install behaviour: NG_INSTALL_DIR_BIN NG_INSTALL_DIR_LIB NG_INSTALL_DIR_CMAKE NG_INSTALL_DIR_INCLUDE
2017-05-30 00:19:34 +05:00
string script;
const char ** hcp = ngscript;
while (*hcp)
script += *hcp++;
m.attr("_ngscript") = py::cast(script);
2018-11-06 15:41:04 +05:00
m.def("_GetStatus", []()
{
MyStr s; double percent;
GetStatus(s, percent);
return py::make_tuple(s.c_str(), percent);
});
m.def("_PushStatus", [](string s) { PushStatus(MyStr(s)); });
m.def("_SetThreadPercentage", [](double percent) { SetThreadPercent(percent); });
2021-11-28 20:14:41 +05:00
py::enum_<Identifications::ID_TYPE>(m,"IdentificationType")
.value("UNDEFINED", Identifications::UNDEFINED)
.value("PERIODIC", Identifications::PERIODIC)
.value("CLOSESURFACES", Identifications::CLOSESURFACES)
.value("CLOSEEDGES", Identifications::CLOSEEDGES)
;
py::implicitly_convertible<int, Identifications::ID_TYPE>();
2019-02-12 03:59:32 +05:00
py::class_<NgMPI_Comm> (m, "MPI_Comm")
2020-07-29 20:18:12 +05:00
#ifdef NG_MPI4PY
.def(py::init([] (mpi4py_comm comm)
{
return NgMPI_Comm(comm);
}))
2020-08-25 21:18:31 +05:00
.def_property_readonly ("mpi4py", [] (NgMPI_Comm comm) { return mpi4py_comm(comm); })
2020-07-29 20:18:12 +05:00
#endif // NG_MPI4PY
2019-02-12 03:59:32 +05:00
.def_property_readonly ("rank", &NgMPI_Comm::Rank)
.def_property_readonly ("size", &NgMPI_Comm::Size)
2019-02-13 02:11:55 +05:00
.def("Barrier", &NgMPI_Comm::Barrier)
2019-02-12 03:59:32 +05:00
#ifdef PARALLEL
.def("WTime", [](NgMPI_Comm & c) { return MPI_Wtime(); })
#else
.def("WTime", [](NgMPI_Comm & c) { return -1.0; })
#endif
2020-07-31 12:57:19 +05:00
.def("Sum", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_SUM); })
.def("Min", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MIN); })
.def("Max", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MAX); })
.def("Sum", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_SUM); })
.def("Min", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MIN); })
.def("Max", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MAX); })
.def("Sum", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_SUM); })
.def("Min", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MIN); })
.def("Max", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MAX); })
2019-02-12 03:59:32 +05:00
.def("SubComm", [](NgMPI_Comm & c, std::vector<int> proc_list) {
Array<int> procs(proc_list.size());
2019-02-12 03:59:32 +05:00
for (int i = 0; i < procs.Size(); i++)
{ procs[i] = proc_list[i]; }
2019-02-12 03:59:32 +05:00
if (!procs.Contains(c.Rank()))
{ throw Exception("rank "+ToString(c.Rank())+" not in subcomm"); }
return c.SubCommunicator(procs);
2019-02-12 03:59:32 +05:00
}, py::arg("procs"));
;
2020-07-29 20:18:12 +05:00
#ifdef NG_MPI4PY
py::implicitly_convertible<mpi4py_comm, NgMPI_Comm>();
#endif // NG_MPI4PY
2019-02-12 03:59:32 +05:00
py::class_<NGDummyArgument>(m, "NGDummyArgument")
.def("__bool__", []( NGDummyArgument &self ) { return false; } )
;
2014-08-30 06:15:59 +06:00
py::class_<Point<2>> (m, "Point2d")
.def(py::init<double,double>())
.def(py::init( [] (std::pair<double,double> xy)
{
return Point<2>{xy.first, xy.second};
}))
.def ("__str__", &ToString<Point<2>>)
.def(py::self-py::self)
.def(py::self+Vec<2>())
.def(py::self-Vec<2>())
.def("__getitem__", [](Point<2>& self, int index) { return self[index]; })
;
py::implicitly_convertible<py::tuple, Point<2>>();
py::class_<Point<3>> (m, "Point3d")
.def(py::init<double,double,double>())
.def(py::init([](py::tuple p)
{
return Point<3> { p[0].cast<double>(), p[1].cast<double>(),
p[2].cast<double>() };
}))
.def ("__str__", &ToString<Point<3>>)
.def(py::self-py::self)
.def(py::self+Vec<3>())
.def(py::self-Vec<3>())
.def("__getitem__", [](Point<2>& self, int index) { return self[index]; })
;
py::implicitly_convertible<py::tuple, Point<3>>();
m.def("Pnt", [](double x, double y, double z)
{ return global_trafo(Point<3>(x,y,z)); });
m.def("Pnt", [](double x, double y) { return Point<2>(x,y); });
m.def("Pnt", [](py::array_t<double> np_array)
{
int dim = np_array.size();
if(!(dim == 2 || dim == 3))
throw Exception("Invalid dimension of input array!");
if(dim == 2)
return py::cast(Point<2>(np_array.at(0),
np_array.at(1)));
return py::cast(global_trafo(Point<3>(np_array.at(0),
np_array.at(1),
np_array.at(2))));
});
py::class_<Vec<2>> (m, "Vec2d")
.def(py::init<double,double>())
2020-11-05 18:59:58 +05:00
.def(py::init( [] (std::pair<double,double> xy)
{
return Vec<2>{xy.first, xy.second};
}))
.def ("__str__", &ToString<Vec<3>>)
.def(py::self==py::self)
.def(py::self+py::self)
.def(py::self-py::self)
.def(-py::self)
.def(double()*py::self)
.def(py::self*double())
.def("Norm", &Vec<2>::Length)
2019-01-24 20:13:22 +05:00
.def("__getitem__", [](Vec<2>& vec, int index) { return vec[index]; })
.def("__len__", [](Vec<2>& /*unused*/) { return 2; })
;
2020-11-05 18:59:58 +05:00
py::implicitly_convertible<py::tuple, Vec<2>>();
py::class_<Vec<3>> (m, "Vec3d")
.def(py::init<double,double,double>())
.def(py::init([](py::tuple v)
{
return Vec<3> { v[0].cast<double>(), v[1].cast<double>(),
v[2].cast<double>() };
}))
.def ("__str__", &ToString<Vec<3>>)
.def(py::self==py::self)
.def(py::self+py::self)
.def(py::self-py::self)
.def(-py::self)
.def(double()*py::self)
.def(py::self*double())
.def("Norm", &Vec<3>::Length)
2019-01-24 20:13:22 +05:00
.def("__getitem__", [](Vec<3>& vec, int index) { return vec[index]; })
.def("__len__", [](Vec<3>& /*unused*/) { return 3; })
;
py::implicitly_convertible<py::tuple, Vec<3>>();
m.def ("Vec", FunctionPointer
([] (double x, double y, double z) { return global_trafo(Vec<3>(x,y,z)); }));
m.def("Vec", [](py::array_t<double> np_array)
{
int dim = np_array.size();
if(!(dim == 2 || dim == 3))
throw Exception("Invalid dimension of input array!");
if(dim == 2)
return py::cast(Vec<2>(np_array.at(0),
np_array.at(1)));
return py::cast(global_trafo(Vec<3>(np_array.at(0),
np_array.at(1),
np_array.at(2))));
});
m.def ("Vec", FunctionPointer
([] (double x, double y) { return Vec<2>(x,y); }));
py::class_<Transformation<3>> (m, "Trafo")
.def(py::init<Vec<3>>(), "a translation")
.def(py::init<Point<3>,Vec<3>,double>(), "a rotation given by point on axes, direction of axes, angle")
.def("__mul__", [](Transformation<3> a, Transformation<3> b)->Transformation<3>
{ Transformation<3> res; res.Combine(a,b); return res; })
.def("__call__", [] (Transformation<3> trafo, Point<3> p) { return trafo(p); })
;
2018-06-25 22:42:42 +05:00
m.def ("GetTransformation", [] () { return global_trafo; });
m.def ("SetTransformation", [] (Transformation<3> trafo) { global_trafo = trafo; });
2018-06-25 22:25:17 +05:00
m.def ("SetTransformation",
[](int dir, double angle)
{
if (dir > 0)
global_trafo.SetAxisRotation (dir, angle*M_PI/180);
else
global_trafo = Transformation<3> (Vec<3>(0,0,0));
},
py::arg("dir")=int(0), py::arg("angle")=int(0));
2018-06-25 22:25:17 +05:00
m.def ("SetTransformation",
[](Point<3> p0, Vec<3> ex, Vec<3> ey, Vec<3> ez)
{
Point<3> pnts[4];
pnts[0] = p0;
pnts[1] = p0 + ex;
pnts[2] = p0 + ey;
pnts[3] = p0 + ez;
global_trafo = Transformation<3> (pnts);
},
py::arg("p0"), py::arg("ex"), py::arg("ey"), py::arg("ez"));
2015-10-22 20:26:43 +05:00
2016-11-04 16:14:52 +05:00
py::class_<PointIndex>(m, "PointId")
.def(py::init<int>())
2014-08-30 06:15:59 +06:00
.def("__repr__", &ToString<PointIndex>)
.def("__str__", &ToString<PointIndex>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("nr", &PointIndex::operator int)
2015-05-20 13:39:55 +05:00
.def("__eq__" , FunctionPointer( [](PointIndex &self, PointIndex &other)
{ return static_cast<int>(self)==static_cast<int>(other); }) )
.def("__hash__" , FunctionPointer( [](PointIndex &self ) { return static_cast<int>(self); }) )
2014-08-30 06:15:59 +06:00
;
2014-09-26 02:23:31 +06:00
2016-11-04 16:14:52 +05:00
py::class_<ElementIndex>(m, "ElementId3D")
.def(py::init<int>())
2015-05-18 19:19:38 +05:00
.def("__repr__", &ToString<ElementIndex>)
.def("__str__", &ToString<ElementIndex>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("nr", &ElementIndex::operator int)
2015-05-20 13:39:55 +05:00
.def("__eq__" , FunctionPointer( [](ElementIndex &self, ElementIndex &other)
{ return static_cast<int>(self)==static_cast<int>(other); }) )
.def("__hash__" , FunctionPointer( [](ElementIndex &self ) { return static_cast<int>(self); }) )
2015-05-18 19:19:38 +05:00
;
2016-11-04 16:14:52 +05:00
py::class_<SurfaceElementIndex>(m, "ElementId2D")
.def(py::init<int>())
2015-05-18 19:19:38 +05:00
.def("__repr__", &ToString<SurfaceElementIndex>)
.def("__str__", &ToString<SurfaceElementIndex>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("nr", &SurfaceElementIndex::operator int)
2015-05-20 13:39:55 +05:00
.def("__eq__" , FunctionPointer( [](SurfaceElementIndex &self, SurfaceElementIndex &other)
{ return static_cast<int>(self)==static_cast<int>(other); }) )
.def("__hash__" , FunctionPointer( [](SurfaceElementIndex &self ) { return static_cast<int>(self); }) )
2015-05-18 19:19:38 +05:00
;
2016-11-04 16:14:52 +05:00
py::class_<SegmentIndex>(m, "ElementId1D")
.def(py::init<int>())
2015-05-18 19:19:38 +05:00
.def("__repr__", &ToString<SegmentIndex>)
.def("__str__", &ToString<SegmentIndex>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("nr", &SegmentIndex::operator int)
2015-05-20 13:39:55 +05:00
.def("__eq__" , FunctionPointer( [](SegmentIndex &self, SegmentIndex &other)
{ return static_cast<int>(self)==static_cast<int>(other); }) )
.def("__hash__" , FunctionPointer( [](SegmentIndex &self ) { return static_cast<int>(self); }) )
2015-05-18 19:19:38 +05:00
;
2014-09-26 02:23:31 +06:00
/*
2016-11-04 16:14:52 +05:00
py::class_<Point<3>> ("Point")
.def(py::init<double,double,double>())
2014-08-31 15:14:18 +06:00
;
2014-09-26 02:23:31 +06:00
*/
2016-11-04 16:14:52 +05:00
py::class_<MeshPoint /* ,py::bases<Point<3>> */ >(m, "MeshPoint")
.def(py::init<Point<3>>())
2015-05-18 19:19:38 +05:00
.def("__str__", &ToString<MeshPoint>)
.def("__repr__", &ToString<MeshPoint>)
2019-09-04 18:24:37 +05:00
.def_property_readonly("p", [](const MeshPoint & self)
{
py::list l;
l.append ( py::cast(self[0]) );
l.append ( py::cast(self[1]) );
l.append ( py::cast(self[2]) );
return py::tuple(l);
})
.def("__getitem__", [](const MeshPoint & self, int index) {
2016-08-06 15:55:59 +05:00
if(index<0 || index>2)
2016-11-04 16:14:52 +05:00
throw py::index_error();
2016-08-06 15:55:59 +05:00
return self[index];
2019-09-04 18:24:37 +05:00
})
.def("__setitem__", [](MeshPoint & self, int index, double val) {
2017-06-27 02:26:09 +05:00
if(index<0 || index>2)
throw py::index_error();
self(index) = val;
2019-09-04 18:24:37 +05:00
})
2014-08-31 15:14:18 +06:00
;
2016-11-04 16:14:52 +05:00
py::class_<Element>(m, "Element3D")
.def(py::init([](int index, std::vector<PointIndex> vertices)
2018-03-09 02:19:11 +05:00
{
int np = vertices.size();
ELEMENT_TYPE et;
switch (np)
{
case 4: et = TET; break;
case 5: et = PYRAMID; break;
case 6: et = PRISM; break;
case 8: et = HEX; break;
case 10: et = TET10; break;
case 13: et = PYRAMID13; break;
case 15: et = PRISM15; break;
case 20: et = HEX20; break;
default:
throw Exception ("no Element3D with " + ToString(np) +
" points");
}
auto newel = new Element(et);
for(int i=0; i<np; i++)
(*newel)[i] = vertices[i];
newel->SetIndex(index);
2018-03-09 02:19:11 +05:00
return newel;
}),
2016-11-04 16:14:52 +05:00
py::arg("index")=1,py::arg("vertices"),
2015-05-18 19:19:38 +05:00
"create volume element"
)
.def("__repr__", &ToString<Element>)
2016-11-04 16:14:52 +05:00
.def_property("index", &Element::GetIndex, &Element::SetIndex)
.def_property("curved", &Element::IsCurved, &Element::SetCurved)
.def_property("refine", &Element::TestRefinementFlag, &Element::SetRefinementFlag)
2016-11-04 16:14:52 +05:00
.def_property_readonly("vertices",
FunctionPointer ([](const Element & self) -> py::list
2014-08-30 06:15:59 +06:00
{
2016-11-04 16:14:52 +05:00
py::list li;
2014-08-30 06:15:59 +06:00
for (int i = 0; i < self.GetNV(); i++)
2016-11-04 16:14:52 +05:00
li.append (py::cast(self[i]));
2014-08-30 06:15:59 +06:00
return li;
}))
2017-06-01 02:44:50 +05:00
.def_property_readonly("points",
FunctionPointer ([](const Element & self) -> py::list
{
py::list li;
for (int i = 0; i < self.GetNP(); i++)
li.append (py::cast(self[i]));
return li;
}))
2014-08-30 06:15:59 +06:00
;
2014-10-01 19:16:34 +06:00
if(ngcore_have_numpy)
{
auto data_layout = Element::GetDataLayout();
py::detail::npy_format_descriptor<Element>::register_dtype({
py::detail::field_descriptor {
"nodes", data_layout["pnum"],
ELEMENT_MAXPOINTS * sizeof(PointIndex),
py::format_descriptor<int[ELEMENT_MAXPOINTS]>::format(),
py::detail::npy_format_descriptor<int[ELEMENT_MAXPOINTS]>::dtype() },
py::detail::field_descriptor {
"index", data_layout["index"], sizeof(int),
py::format_descriptor<int>::format(),
py::detail::npy_format_descriptor<int>::dtype() },
py::detail::field_descriptor {
"np", data_layout["np"], sizeof(int8_t),
py::format_descriptor<signed char>::format(),
pybind11::dtype("int8") },
py::detail::field_descriptor {
"refine", data_layout["refine"], sizeof(bool),
py::format_descriptor<bool>::format(),
py::detail::npy_format_descriptor<bool>::dtype() }
});
}
2016-11-04 16:14:52 +05:00
py::class_<Element2d>(m, "Element2D")
2019-10-06 02:02:32 +05:00
.def(py::init ([](int index, std::vector<PointIndex> vertices)
2018-03-09 02:19:11 +05:00
{
Element2d * newel = nullptr;
2019-10-06 02:02:32 +05:00
if (vertices.size() == 3)
2018-03-09 02:19:11 +05:00
{
newel = new Element2d(TRIG);
for (int i = 0; i < 3; i++)
2019-10-06 02:02:32 +05:00
(*newel)[i] = vertices[i];
2018-03-09 02:19:11 +05:00
newel->SetIndex(index);
}
2019-10-06 02:02:32 +05:00
else if (vertices.size() == 4)
2018-03-09 02:19:11 +05:00
{
newel = new Element2d(QUAD);
for (int i = 0; i < 4; i++)
2019-10-06 02:02:32 +05:00
(*newel)[i] = vertices[i];
2018-03-09 02:19:11 +05:00
newel->SetIndex(index);
}
2019-10-06 02:02:32 +05:00
else if (vertices.size() == 6)
2018-03-09 02:19:11 +05:00
{
newel = new Element2d(TRIG6);
for(int i = 0; i<6; i++)
2019-10-06 02:02:32 +05:00
(*newel)[i] = vertices[i];
2018-03-09 02:19:11 +05:00
newel->SetIndex(index);
}
2019-10-06 02:02:32 +05:00
else if (vertices.size() == 8)
2019-01-18 02:08:35 +05:00
{
newel = new Element2d(QUAD8);
for(int i = 0; i<8; i++)
2019-10-06 02:02:32 +05:00
(*newel)[i] = vertices[i];
2019-01-18 02:08:35 +05:00
newel->SetIndex(index);
}
2018-03-09 02:19:11 +05:00
else
throw NgException("Inconsistent number of vertices in Element2D");
return newel;
}),
py::arg("index")=1,py::arg("vertices"),
2015-05-18 19:19:38 +05:00
"create surface element"
)
2016-11-04 16:14:52 +05:00
.def_property("index", &Element2d::GetIndex, &Element2d::SetIndex)
2018-11-18 00:57:53 +05:00
.def_property("curved", &Element2d::IsCurved, &Element2d::SetCurved)
.def_property("refine", &Element2d::TestRefinementFlag, &Element2d::SetRefinementFlag)
2016-11-04 16:14:52 +05:00
.def_property_readonly("vertices",
FunctionPointer([](const Element2d & self) -> py::list
2015-01-20 22:41:16 +05:00
{
2016-11-04 16:14:52 +05:00
py::list li;
2015-01-20 22:41:16 +05:00
for (int i = 0; i < self.GetNV(); i++)
2016-11-04 16:14:52 +05:00
li.append(py::cast(self[i]));
2015-01-20 22:41:16 +05:00
return li;
}))
.def_property_readonly("points",
FunctionPointer ([](const Element2d & self) -> py::list
{
py::list li;
for (int i = 0; i < self.GetNP(); i++)
li.append (py::cast(self[i]));
return li;
}))
2015-01-20 22:41:16 +05:00
;
2015-05-18 19:19:38 +05:00
if(ngcore_have_numpy)
{
auto data_layout = Element2d::GetDataLayout();
py::detail::npy_format_descriptor<Element2d>::register_dtype({
py::detail::field_descriptor {
"nodes", data_layout["pnum"],
ELEMENT2D_MAXPOINTS * sizeof(PointIndex),
py::format_descriptor<int[ELEMENT2D_MAXPOINTS]>::format(),
py::detail::npy_format_descriptor<int[ELEMENT2D_MAXPOINTS]>::dtype() },
py::detail::field_descriptor {
"index", data_layout["index"], sizeof(int),
py::format_descriptor<int>::format(),
py::detail::npy_format_descriptor<int>::dtype() },
py::detail::field_descriptor {
"np", data_layout["np"], sizeof(int8_t),
py::format_descriptor<signed char>::format(),
pybind11::dtype("int8") },
py::detail::field_descriptor {
"refine", data_layout["refine"], sizeof(bool),
py::format_descriptor<bool>::format(),
py::detail::npy_format_descriptor<bool>::dtype() }
});
}
2016-11-04 16:14:52 +05:00
py::class_<Segment>(m, "Element1D")
.def(py::init([](py::list vertices, py::list surfaces, int index, int edgenr,
py::list trignums)
2018-03-09 02:19:11 +05:00
{
Segment * newel = new Segment();
for (int i = 0; i < 2; i++)
(*newel)[i] = py::extract<PointIndex>(vertices[i])();
newel -> si = index;
newel -> edgenr = edgenr;
newel -> epgeominfo[0].edgenr = edgenr;
newel -> epgeominfo[1].edgenr = edgenr;
2018-03-09 02:19:11 +05:00
// needed for codim2 in 3d
newel -> edgenr = index;
for(auto i : Range(len(trignums)))
newel->geominfo[i].trignum = py::cast<int>(trignums[i]);
2018-03-09 02:19:11 +05:00
if (len(surfaces))
{
newel->surfnr1 = py::extract<int>(surfaces[0])();
newel->surfnr2 = py::extract<int>(surfaces[1])();
}
return newel;
}),
2016-11-04 16:14:52 +05:00
py::arg("vertices"),
py::arg("surfaces")=py::list(),
py::arg("index")=1,
py::arg("edgenr")=1,
py::arg("trignums")=py::list(), // for stl
2015-05-18 19:19:38 +05:00
"create segment element"
)
2015-11-11 22:46:18 +05:00
.def("__repr__", &ToString<Segment>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("vertices",
FunctionPointer ([](const Segment & self) -> py::list
2015-05-18 19:19:38 +05:00
{
2016-11-04 16:14:52 +05:00
py::list li;
2015-05-18 19:19:38 +05:00
for (int i = 0; i < 2; i++)
2016-11-04 16:14:52 +05:00
li.append (py::cast(self[i]));
2015-05-18 19:19:38 +05:00
return li;
}))
.def_property_readonly("points",
FunctionPointer ([](const Segment & self) -> py::list
{
py::list li;
for (int i = 0; i < self.GetNP(); i++)
li.append (py::cast(self[i]));
return li;
}))
2016-11-04 16:14:52 +05:00
.def_property_readonly("surfaces",
FunctionPointer ([](const Segment & self) -> py::list
2015-05-18 19:19:38 +05:00
{
2016-11-04 16:14:52 +05:00
py::list li;
li.append (py::cast(self.surfnr1));
li.append (py::cast(self.surfnr2));
2015-05-18 19:19:38 +05:00
return li;
}))
2016-11-05 21:15:16 +05:00
.def_property_readonly("index", FunctionPointer([](const Segment &self) -> size_t
2016-10-28 19:49:50 +05:00
{
2016-11-21 18:54:11 +05:00
return self.si;
2016-10-28 19:49:50 +05:00
}))
2016-11-21 18:54:11 +05:00
.def_property_readonly("edgenr", FunctionPointer([](const Segment & self) -> size_t
{
return self.edgenr;
}))
2015-05-18 19:19:38 +05:00
;
if(ngcore_have_numpy)
{
py::detail::npy_format_descriptor<Segment>::register_dtype({
py::detail::field_descriptor {
"nodes", offsetof(Segment, pnums),
3 * sizeof(PointIndex),
py::format_descriptor<int[3]>::format(),
py::detail::npy_format_descriptor<int[3]>::dtype() },
py::detail::field_descriptor {
"index", offsetof(Segment, edgenr), sizeof(int),
py::format_descriptor<int>::format(),
py::detail::npy_format_descriptor<int>::dtype() },
});
}
2015-05-18 19:19:38 +05:00
2016-11-04 16:14:52 +05:00
py::class_<Element0d>(m, "Element0D")
2018-03-09 02:19:11 +05:00
.def(py::init([](PointIndex vertex, int index)
{
Element0d * instance = new Element0d;
instance->pnum = vertex;
instance->index = index;
return instance;
}),
2016-11-04 16:14:52 +05:00
py::arg("vertex"),
py::arg("index")=1,
2015-11-11 22:46:18 +05:00
"create point element"
)
.def("__repr__", &ToString<Element0d>)
2016-11-04 16:14:52 +05:00
.def_property_readonly("vertices",
FunctionPointer ([](const Element0d & self) -> py::list
2015-11-11 22:46:18 +05:00
{
2016-11-04 16:14:52 +05:00
py::list li;
li.append (py::cast(self.pnum));
2015-11-11 22:46:18 +05:00
return li;
}))
;
2015-05-18 19:19:38 +05:00
2016-11-04 16:14:52 +05:00
py::class_<FaceDescriptor>(m, "FaceDescriptor")
.def(py::init<const FaceDescriptor&>())
2018-03-09 02:19:11 +05:00
.def(py::init([](int surfnr, int domin, int domout, int bc)
{
FaceDescriptor * instance = new FaceDescriptor();
instance->SetSurfNr(surfnr);
instance->SetDomainIn(domin);
instance->SetDomainOut(domout);
instance->SetBCProperty(bc);
return instance;
}),
py::arg("surfnr")=1,
py::arg("domin")=1,
py::arg("domout")=py::int_(0),
py::arg("bc")=py::int_(0),
2015-08-29 16:54:00 +05:00
"create facedescriptor")
2015-05-18 19:19:38 +05:00
.def("__str__", &ToString<FaceDescriptor>)
.def("__repr__", &ToString<FaceDescriptor>)
2016-11-04 16:14:52 +05:00
.def_property("surfnr", &FaceDescriptor::SurfNr, &FaceDescriptor::SetSurfNr)
.def_property("domin", &FaceDescriptor::DomainIn, &FaceDescriptor::SetDomainIn)
.def_property("domout", &FaceDescriptor::DomainOut, &FaceDescriptor::SetDomainOut)
.def_property("bc", &FaceDescriptor::BCProperty, &FaceDescriptor::SetBCProperty)
2017-02-09 14:06:34 +05:00
.def_property("bcname",
[](FaceDescriptor & self) -> string { return self.GetBCName(); },
[](FaceDescriptor & self, string name) { self.SetBCName(new string(name)); } // memleak
)
.def_property("color",
[](const FaceDescriptor& self)
{
auto sc = self.SurfColour();
2022-05-06 20:47:50 +05:00
return py::make_tuple(sc[0], sc[1], sc[2]);
},
[](FaceDescriptor& self, py::tuple col)
{
Vec<4> sc = 1;
sc[0] = py::cast<double>(col[0]);
sc[1] = py::cast<double>(col[1]);
sc[2] = py::cast<double>(col[2]);
if(py::len(col) > 3)
sc[3] = py::cast<double>(col[3]);
self.SetSurfColour(sc);
}
)
.def_property("transparency",
[](const FaceDescriptor& self)
{
return self.SurfColour()[3];
},
[](FaceDescriptor& self, double val)
{
auto sc = self.SurfColour();
sc[3] = val;
self.SetSurfColour(sc);
})
2015-05-18 19:19:38 +05:00
;
ExportArray<Element,ElementIndex>(m);
2019-08-18 16:25:04 +05:00
ExportArray<Element2d,SurfaceElementIndex>(m);
ExportArray<Segment,SegmentIndex>(m);
2016-11-04 16:14:52 +05:00
ExportArray<Element0d>(m);
2019-08-12 17:20:30 +05:00
ExportArray<MeshPoint,PointIndex>(m);
2016-11-04 16:14:52 +05:00
ExportArray<FaceDescriptor>(m);
py::implicitly_convertible< int, PointIndex>();
py::class_<NetgenGeometry, shared_ptr<NetgenGeometry>> (m, "NetgenGeometry", py::dynamic_attr())
2021-09-09 01:12:45 +05:00
.def("RestrictH", &NetgenGeometry::RestrictH)
;
2014-08-30 06:15:59 +06:00
2016-11-04 16:14:52 +05:00
py::class_<Mesh,shared_ptr<Mesh>>(m, "Mesh")
// .def(py::init<>("create empty mesh"))
2015-10-22 19:32:58 +05:00
2019-02-12 01:37:00 +05:00
.def(py::init( [] (int dim, NgMPI_Comm comm)
{
auto mesh = make_shared<Mesh>();
2019-02-12 01:37:00 +05:00
mesh->SetCommunicator(comm);
mesh -> SetDimension(dim);
SetGlobalMesh(mesh); // for visualization
2018-12-14 16:01:58 +05:00
mesh -> SetGeometry (nullptr);
return mesh;
} ),
2019-02-12 20:30:18 +05:00
py::arg("dim")=3, py::arg("comm")=NgMPI_Comm{}
)
.def(NGSPickle<Mesh>())
2019-02-12 01:37:00 +05:00
.def_property_readonly("comm", [](const Mesh & amesh) -> NgMPI_Comm
{ return amesh.GetCommunicator(); },
2019-01-31 00:55:45 +05:00
"MPI-communicator the Mesh lives in")
/*
2016-11-04 16:14:52 +05:00
.def("__init__",
[](Mesh *instance, int dim)
2015-10-22 19:32:58 +05:00
{
2016-11-04 16:14:52 +05:00
new (instance) Mesh();
instance->SetDimension(dim);
},
py::arg("dim")=3
)
*/
2015-10-22 19:32:58 +05:00
.def_property_readonly("_timestamp", &Mesh::GetTimeStamp)
2019-08-08 13:12:33 +05:00
.def_property_readonly("ne", [](Mesh& m) { return m.GetNE(); })
.def("Partition", [](shared_ptr<Mesh> self, int numproc) {
self->ParallelMetis(numproc);
}, py::arg("numproc"))
2019-02-12 01:37:00 +05:00
.def("Distribute", [](shared_ptr<Mesh> self, NgMPI_Comm comm) {
2019-02-08 18:14:19 +05:00
self->SetCommunicator(comm);
2019-02-13 02:11:55 +05:00
if(comm.Size()==1) return self;
2019-02-09 02:12:00 +05:00
// if(MyMPI_GetNTasks(comm)==2) throw NgException("Sorry, cannot handle communicators with NP=2!");
// cout << " rank " << MyMPI_GetId(comm) << " of " << MyMPI_GetNTasks(comm) << " called Distribute " << endl;
2019-02-13 02:11:55 +05:00
if(comm.Rank()==0) self->Distribute();
2019-02-08 18:14:19 +05:00
else self->SendRecvMesh();
return self;
2019-02-13 02:11:55 +05:00
}, py::arg("comm"))
.def_static("Receive", [](NgMPI_Comm comm) -> shared_ptr<Mesh> {
2019-02-08 18:14:19 +05:00
auto mesh = make_shared<Mesh>();
2019-02-12 01:37:00 +05:00
mesh->SetCommunicator(comm);
2019-02-08 18:14:19 +05:00
mesh->SendRecvMesh();
return mesh;
}, py::arg("comm"))
2014-12-19 19:03:36 +05:00
.def("Load", FunctionPointer
([](shared_ptr<Mesh> self, const string & filename)
2014-12-19 19:03:36 +05:00
{
auto comm = self->GetCommunicator();
int id = comm.Rank();
int ntasks = comm.Size();
auto & mesh = self;
2019-01-31 00:55:45 +05:00
{
ifstream infile(filename.c_str());
if(!infile.good())
throw NgException(string("Error opening file ") + filename);
}
if ( filename.find(".vol") == string::npos )
{
if(ntasks>1)
throw NgException("Not sure what to do with this?? Does this work with MPI??");
mesh->SetCommunicator(comm);
ReadFile(*mesh,filename.c_str());
//mesh->SetGlobalH (mparam.maxh);
//mesh->CalcLocalH();
return;
2016-02-27 00:35:09 +05:00
}
2021-05-30 21:52:27 +05:00
istream * infile = nullptr;
2022-04-27 01:00:25 +05:00
Array<char> buf; // for distributing geometry!
int strs;
if( id == 0) {
2021-11-18 12:48:09 +05:00
if (filename.length() > 8 && filename.substr (filename.length()-8, 8) == ".vol.bin")
2021-05-30 21:52:27 +05:00
mesh -> Load(filename);
else if (filename.substr (filename.length()-3, 3) == ".gz")
infile = new igzstream (filename.c_str());
else
infile = new ifstream (filename.c_str());
2021-05-30 21:52:27 +05:00
if(infile)
{
mesh -> Load(*infile);
// make string from rest of file (for geometry info!)
// (this might be empty, in which case we take the global ng_geometry)
stringstream geom_part;
geom_part << infile->rdbuf();
string geom_part_string = geom_part.str();
strs = geom_part_string.size();
// buf = new char[strs];
buf.SetSize(strs);
memcpy(buf.Data(), geom_part_string.c_str(), strs*sizeof(char));
2021-05-30 21:52:27 +05:00
delete infile;
}
if (ntasks > 1)
{
char * weightsfilename = new char [filename.size()+1];
strcpy (weightsfilename, filename.c_str());
weightsfilename[strlen (weightsfilename)-3] = 'w';
weightsfilename[strlen (weightsfilename)-2] = 'e';
weightsfilename[strlen (weightsfilename)-1] = 'i';
ifstream weightsfile(weightsfilename);
delete [] weightsfilename;
if (!(weightsfile.good()))
{
// cout << "regular distribute" << endl;
mesh -> Distribute();
}
else
{
char str[20];
bool endfile = false;
int n, dummy;
2019-07-09 13:39:16 +05:00
NgArray<int> segment_weights;
NgArray<int> surface_weights;
NgArray<int> volume_weights;
while (weightsfile.good() && !endfile)
{
weightsfile >> str;
if (strcmp (str, "edgeweights") == 0)
{
weightsfile >> n;
segment_weights.SetSize(n);
for (int i = 0; i < n; i++)
weightsfile >> dummy >> segment_weights[i];
}
if (strcmp (str, "surfaceweights") == 0)
{
weightsfile >> n;
surface_weights.SetSize(n);
for (int i=0; i<n; i++)
weightsfile >> dummy >> surface_weights[i];
}
if (strcmp (str, "volumeweights") == 0)
{
weightsfile >> n;
volume_weights.SetSize(n);
for (int i=0; i<n; i++)
weightsfile >> dummy >> volume_weights[i];
}
if (strcmp (str, "endfile") == 0)
endfile = true;
}
mesh -> Distribute(volume_weights, surface_weights, segment_weights);
}
} // ntasks>1 end
} // id==0 end
else {
mesh->SendRecvMesh();
}
if(ntasks>1) {
2022-04-27 01:00:25 +05:00
// #ifdef PARALLEL
/** Scatter the geometry-string (no dummy-implementation in mpi_interface) **/
2022-04-27 01:00:25 +05:00
/*
int strs = buf.Size();
MyMPI_Bcast(strs, comm);
if(strs>0)
MyMPI_Bcast(buf, comm);
2022-04-27 01:00:25 +05:00
*/
comm.Bcast(buf);
// #endif
}
shared_ptr<NetgenGeometry> geo;
if(buf.Size()) { // if we had geom-info in the file, take it
istringstream geom_infile(string((const char*)buf.Data(), buf.Size()));
geo = geometryregister.LoadFromMeshFile(geom_infile);
}
if(geo!=nullptr) mesh->SetGeometry(geo);
else if(ng_geometry!=nullptr) mesh->SetGeometry(ng_geometry);
2018-03-13 02:38:21 +05:00
}),py::call_guard<py::gil_scoped_release>())
2022-02-17 20:52:07 +05:00
.def("Save", static_cast<void(Mesh::*)(const filesystem::path & name)const>(&Mesh::Save),py::call_guard<py::gil_scoped_release>())
2016-11-04 16:14:52 +05:00
.def("Export",
[] (Mesh & self, string filename, string format)
2016-07-10 21:07:36 +05:00
{
if (WriteUserFormat (format, self, /* *self.GetGeometry(), */ filename))
2016-07-10 21:07:36 +05:00
{
string err = string ("nothing known about format")+format;
2019-07-09 13:39:16 +05:00
NgArray<const char*> names, extensions;
2016-07-10 21:07:36 +05:00
RegisterUserFormats (names, extensions);
err += "\navailable formats are:\n";
for (auto name : names)
err += string("'") + name + "'\n";
throw NgException (err);
}
2016-11-04 16:14:52 +05:00
},
2018-03-13 02:38:21 +05:00
py::arg("filename"), py::arg("format"),py::call_guard<py::gil_scoped_release>())
2016-07-10 21:07:36 +05:00
2016-11-04 16:14:52 +05:00
.def_property("dim", &Mesh::GetDimension, &Mesh::SetDimension)
2015-08-31 20:41:26 +05:00
2014-08-30 06:15:59 +06:00
.def("Elements3D",
static_cast<Array<Element,ElementIndex>&(Mesh::*)()> (&Mesh::VolumeElements),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2014-08-31 15:14:18 +06:00
.def("Elements2D",
2019-08-18 16:10:58 +05:00
static_cast<Array<Element2d,SurfaceElementIndex>&(Mesh::*)()> (&Mesh::SurfaceElements),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2014-08-31 15:14:18 +06:00
2015-05-18 19:19:38 +05:00
.def("Elements1D",
static_cast<Array<Segment, SegmentIndex>&(Mesh::*)()> (&Mesh::LineSegments),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2015-05-18 19:19:38 +05:00
2019-08-09 03:23:12 +05:00
.def("Elements0D", FunctionPointer([] (Mesh & self) -> Array<Element0d>&
2015-11-11 22:46:18 +05:00
{
return self.pointelements;
} ),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2015-05-18 19:19:38 +05:00
2014-08-31 15:14:18 +06:00
.def("Points",
2014-09-03 15:07:10 +06:00
static_cast<Mesh::T_POINTS&(Mesh::*)()> (&Mesh::Points),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2014-08-30 06:15:59 +06:00
.def("Coordinates", [](Mesh & self) {
return py::array
(
py::memoryview::from_buffer
(&self.Points()[PointIndex::BASE](0), sizeof(double),
py::format_descriptor<double>::value,
{ self.Points().Size(), size_t(self.GetDimension()) },
{ sizeof(self.Points()[PointIndex::BASE]), sizeof(double) } )
);
})
2015-05-18 19:19:38 +05:00
.def("FaceDescriptor", static_cast<FaceDescriptor&(Mesh::*)(int)> (&Mesh::GetFaceDescriptor),
2016-11-04 16:14:52 +05:00
py::return_value_policy::reference)
2015-12-11 18:31:28 +05:00
.def("GetNFaceDescriptors", &Mesh::GetNFD)
2021-09-10 15:42:41 +05:00
.def("FaceDescriptors",
// static_cast<Array<Element>&(Mesh::*)()> (&Mesh::FaceDescriptors),
&Mesh::FaceDescriptors,
py::return_value_policy::reference)
.def("GetNDomains", &Mesh::GetNDomains)
2016-11-18 20:57:42 +05:00
.def("GetVolumeNeighboursOfSurfaceElement", [](Mesh & self, size_t sel)
{
int elnr1, elnr2;
self.GetTopology().GetSurface2VolumeElement(sel+1, elnr1, elnr2);
return py::make_tuple(elnr1, elnr2);
}, "Returns element nrs of volume element connected to surface element, -1 if no volume element")
2016-11-18 20:57:42 +05:00
.def("GetNCD2Names", &Mesh::GetNCD2Names)
2015-12-11 18:31:28 +05:00
2014-08-30 06:15:59 +06:00
2019-09-04 18:24:37 +05:00
.def("__getitem__", [](const Mesh & self, PointIndex id) { return self[id]; })
.def("__getitem__", [](const Mesh & self, ElementIndex id) { return self[id]; })
.def("__getitem__", [](const Mesh & self, SurfaceElementIndex id) { return self[id]; })
.def("__getitem__", [](const Mesh & self, SegmentIndex id) { return self[id]; })
2015-05-18 19:19:38 +05:00
2019-09-04 18:24:37 +05:00
.def("__setitem__", [](Mesh & self, PointIndex id, const MeshPoint & mp) { return self[id] = mp; })
2015-11-11 22:46:18 +05:00
2019-09-04 18:24:37 +05:00
.def ("Add", [](Mesh & self, MeshPoint p)
{
return self.AddPoint (Point3d(p));
})
.def ("Add", [](Mesh & self, const Element & el)
{
return self.AddVolumeElement (el);
})
.def ("Add", [](Mesh & self, const Element2d & el)
{
return self.AddSurfaceElement (el);
})
2015-05-18 19:19:38 +05:00
2019-09-04 18:24:37 +05:00
.def ("Add", [](Mesh & self, const Segment & el)
{
return self.AddSegment (el);
})
.def ("Add", [](Mesh & self, const Element0d & el)
{
return self.pointelements.Append (el);
})
.def ("Add", [](Mesh & self, const FaceDescriptor & fd)
{
return self.AddFaceDescriptor (fd);
})
2022-02-13 20:31:55 +05:00
2023-06-21 19:44:21 +05:00
.def ("AddSingularity", [](Mesh & self, PointIndex pi, double factor)
{
self[pi].Singularity(factor);
})
2022-02-13 23:02:51 +05:00
.def ("AddPoints", [](Mesh & self, py::buffer b1)
2022-02-13 20:31:55 +05:00
{
2022-02-13 21:29:53 +05:00
static Timer timer("Mesh::AddPoints");
2022-02-13 23:02:51 +05:00
static Timer timercast("Mesh::AddPoints - casting");
2022-02-13 21:29:53 +05:00
RegionTimer reg(timer);
2022-02-13 23:02:51 +05:00
timercast.Start();
// casting from here: https://github.com/pybind/pybind11/issues/1908
auto b = b1.cast<py::array_t<double_t, py::array::c_style | py::array::forcecast>>();
timercast.Stop();
2022-02-13 21:29:53 +05:00
2022-02-13 20:31:55 +05:00
py::buffer_info info = b.request();
2022-02-13 23:02:51 +05:00
// cout << "data format = " << info.format << endl;
2022-02-13 20:31:55 +05:00
if (info.ndim != 2)
throw std::runtime_error("AddPoints needs buffer of dimension 2");
2022-02-13 23:02:51 +05:00
// if (info.format != py::format_descriptor<double>::format())
// throw std::runtime_error("AddPoints needs buffer of type double");
2022-02-13 20:31:55 +05:00
if (info.strides[0] != sizeof(double)*info.shape[1])
throw std::runtime_error("AddPoints needs packed array");
double * ptr = static_cast<double*> (info.ptr);
2022-02-13 21:29:53 +05:00
self.Points().SetAllocSize(self.Points().Size()+info.shape[0]);
2022-02-13 20:31:55 +05:00
if (info.shape[1]==2)
for (auto i : Range(info.shape[0]))
{
self.AddPoint (Point<3>(ptr[0], ptr[1], 0));
ptr += 2;
}
if (info.shape[1]==3)
for (auto i : Range(info.shape[0]))
{
self.AddPoint (Point<3>(ptr[0], ptr[1], ptr[2]));
ptr += 3;
}
})
2022-02-13 23:02:51 +05:00
.def ("AddElements", [](Mesh & self, int dim, int index, py::buffer b1, int base)
2022-02-13 20:31:55 +05:00
{
2022-02-13 21:29:53 +05:00
static Timer timer("Mesh::AddElements");
2022-02-13 23:02:51 +05:00
static Timer timercast("Mesh::AddElements casting");
2022-02-13 21:29:53 +05:00
RegionTimer reg(timer);
2022-02-13 23:02:51 +05:00
timercast.Start();
auto b = b1.cast<py::array_t<int, py::array::c_style | py::array::forcecast>>();
timercast.Stop();
2022-02-13 21:29:53 +05:00
2022-02-13 20:31:55 +05:00
py::buffer_info info = b.request();
if (info.ndim != 2)
throw std::runtime_error("AddElements needs buffer of dimension 2");
2022-02-13 23:02:51 +05:00
// if (info.format != py::format_descriptor<int>::format())
// throw std::runtime_error("AddPoints needs buffer of type int");
2022-02-13 20:31:55 +05:00
int * ptr = static_cast<int*> (info.ptr);
2023-05-07 20:45:20 +05:00
if (dim == 1)
{
ELEMENT_TYPE type;
int np = info.shape[1];
self.LineSegments().SetAllocSize(self.LineSegments().Size()+info.shape[0]);
for (auto i : Range(info.shape[0]))
{
Segment el;
for (int j = 0; j < np; j++)
el[j] = ptr[j]+PointIndex::BASE-base;
el.si = index;
self.AddSegment(el);
ptr += info.strides[0]/sizeof(int);
}
}
2022-02-13 20:31:55 +05:00
if (dim == 2)
{
ELEMENT_TYPE type;
int np = info.shape[1];
switch (np)
{
case 3: type = TRIG; break;
case 4: type = QUAD; break;
case 6: type = TRIG6; break;
case 8: type = QUAD8; break;
default:
throw Exception("unsupported 2D element with "+ToString(np)+" points");
}
2022-02-13 21:29:53 +05:00
self.SurfaceElements().SetAllocSize(self.SurfaceElements().Size()+info.shape[0]);
2022-02-13 20:31:55 +05:00
for (auto i : Range(info.shape[0]))
{
Element2d el(type);
2023-05-07 20:45:20 +05:00
for (int j = 0; j < np; j++)
2022-02-13 20:31:55 +05:00
el[j] = ptr[j]+PointIndex::BASE-base;
el.SetIndex(index);
self.AddSurfaceElement (el);
ptr += info.strides[0]/sizeof(int);
}
}
if (dim == 3)
{
ELEMENT_TYPE type;
int np = info.shape[1];
switch (np)
{
case 4: type = TET; break;
/* // have to check ordering of points
case 10: type = TET10; break;
case 8: type = HEX; break;
case 6: type = PRISM; break;
*/
default:
throw Exception("unsupported 3D element with "+ToString(np)+" points");
}
2022-02-13 21:29:53 +05:00
self.VolumeElements().SetAllocSize(self.VolumeElements().Size()+info.shape[0]);
2022-02-13 20:31:55 +05:00
for (auto i : Range(info.shape[0]))
{
Element el(type);
for (int j = 0; j < np;j ++)
el[j] = ptr[j]+PointIndex::BASE-base;
el.SetIndex(index);
self.AddVolumeElement (el);
ptr += info.strides[0]/sizeof(int);
}
}
}, py::arg("dim"), py::arg("index"), py::arg("data"), py::arg("base")=0)
2016-12-15 17:05:34 +05:00
.def ("DeleteSurfaceElement",
2019-09-04 18:24:37 +05:00
[](Mesh & self, SurfaceElementIndex i)
{
return self.Delete(i);
})
.def ("Compress", [](Mesh & self)
{
return self.Compress ();
} ,py::call_guard<py::gil_scoped_release>())
2019-10-06 02:02:32 +05:00
.def ("AddRegion", [] (Mesh & self, string name, int dim) -> int
{
auto & regionnames = self.GetRegionNamesCD(self.GetDimension()-dim);
regionnames.Append (new string(name));
int idx = regionnames.Size();
if (dim == 2)
{
FaceDescriptor fd;
fd.SetBCName(regionnames.Last());
fd.SetBCProperty(idx);
self.AddFaceDescriptor(fd);
}
return idx;
}, py::arg("name"), py::arg("dim"))
2023-03-26 14:01:05 +05:00
.def ("GetRegionNames", [] (Mesh & self, optional<int> optdim, optional<int> optcodim)
{
int codim;
if (optdim)
codim = self.GetDimension() - *optdim;
else if (optcodim)
codim = *optcodim;
else
throw Exception("either 'dim' or 'codim' must be specified");
NgArray<string*> & codimnames = self.GetRegionNamesCD (codim);
std::vector<string> names;
for (auto name : codimnames)
{
if (name)
names.push_back(*name);
else
names.push_back("");
}
return names;
}, py::arg("dim")=nullopt, py::arg("codim")=nullopt)
2016-12-15 17:05:34 +05:00
2015-09-01 13:50:15 +05:00
.def ("SetBCName", &Mesh::SetBCName)
2015-09-01 22:21:52 +05:00
.def ("GetBCName", FunctionPointer([](Mesh & self, int bc)->string
{ return self.GetBCName(bc); }))
.def ("SetMaterial", &Mesh::SetMaterial)
.def ("GetMaterial", FunctionPointer([](Mesh & self, int domnr)
{ return string(self.GetMaterial(domnr)); }))
2016-10-20 16:19:24 +05:00
2016-11-18 20:57:42 +05:00
.def ("GetCD2Name", &Mesh::GetCD2Name)
2018-08-06 20:09:03 +05:00
.def ("SetCD2Name", &Mesh::SetCD2Name)
.def ("GetCD3Name", &Mesh::GetCD3Name)
.def ("SetCD3Name", &Mesh::SetCD3Name)
2016-11-18 20:57:42 +05:00
2021-11-28 20:14:41 +05:00
.def ("AddPointIdentification", [](Mesh & self, py::object pindex1, py::object pindex2, int identnr, Identifications::ID_TYPE type)
{
2016-11-16 20:13:17 +05:00
if(py::extract<PointIndex>(pindex1).check() && py::extract<PointIndex>(pindex2).check())
{
2016-11-16 20:13:17 +05:00
self.GetIdentifications().Add (py::extract<PointIndex>(pindex1)(), py::extract<PointIndex>(pindex2)(), identnr);
2021-11-28 20:14:41 +05:00
self.GetIdentifications().SetType(identnr, type); // type = 2 ... periodic
}
2016-11-16 20:13:17 +05:00
},
//py::default_call_policies(),
py::arg("pid1"),
py::arg("pid2"),
py::arg("identnr"),
2021-11-28 20:14:41 +05:00
py::arg("type")=Identifications::PERIODIC)
.def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries,
py::arg("face1"), py::arg("face2"), py::arg("mapping"), py::arg("point_tolerance") = -1.)
2020-03-17 19:32:42 +05:00
.def("GetNrIdentifications", [](Mesh& self)
{
return self.GetIdentifications().GetMaxNr();
})
.def ("CalcLocalH", &Mesh::CalcLocalH)
.def ("SetMaxHDomain", [] (Mesh& self, py::list maxhlist)
{
2019-07-09 13:39:16 +05:00
NgArray<double> maxh;
for(auto el : maxhlist)
maxh.Append(py::cast<double>(el));
self.SetMaxHDomain(maxh);
})
2016-11-16 20:13:17 +05:00
.def ("GenerateVolumeMesh",
[](Mesh & self, MeshingParameters* pars,
py::kwargs kwargs)
2015-08-29 16:54:00 +05:00
{
MeshingParameters mp;
if(pars) mp = *pars;
2018-03-13 02:38:21 +05:00
{
py::gil_scoped_acquire acquire;
CreateMPfromKwargs(mp, kwargs);
2018-03-13 02:38:21 +05:00
}
2015-08-29 16:54:00 +05:00
MeshVolume (mp, self);
2015-09-02 22:01:49 +05:00
OptimizeVolume (mp, self);
}, py::arg("mp")=nullptr,
meshingparameter_description.c_str(),
py::call_guard<py::gil_scoped_release>())
2015-08-29 16:54:00 +05:00
.def ("OptimizeVolumeMesh", [](Mesh & self, MeshingParameters* pars)
2015-12-11 18:31:28 +05:00
{
MeshingParameters mp;
if(pars) mp = *pars;
else mp.optsteps3d = 5;
2015-12-11 18:31:28 +05:00
OptimizeVolume (mp, self);
}, py::arg("mp"), py::call_guard<py::gil_scoped_release>())
2015-12-11 18:31:28 +05:00
.def ("OptimizeMesh2d", [](Mesh & self, MeshingParameters* pars)
2019-04-10 17:13:12 +05:00
{
self.CalcLocalH(0.5);
MeshingParameters mp;
if(pars) mp = *pars;
else mp.optsteps2d = 5;
if(!self.GetGeometry())
throw Exception("Cannot optimize surface mesh without geometry!");
2019-04-10 17:13:12 +05:00
Optimize2d (self, mp);
}, py::arg("mp")=nullptr, py::call_guard<py::gil_scoped_release>())
2019-04-10 17:13:12 +05:00
2015-08-29 16:54:00 +05:00
.def ("Refine", FunctionPointer
([](Mesh & self, bool adaptive)
2015-08-29 16:54:00 +05:00
{
if (!adaptive)
{
self.GetGeometry()->GetRefinement().Refine(self);
self.UpdateTopology();
}
else
{
BisectionOptions biopt;
biopt.usemarkedelements = 1;
biopt.refine_p = 0;
biopt.refine_hp = 0;
/*
biopt.onlyonce = onlyonce;
if (reftype == NG_REFINE_P)
biopt.refine_p = 1;
if (reftype == NG_REFINE_HP)
biopt.refine_hp = 1;
*/
self.GetGeometry()->GetRefinement().Bisect (self, biopt);
self.UpdateTopology();
self.GetCurvedElements().SetIsHighOrder (false);
}
}), py::arg("adaptive")=false, py::call_guard<py::gil_scoped_release>())
2022-02-23 16:22:19 +05:00
.def("ZRefine", &Mesh::ZRefine)
2017-06-01 02:44:50 +05:00
.def ("SecondOrder", FunctionPointer
([](Mesh & self)
{
self.GetGeometry()->GetRefinement().MakeSecondOrder(self);
2017-06-01 02:44:50 +05:00
}))
2017-12-06 18:16:52 +05:00
.def ("GetGeometry", [] (Mesh& self) { return self.GetGeometry(); })
.def ("SetGeometry", [](Mesh & self, shared_ptr<NetgenGeometry> geo)
2016-05-09 12:48:33 +05:00
{
self.SetGeometry(geo);
2017-12-06 18:16:52 +05:00
})
2016-05-09 12:48:33 +05:00
/*
.def ("SetGeometry", FunctionPointer
([](Mesh & self, shared_ptr<CSGeometry> geo)
{
self.SetGeometry(geo);
}))
*/
2018-03-13 02:38:21 +05:00
.def ("BuildSearchTree", &Mesh::BuildElementSearchTree,py::call_guard<py::gil_scoped_release>())
2016-05-06 00:26:33 +05:00
.def ("BoundaryLayer2", GenerateBoundaryLayer2, py::arg("domain"), py::arg("thicknesses"), py::arg("make_new_domain")=true, py::arg("boundaries")=Array<int>{})
.def ("BoundaryLayer", [](Mesh & self, variant<string, int> boundary,
variant<double, py::list> thickness,
variant<string, map<string, string>> material,
variant<string, int> domain, bool outside,
optional<string> project_boundaries,
bool grow_edges, bool limit_growth_vectors,
bool sides_keep_surfaceindex)
{
BoundaryLayerParameters blp;
BitArray boundaries(self.GetNFD()+1);
2022-07-12 12:58:35 +05:00
boundaries.Clear();
if(int* bc = get_if<int>(&boundary); bc)
{
for (int i = 1; i <= self.GetNFD(); i++)
if(self.GetFaceDescriptor(i).BCProperty() == *bc)
boundaries.SetBit(i);
}
else
{
regex pattern(*get_if<string>(&boundary));
for(int i = 1; i<=self.GetNFD(); i++)
{
auto& fd = self.GetFaceDescriptor(i);
if(regex_match(fd.GetBCName(), pattern))
{
2022-07-12 12:58:35 +05:00
boundaries.SetBit(i);
auto dom_pattern = get_if<string>(&domain);
// only add if adjacent to domain
if(dom_pattern)
{
regex pattern(*dom_pattern);
bool mat1_match = fd.DomainIn() > 0 && regex_match(self.GetMaterial(fd.DomainIn()), pattern);
bool mat2_match = fd.DomainOut() > 0 && regex_match(self.GetMaterial(fd.DomainOut()), pattern);
// if boundary is inner or outer remove from list
if(mat1_match == mat2_match)
boundaries.Clear(i);
// if((fd.DomainIn() > 0 && regex_match(self.GetMaterial(fd.DomainIn()), pattern)) || (fd.DomainOut() > 0 && regex_match(self.GetMaterial(fd.DomainOut()), pattern)))
// boundaries.Clear(i);
// blp.surfid.Append(i);
}
// else
// blp.surfid.Append(i);
}
}
}
for(int i = 1; i<=self.GetNFD(); i++)
if(boundaries.Test(i))
blp.surfid.Append(i);
if(string* mat = get_if<string>(&material); mat)
blp.new_mat = { { ".*", *mat } };
else
blp.new_mat = *get_if<map<string, string>>(&material);
if(project_boundaries.has_value())
{
regex pattern(*project_boundaries);
for(int i = 1; i<=self.GetNFD(); i++)
if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern))
blp.project_boundaries.Append(i);
}
if(double* pthickness = get_if<double>(&thickness); pthickness)
{
blp.heights.Append(*pthickness);
}
else
{
auto thicknesses = *get_if<py::list>(&thickness);
for(auto val : thicknesses)
blp.heights.Append(val.cast<double>());
}
int nr_domains = self.GetNDomains();
blp.domains.SetSize(nr_domains + 1); // one based
2020-04-23 18:44:32 +05:00
blp.domains.Clear();
if(string* pdomain = get_if<string>(&domain); pdomain)
{
regex pattern(*pdomain);
for(auto i : Range(1, nr_domains+1))
2020-04-23 18:44:32 +05:00
if(regex_match(self.GetMaterial(i), pattern))
blp.domains.SetBit(i);
}
2020-04-23 18:44:32 +05:00
else
{
auto idomain = *get_if<int>(&domain);
blp.domains.SetBit(idomain);
}
blp.outside = outside;
blp.grow_edges = grow_edges;
blp.limit_growth_vectors = limit_growth_vectors;
blp.sides_keep_surfaceindex = sides_keep_surfaceindex;
GenerateBoundaryLayer (self, blp);
2020-04-23 18:44:32 +05:00
self.UpdateTopology();
}, py::arg("boundary"), py::arg("thickness"), py::arg("material"),
2020-04-23 18:44:32 +05:00
py::arg("domains") = ".*", py::arg("outside") = false,
py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, py::arg("limit_growth_vectors") = true, py::arg("sides_keep_surfaceindex")=false,
2020-04-23 18:44:32 +05:00
R"delimiter(
Add boundary layer to mesh.
Parameters
----------
2014-12-18 21:46:54 +05:00
boundary : string or int
Boundary name or number.
2014-12-18 21:46:54 +05:00
thickness : float or List[float]
Thickness of boundary layer(s).
2014-12-18 21:46:54 +05:00
material : str or List[str]
Material name of boundary layer(s).
2014-12-18 21:46:54 +05:00
2020-04-23 18:44:32 +05:00
domain : str or int
Regexp for domain boundarylayer is going into.
outside : bool = False
If true add the layer on the outside
grow_edges : bool = False
Grow boundary layer over edges.
project_boundaries : Optional[str] = None
Project boundarylayer to these boundaries if they meet them. Set
to boundaries that meet boundarylayer at a non-orthogonal edge and
layer-ending should be projected to that boundary.
)delimiter")
2016-10-28 19:49:50 +05:00
.def_static ("EnableTableClass", [] (string name, bool set)
{
MeshTopology::EnableTableStatic(name, set);
},
py::arg("name"), py::arg("set")=true)
.def ("EnableTable", [] (Mesh & self, string name, bool set)
{
2021-02-18 03:32:15 +05:00
const_cast<MeshTopology&>(self.GetTopology()).EnableTable(name, set);
},
py::arg("name"), py::arg("set")=true)
2019-04-10 17:13:12 +05:00
.def ("Scale", [](Mesh & self, double factor)
{
2020-12-02 21:51:47 +05:00
for(auto & pnt : self.Points())
pnt.Scale(factor);
2019-04-10 17:13:12 +05:00
})
.def ("Copy", [](Mesh & self)
{
auto m2 = make_shared<Mesh> ();
*m2 = self;
return m2;
})
2019-09-16 15:11:49 +05:00
.def ("CalcMinMaxAngle", [](Mesh & self, double badel_limit)
{
double values[4];
self.CalcMinMaxAngle (badel_limit, values);
py::dict res;
res["trig"] = py::make_tuple( values[0], values[1] );
res["tet"] = py::make_tuple( values[2], values[3] );
return res;
}, py::arg("badelement_limit")=175.0)
2020-03-30 23:44:39 +05:00
.def ("Update", [](Mesh & self)
{
self.SetNextTimeStamp();
})
2019-10-04 15:25:14 +05:00
.def ("CalcTotalBadness", &Mesh::CalcTotalBad)
.def ("GetQualityHistogram", &Mesh::GetQualityHistogram)
2022-02-19 00:11:58 +05:00
.def("Mirror", &Mesh::Mirror)
.def("_getVertices", [](Mesh & self)
{
// std::vector<float> verts(3*self.GetNV());
Array<float> verts(3*self.GetNV());
2022-02-19 00:11:58 +05:00
ParallelForRange( self.GetNV(), [&](auto myrange) {
const auto & points = self.Points();
for(auto i : myrange)
{
auto p = points[PointIndex::BASE+i];
auto * v = &verts[3*i];
for(auto k : Range(3))
v[k] = p[k];
} });
return verts;
})
.def("_getSegments", [](Mesh & self)
{
// std::vector<int> output;
// output.resize(2*self.GetNSeg());
Array<int> output(2*self.GetNSeg());
2022-02-19 00:11:58 +05:00
ParallelForRange( self.GetNSeg(), [&](auto myrange) {
const auto & segs = self.LineSegments();
for(auto i : myrange)
{
const auto & seg = segs[i];
for(auto k : Range(2))
output[2*i+k] = seg[k]-PointIndex::BASE;
} });
return output;
})
.def("_getWireframe", [](Mesh & self)
{
const auto & topo = self.GetTopology();
size_t n = topo.GetNEdges();
/*
2022-02-19 00:11:58 +05:00
std::vector<int> output;
output.resize(2*n);
*/
Array<int> output(2*n);
2022-02-19 00:11:58 +05:00
ParallelForRange( n, [&](auto myrange) {
for(auto i : myrange)
{
PointIndex p0,p1;
topo.GetEdgeVertices(i+1, p0, p1);
output[2*i] = p0-PointIndex::BASE;
output[2*i+1] = p1-PointIndex::BASE;
} });
return output;
})
.def("_get2dElementsAsTriangles", [](Mesh & self)
{
/*
2022-02-19 00:11:58 +05:00
std::vector<int> trigs;
trigs.resize(3*self.GetNSE());
*/
Array<int> trigs(3*self.GetNSE());
2022-02-19 00:11:58 +05:00
ParallelForRange( self.GetNSE(), [&](auto myrange) {
const auto & surfels = self.SurfaceElements();
for(auto i : myrange)
{
const auto & sel = surfels[i];
auto * trig = &trigs[3*i];
for(auto k : Range(3))
trig[k] = sel[k]-PointIndex::BASE;
// todo: quads (store the second trig in thread-local extra array, merge them at the end (mutex)
} });
return trigs;
})
.def("_get3dElementsAsTets", [](Mesh & self)
{
// std::vector<int> tets;
// tets.resize(4*self.GetNE());
2022-02-19 00:11:58 +05:00
Array<int> tets(4*self.GetNE());
2022-02-19 00:11:58 +05:00
ParallelForRange( self.GetNE(), [&](auto myrange) {
const auto & els = self.VolumeElements();
for(auto i : myrange)
{
const auto & el = els[i];
auto * trig = &tets[4*i];
for(auto k : Range(4))
trig[k] = el[k]-PointIndex::BASE;
// todo: prisms etc (store the extra tets in thread-local extra array, merge them at the end (mutex)
} });
return tets;
})
2014-08-31 15:14:18 +06:00
;
2014-08-30 06:15:59 +06:00
m.def("ImportMesh", [](const string& filename)
{
auto mesh = make_shared<Mesh>();
ReadFile(*mesh, filename);
return mesh;
}, py::arg("filename"),
R"delimiter(Import mesh from other file format, supported file formats are:
Neutral format (*.mesh, *.emt)
Surface file (*.surf)
Universal format (*.unv)
Olaf format (*.emt)
Tet format (*.tet)
Pro/ENGINEER format (*.fnf)
)delimiter");
2016-12-05 18:39:09 +05:00
py::enum_<MESHING_STEP>(m,"MeshingStep")
2019-09-23 14:22:34 +05:00
.value("ANALYSE", MESHCONST_ANALYSE)
.value("MESHEDGES", MESHCONST_MESHEDGES)
.value("MESHSURFACE", MESHCONST_OPTSURFACE)
.value("MESHVOLUME", MESHCONST_OPTVOLUME)
2016-12-05 18:39:09 +05:00
;
2018-03-09 02:19:11 +05:00
2014-08-31 15:14:18 +06:00
typedef MeshingParameters MP;
auto mp = py::class_<MP> (m, "MeshingParameters")
2016-11-04 16:14:52 +05:00
.def(py::init<>())
.def(py::init([](MeshingParameters* other, py::kwargs kwargs)
2018-03-09 02:19:11 +05:00
{
MeshingParameters mp;
if(other) mp = *other;
CreateMPfromKwargs(mp, kwargs, false);
return mp;
}), py::arg("mp")=nullptr, meshingparameter_description.c_str())
2014-08-31 15:14:18 +06:00
.def("__str__", &ToString<MP>)
2021-01-26 19:33:21 +05:00
.def("RestrictH", [](MP & mp, double x, double y, double z, double h)
{
2021-01-26 19:33:21 +05:00
mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint(Point<3> (x,y,z), h));
}, py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h")
)
2021-01-26 19:33:21 +05:00
.def("RestrictH", [](MP & mp, const Point<3>& p, double h)
{
mp.meshsize_points.Append ({p, h});
}, py::arg("p"), py::arg("h"))
.def("RestrictHLine", [](MP& mp, const Point<3>& p1, const Point<3>& p2,
double maxh)
{
int steps = int(Dist(p1, p2) / maxh) + 2;
auto v = p2 - p1;
for (int i = 0; i <= steps; i++)
{
mp.meshsize_points.Append({p1 + double(i)/steps * v, maxh});
}
}, py::arg("p1"), py::arg("p2"), py::arg("maxh"))
2014-08-30 06:15:59 +06:00
;
2014-12-05 21:00:01 +05:00
2016-11-04 16:14:52 +05:00
m.def("SetTestoutFile", FunctionPointer ([] (const string & filename)
2014-12-05 21:00:01 +05:00
{
delete testout;
testout = new ofstream (filename);
}));
2014-12-09 19:58:26 +05:00
2016-11-04 16:14:52 +05:00
m.def("SetMessageImportance", FunctionPointer ([] (int importance)
2014-12-09 19:58:26 +05:00
{
int old = printmessage_importance;
printmessage_importance = importance;
return old;
}));
2019-01-31 00:55:45 +05:00
py::class_<DebugParameters> (m, "_DebugParameters")
.def_readwrite("debugoutput", &DebugParameters::debugoutput)
.def_readwrite("slowchecks", &DebugParameters::slowchecks)
.def_readwrite("haltsuccess", &DebugParameters::haltsuccess)
.def_readwrite("haltnosuccess", &DebugParameters::haltnosuccess)
.def_readwrite("haltlargequalclass", &DebugParameters::haltlargequalclass)
.def_readwrite("haltsegment", &DebugParameters::haltsegment)
.def_readwrite("haltnode", &DebugParameters::haltnode)
.def_readwrite("haltsegmentp1", &DebugParameters::haltsegmentp1)
.def_readwrite("haltsegmentp2", &DebugParameters::haltsegmentp2)
.def_readwrite("haltexistingline", &DebugParameters::haltexistingline)
.def_readwrite("haltoverlap", &DebugParameters::haltoverlap)
.def_readwrite("haltface", &DebugParameters::haltface)
.def_readwrite("haltfacenr", &DebugParameters::haltfacenr)
.def_readwrite("write_mesh_on_error", &DebugParameters::write_mesh_on_error)
;
m.attr("debugparam") = py::cast(&debugparam);
2019-01-31 00:55:45 +05:00
2020-03-11 15:48:05 +05:00
m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file");
2020-08-04 14:12:47 +05:00
m.def("WriteCGNSFile", &WriteCGNSFile, py::arg("mesh"), py::arg("filename"), py::arg("names"), py::arg("values"), py::arg("locations"),
R"(Write mesh and solution vectors to CGNS file, possible values for locations:
Vertex = 0
EdgeCenter = 1
FaceCenter = 2
CellCenter = 3
)");
2020-06-24 11:41:55 +05:00
py::class_<SurfaceGeometry, NetgenGeometry, shared_ptr<SurfaceGeometry>> (m, "SurfaceGeometry")
.def(py::init<>())
.def(py::init([](py::object pyfunc)
{
std::function<Vec<3> (Point<2>)> func = [pyfunc](Point<2> p)
{
py::gil_scoped_acquire aq;
py::tuple pyres = py::extract<py::tuple>(pyfunc(p[0],p[1],0.0)) ();
return Vec<3>(py::extract<double>(pyres[0])(),py::extract<double>(pyres[1])(),py::extract<double>(pyres[2])());
};
auto geo = make_shared<SurfaceGeometry>(func);
return geo;
}), py::arg("mapping"))
.def(NGSPickle<SurfaceGeometry>())
.def("GenerateMesh", [](shared_ptr<SurfaceGeometry> geo,
2023-06-21 19:44:21 +05:00
bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames, py::list py_hppnts, py::dict/*list*/ py_hpbnd, py::dict py_layers)
2020-06-24 11:41:55 +05:00
{
if (py::len(py_bbbpts) != py::len(py_bbbnames))
throw Exception("In SurfaceGeometry::GenerateMesh bbbpts and bbbnames do not have same lengths.");
Array<Point<3>> bbbpts(py::len(py_bbbpts));
Array<string> bbbname(py::len(py_bbbpts));
2023-06-21 19:44:21 +05:00
Array<Point<3>> hppnts(py::len(py_hppnts));
Array<float> hppntsfac(py::len(py_hppnts));
Array<string> hpbnd(py::len(py_hpbnd));
Array<float> hpbndfac(py::len(py_hpbnd));
2020-06-24 11:41:55 +05:00
for(int i = 0; i<py::len(py_bbbpts);i++)
{
py::tuple pnt = py::extract<py::tuple>(py_bbbpts[i])();
bbbpts[i] = Point<3>(py::extract<double>(pnt[0])(),py::extract<double>(pnt[1])(),py::extract<double>(pnt[2])());
bbbname[i] = py::extract<string>(py_bbbnames[i])();
}
2023-06-21 19:44:21 +05:00
for(int i = 0; i<py::len(py_hppnts);i++)
{
2023-06-21 19:44:21 +05:00
py::tuple pnt = py::extract<py::tuple>(py_hppnts[i])();
hppnts[i] = Point<3>(py::extract<double>(pnt[0])(),py::extract<double>(pnt[1])(),py::extract<double>(pnt[2])());
hppntsfac[i] = py::extract<double>(pnt[3])();
}
2023-06-21 19:44:21 +05:00
int ii=0;
for(auto val : py_hpbnd)
{
hpbnd[ii] = py::cast<string>(val.first);
hpbndfac[ii] = py::cast<float>(val.second);
ii++;
}
Array<double> layer_thickness[4];
bool layer_quad = false;
for(auto val : py_layers)
{
int index = -1;
if (py::cast<string>(val.first) == "left") index = 0;
else if (py::cast<string>(val.first) == "top") index = 3;
else if (py::cast<string>(val.first) == "right") index = 2;
else if (py::cast<string>(val.first) == "bottom") index = 1;
else if (py::cast<string>(val.first) == "quads") layer_quad = py::cast<bool>(val.second);
else throw Exception("Unknown parameter " + string(py::cast<string>(val.first)));
if (index < 0) continue;
auto list = py::cast<py::list>(val.second);
layer_thickness[index] = Array<double>(py::len(list));
for (size_t i = 0; i < py::len(list); i++)
layer_thickness[index][i] = py::cast<double>(list[i]);
}
2020-06-24 11:41:55 +05:00
auto mesh = make_shared<Mesh>();
SetGlobalMesh (mesh);
mesh->SetGeometry(geo);
ng_geometry = geo;
2023-06-21 19:44:21 +05:00
auto result = geo->GenerateStructuredMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname, hppnts, hppntsfac, hpbnd, hpbndfac, layer_thickness, layer_quad);
2020-06-24 11:41:55 +05:00
if(result != 0)
throw Exception("SurfaceGeometry: Meshing failed!");
return mesh;
2023-06-21 19:44:21 +05:00
}, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list(), py::arg("hppnts")=py::list(), py::arg("hpbnd")=py::dict(), py::arg("boundarylayer")=py::dict());/*, R"raw_string(
Generate a structured 2D surface mesh
Parameters:
quads : bool
If True, a quadrilateral mesh is generated. If False, the quads are split to triangles.
nx : int
Number of cells in x-direction.
ny : int
Number of cells in y-direction.
flip_triangles : bool
If set to True together with quads=False the quads are cut the other way round
bbbpts : list
List of points which should be handled as BBBND and are named with bbbnames. The mesh must be constructed in such a way that the bbbpts coincide with generated points.
bbbnames : list
List of bbbnd names as strings. Size must coincide with size of bbbpts.
hppnts : list
If not None it expects a list of the form [ (px1,py1,pz1, hpref1), (px2,py2,pz2, hpref2), ... ] where px,py,pz are the point coordinates which have to be resolved in the mesh and hpref the refinement factor.
hpbnd : dict
If not None it expects a dictionary of the form {"boundaryname" : hpref } where boundaryname in [left, right, top, bottom] and hpref the refinement factor.
boundarylayer : dict
If not None it expects a dictionary of the form { "boundaryname" : [t1,...,tn], "quads" : False } where ti denote the thickness of layer i. The number of layers are included in nx/ny. After the layers are placed the remaining number of cells are used to divide the remaining grid uniformly. If quads are set to True quadrilaterals are used inside the boundarylayer. If set False the value of "quads" of the function call is used.
)raw_string");*/
2020-06-24 11:41:55 +05:00
;
py::class_<ClearSolutionClass> (m, "ClearSolutionClass")
.def(py::init<>())
;
2020-08-19 17:50:11 +05:00
m.def("SetParallelPickling", [](bool par) { parallel_pickling = par; });
m.def ("_Redraw",
([](bool blocking, double fr)
{
static auto last_time = std::chrono::system_clock::now()-std::chrono::seconds(10);
auto now = std::chrono::system_clock::now();
double elapsed = std::chrono::duration<double>(now-last_time).count();
if (blocking || elapsed * fr > 1)
{
Ng_Redraw(blocking);
last_time = std::chrono::system_clock::now();
return true;
}
return false;
}),
py::arg("blocking")=false, py::arg("fr") = 25, R"raw_string(
Redraw all
Parameters:
blocking : bool
input blocking
fr : double
input framerate
)raw_string");
2014-08-30 06:15:59 +06:00
}
PYBIND11_MODULE(libmesh, m) {
2016-11-04 16:14:52 +05:00
ExportNetgenMeshing(m);
2014-08-30 06:15:59 +06:00
}
2014-08-31 19:05:24 +06:00
#endif
2014-08-30 06:15:59 +06:00