Loading...
Searching...
No Matches
RBF_example_00001.cpp
1#if BITPIT_ENABLE_MPI==1
2#include <mpi.h>
3#endif
4
5#include "bitpit_surfunstructured.hpp"
6#include "bitpit_voloctree.hpp"
7#include "bitpit_levelset.hpp"
8#include "bitpit_LA.hpp"
9#include "bitpit_operators.hpp"
10#include "bitpit_IO.hpp"
11#include "bitpit_RBF.hpp"
12#include "bitpit_common.hpp"
13
14#include <array>
15#include <fstream>
16#include <iostream>
17#include <string>
18#include <vector>
19#include <numeric>
20#include <algorithm>
21#include <iomanip>
22
23using namespace std;
24using namespace bitpit;
25
67void
68parse_parameters(std::map<std::string, std::vector<double>> &map,
69 std::string file,
70 const std::string delimiter)
71{
72 // fill a pair, first being a vector of vector name and the second being the
73 // vector of vector associated with the vector name.
74 std::ifstream myfile(file);
75 // open the file.
76 if (myfile.is_open())
77 {
78 std::string line;
79 std::vector<std::string> column_names;
80 std::vector<double> line_of_data;
81 unsigned int line_count = 0;
82
83 while (std::getline(myfile, line))
84 {
85 // read the line and clean the resulting vector.
86 std::vector<std::string> list_of_words_base;
87
88 std::string s = line;
89 size_t pos = 0;
90 std::string token;
91 while ((pos = s.find(delimiter)) != std::string::npos) {
92 token = s.substr(0, pos);
93 list_of_words_base.push_back(token);
94 s.erase(0, pos + delimiter.length());
95 }
96 std::vector<std::string> list_of_words_clean;
97 for (std::size_t i = 0; i < list_of_words_base.size(); ++i)
98 {
99 if (list_of_words_base[i] != "")
100 {
101 list_of_words_clean.push_back(list_of_words_base[i]);
102 }
103 }
104 // check if the line is contained words or numbers.
105 if (line_count != 0)
106 {
107 line_of_data.resize(list_of_words_clean.size());
108 for (std::size_t i = 0; i < line_of_data.size(); i++)
109 {
110 line_of_data[i] = std::stod(list_of_words_clean[i]);
111 }
112 for (std::size_t i = 0; i < line_of_data.size(); ++i)
113 {
114 map[column_names[i]].push_back(line_of_data[i]);
115 }
116 }
117 else
118 {
119 // the line contains words, we assume these are the columns names.
120 column_names = list_of_words_clean;
121 for (std::size_t i = 0; i < list_of_words_clean.size(); ++i)
122 {
123 std::vector<double> base_vector;
124 map[column_names[i]] = base_vector;
125 }
126 }
127 ++line_count;
128 }
129 myfile.close();
130 }
131 else
132 std::cout << "Unable to open file";
133
134 // We add here the default values
135 std::vector<std::string> names = {"nb_subdivision",
136 "nb_adaptions",
137 "radius_ratio",
138 "base_function",
139 "mesh_range",
140 "tolerance",
141 "scaling"};
142 std::vector<double> values = {16,
143 0,
144 1,
145 2,
146 0.2,
147 1e-8,
148 1.0};
149 for (std::size_t i = 0; i < names.size(); i++)
150 {
151 if (map.find("f") == map.end())
152 map[names[i]].push_back(values[i]);
153 }
154}
155
156void run(std::string filename,
157 std::string data_path,
158 std::string parameter_file) {
159 constexpr int dimensions(3);
160
161 // Parsing the parameters
162 std::map<std::string, std::vector<double>> parameters;
163 parse_parameters(parameters, parameter_file," ");
164 int nb_subdivision = static_cast<int>(parameters["nb_subdivision"][0]);
165 int nb_adaptions = static_cast<int>(parameters["nb_adaptions"][0]);
166 double radius_ratio = parameters["radius_ratio"][0];
167 int base_function = static_cast<int>(parameters["base_function"][0]);
168 double mesh_range = parameters["mesh_range"][0];
169 double TOL = parameters["tolerance"][0];
170 double scaling = parameters["scaling"][0];
171
172 std::vector<std::string> timers_name;
173 std::vector<double> timers_values;
174
175 timers_name.push_back("load_geometry");
176 double time_start = MPI_Wtime();
177
178 //LEVELSET PART
179 //Input geometry
180#if BITPIT_ENABLE_MPI
181 std::unique_ptr<bitpit::SurfUnstructured> STL0(new bitpit::SurfUnstructured(dimensions - 1, MPI_COMM_NULL));
182#else
183 std::unique_ptr<bitpit::SurfUnstructured> STL0( new bitpit::SurfUnstructured (dimensions - 1) );
184#endif
185 bitpit::log::cout() << " - Loading stl geometry" << std::endl;
186 // Make sure that the STL format is in binary (not ASCII)
187 try {
188 STL0->importSTL(data_path + filename + ".stl", true);
189 }
190 catch (const std::bad_alloc &) {
191 STL0->importSTL(data_path + filename + ".stl", false);
192 }
193 STL0->deleteCoincidentVertices();
194 STL0->initializeAdjacencies();
195 STL0->getVTK().setName("levelset");
196 std::array<double, dimensions> center{};
197 STL0->scale(scaling,scaling,scaling,center);
198 bitpit::log::cout() << "n. vertex: " << STL0->getVertexCount() << std::endl;
199 bitpit::log::cout() << "n. simplex: " << STL0->getCellCount() << std::endl;
200 // Create initial octree mesh for levelset
201 bitpit::log::cout() << " - Setting mesh" << std::endl;
202 std::array<double, dimensions> stlMin, stlMax, meshMin, meshMax, delta;
203 double h(0.), dh;
204 STL0->getBoundingBox(stlMin, stlMax);
205 bitpit::log::cout() << " Bounding box minima " << std::endl;
206 bitpit::log::cout() << stlMin << std::endl;
207 bitpit::log::cout() << " Bounding box maxima " << std::endl;
208 bitpit::log::cout() << stlMax << std::endl;
209 bitpit::log::cout() << " Bounding box center " << std::endl;
210 bitpit::log::cout() << 0.5*(stlMax+stlMin) << std::endl;
211
212 delta = stlMax - stlMin;
213 meshMin = stlMin - mesh_range * delta;
214 meshMax = stlMax + mesh_range * delta;
215 for (int i = 0; i < dimensions; ++i) {
216 h = std::max(h, meshMax[i] - meshMin[i]);
217 }
218 dh = h / nb_subdivision;
219#if BITPIT_ENABLE_MPI
220 bitpit::VolOctree mesh(dimensions, meshMin, h, dh, MPI_COMM_NULL);
221#else
222 bitpit::VolOctree mesh(dimensions, meshMin, h, dh);
223#endif
224 mesh.initializeAdjacencies();
225 mesh.initializeInterfaces();
226 mesh.update();
227 mesh.getVTK().setName("RBF_" + filename);
228#if BITPIT_ENABLE_MPI
229 mesh.setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_INTERNAL);
230#endif
231
232 timers_values.push_back(MPI_Wtime() - time_start);
233 timers_name.push_back("compute_levelset");
234 time_start = MPI_Wtime();
235
236
237 // Set levelset configuration
238 bitpit::LevelSet levelset;
239 levelset.setNarrowBandSize(sqrt(3.0) * h);
240 levelset.setMesh(&mesh);
241
242 int id0 = levelset.addObject(std::move(STL0), 0);
243 const bitpit::LevelSetObject &object0 = levelset.getObject(id0);
246
247 // Write levelset information
248 mesh.write();
249 bitpit::log::cout() << "Computed levelset within the narrow band... " << std::endl;
250
251
252 // Adaptative Refinement
253 std::vector<bitpit::adaption::Info> adaptionData_levelset;
254 for (int r = 0; r < nb_adaptions; ++r) {
255 for (auto &cell: mesh.getCells()) {
256 long cellId = cell.getId();
257 if (object0.evalCellValue(cellId, false) < mesh.evalCellSize(cellId))
258 mesh.markCellForRefinement(cellId);
259 }
260 adaptionData_levelset = mesh.update(true);
261 levelset.update(adaptionData_levelset);
262 mesh.write();
263 }
264 unsigned long nP_total = mesh.getCellCount();
265
266
267 timers_values.push_back(MPI_Wtime() - time_start);
268 timers_name.push_back("add_nodes_to_RBF");
269 time_start = MPI_Wtime();
270
271
272 // RBF PART
273 bitpit::RBFBasisFunction basisFunction;
274 switch (base_function) {
275 case 0:
276 basisFunction = bitpit::RBFBasisFunction::CUSTOM;
277 break;
278 case 1:
280 break;
281 case 2:
282 basisFunction = bitpit::RBFBasisFunction::LINEAR;
283 break;
284 case 3:
285 basisFunction = bitpit::RBFBasisFunction::GAUSS90;
286 break;
287 case 4:
288 basisFunction = bitpit::RBFBasisFunction::GAUSS95;
289 break;
290 case 5:
291 basisFunction = bitpit::RBFBasisFunction::GAUSS99;
292 break;
293 case 6:
294 basisFunction = bitpit::RBFBasisFunction::C1C0;
295 break;
296 case 7:
297 basisFunction = bitpit::RBFBasisFunction::C2C0;
298 break;
299 case 8:
300 basisFunction = bitpit::RBFBasisFunction::C0C1;
301 break;
302 case 9:
303 basisFunction = bitpit::RBFBasisFunction::C1C1;
304 break;
305 case 10:
306 basisFunction = bitpit::RBFBasisFunction::C2C1;
307 break;
308 case 11:
309 basisFunction = bitpit::RBFBasisFunction::C0C2;
310 break;
311 case 12:
312 basisFunction = bitpit::RBFBasisFunction::C1C2;
313 break;
314 case 13:
315 basisFunction = bitpit::RBFBasisFunction::C2C2;
316 break;
317 case 14:
318 basisFunction = bitpit::RBFBasisFunction::COSINUS;
319 break;
320 default:
321 basisFunction = bitpit::RBFBasisFunction::LINEAR;
322 break;
323 }
324 std::vector<double> values;
325 std::vector<double> weights;
326 std::vector<double> radii;
327 std::vector<std::array<double, dimensions>> nodes;
328 values.resize(nP_total);
329 weights.resize(nP_total);
330 nodes.resize(nP_total);
331 radii.resize(nP_total);
332
333 bitpit::RBF RBFObject;
335 RBFObject.setFunction(basisFunction);
336
337 bitpit::log::cout() << "Adding nodes to the RBF" << std::endl;
338 for (size_t it_RBF = 0; it_RBF < nP_total; it_RBF++) {
339 nodes[it_RBF] = mesh.evalCellCentroid(it_RBF);
340 values[it_RBF] = levelset.getObject(id0).evalCellValue(it_RBF, true);
341 RBFObject.addNode(nodes[it_RBF]);
342 radii[it_RBF] = mesh.evalCellSize(it_RBF) * radius_ratio;
343 }
344 RBFObject.setSupportRadius(radii);
345
346 timers_values.push_back(MPI_Wtime() - time_start);
347 timers_name.push_back("fill_matrix");
348 time_start = MPI_Wtime();
349
350 // Training the RBF
351 bitpit::log::cout() << "Training RBFObject" << std::endl;
352 // Initializing the matrix and vector
353 int nNZ = nP_total*(1+(2*(int)ceil(radius_ratio)^dimensions));
354#if BITPIT_ENABLE_MPI==1
355 SparseMatrix A(MPI_COMM_WORLD, true, nP_total, nP_total, nNZ);
356#else
357 SparseMatrix A(nP_total, nP_total, nNZ);
358#endif
359
360 std::vector<long> rowPattern;
361 std::vector<double> rowValues;
362 // Compute the values for A
363 bitpit::log::cout() << "Filling the matrix" << std::endl;
364 for (unsigned long i = 0; i < nP_total; i++) {
365 for (unsigned long j = 0; j < nP_total; j++) {
366 double v_ij = RBFObject.evalBasisPair(i,j);
367 if (abs(v_ij) > TOL) {
368 rowPattern.push_back(j);
369 rowValues.push_back(v_ij);
370 }
371 }
372 A.addRow(rowPattern, rowValues);
373 rowPattern.clear();
374 rowValues.clear();
375 }
376 A.assembly();
377
378 SystemSolver system;
379 system.assembly(A);
380
381 timers_values.push_back(MPI_Wtime() - time_start);
382 timers_name.push_back("fill_RHS");
383 time_start = MPI_Wtime();
384
385 double *b = system.getRHSRawPtr();
386 // Compute the values for b
387 bitpit::log::cout() << "Filling the RHS" << std::endl;
388 for (unsigned long i = 0; i < nP_total; ++i) {
389 b[i] = values[i];
390 }
391 system.restoreRHSRawPtr(b);
392
393 timers_values.push_back(MPI_Wtime() - time_start);
394 timers_name.push_back("solve_system");
395 time_start = MPI_Wtime();
396
397 bitpit::log::cout() << "Solving the system" << std::endl;
398
399 double *initialSolution = system.getSolutionRawPtr();
400 for (unsigned long i = 0; i < nP_total; ++i) {
401 initialSolution[i] = values[i];
402 }
403 system.restoreSolutionRawPtr(initialSolution);
404
405 system.solve();
406 const double *x = system.getSolutionRawReadPtr();
407 bitpit::log::cout() << "Solved system" << std::endl;
408
409 timers_values.push_back(MPI_Wtime() - time_start);
410 timers_name.push_back("add_weights_to_RBFObject");
411 time_start = MPI_Wtime();
412
413 bitpit::log::cout() << "Adding weights to RBFObject" << std::endl;
414 for (unsigned long i = 0; i < nP_total; i++) {
415 weights[i] = x[i];
416 }
417 system.restoreSolutionRawPtr(initialSolution);
418 RBFObject.addData(weights);
419 bitpit::log::cout() << "Added weights to RBFObject" << std::endl;
420 bitpit::log::cout() << "Finished RBF training" << std::endl;
421
422 std::size_t nMaxCellVertices = mesh.getCell(0).getVertexIds().size();
423
424 timers_values.push_back(MPI_Wtime()-time_start);
425 timers_name.push_back("output_RBF_and_analytical");
426 time_start = MPI_Wtime();
427
428 // RBF Output
429 bitpit::log::cout() << "Outputting" << std::endl;
430 std::vector<double> display_values;
431 display_values.resize(nP_total);
432
433 BITPIT_CREATE_WORKSPACE(vertexCoordinates, std::array<double BITPIT_COMMA dimensions>, nMaxCellVertices,
434 ReferenceElementInfo::MAX_ELEM_VERTICES)
435 const PatchKernel::CellConstRange &cellWriteRange = mesh.getVTKCellWriteRange();
436 for (const Cell &cell:cellWriteRange){
437 const unsigned long global_id = cell.getId();
438 mesh.getCellVertexCoordinates(global_id, vertexCoordinates);
439 std::array<double, dimensions> point = cell.evalCentroid(vertexCoordinates);
440 std::vector<double> temp_disp = RBFObject.evalRBF(point);
441 display_values[global_id] = temp_disp[0]; //Only the first field is used, since there is only one
442 }
443 mesh.getVTK().addData<double>("RBF", VTKFieldType::SCALAR, VTKLocation::CELL, display_values);
444 mesh.write();
445
446 timers_values.push_back(MPI_Wtime()-time_start);
447 timers_name.push_back("output_RBF_to_file");
448 time_start = MPI_Wtime();
449
450 //Outputting the combined RBF to a txt file
451 ofstream fw("RBF_" + filename + ".output", std::ofstream::ate);
452 if (fw.is_open()) {
453 fw << "support_radius basis_function node_x node_y ";
454 if (dimensions == 3)
455 {
456 fw << "node_z ";
457 }
458 fw << "weight \n";
459 for (unsigned long line = 0; line < nP_total; line++) {
460 // Set precision
461 int PRECISION = 20; //number of decimals
462 std::ostringstream streamObj_support_radius;
463 std::ostringstream streamObj_x;
464 std::ostringstream streamObj_y;
465 std::ostringstream streamObj_z;
466 std::ostringstream streamObj_weight;
467 streamObj_support_radius << std::fixed;
468 streamObj_x << std::fixed;
469 streamObj_y << std::fixed;
470 streamObj_z << std::fixed;
471 streamObj_weight << std::fixed;
472 streamObj_support_radius << std::setprecision(PRECISION);
473 streamObj_x << std::setprecision(PRECISION);
474 streamObj_y << std::setprecision(PRECISION);
475 streamObj_z << std::setprecision(PRECISION);
476 streamObj_weight << std::setprecision(PRECISION);
477 streamObj_support_radius << radii[line];
478 streamObj_x << nodes[line][0];
479 streamObj_y << nodes[line][1];
480 streamObj_z << nodes[line][2];
481 streamObj_weight << weights[line];
482 std::string strObj_support_radius = streamObj_support_radius.str();
483 std::string strObj_x = streamObj_x.str();
484 std::string strObj_y = streamObj_y.str();
485 std::string strObj_z = streamObj_z.str();
486 std::string strObj_weight = streamObj_weight.str();
487 fw << strObj_support_radius << " " << base_function << " "<<
488 strObj_x << " " << strObj_y << " ";
489 if (dimensions == 3)
490 {
491 fw << strObj_z << " ";
492 }
493 fw << strObj_weight << " ";
494 if (line < nP_total -1)
495 fw << "\n";
496 }
497 fw.close();
498 } else bitpit::log::cout() << "Problem with opening file" << std::endl;
499 bitpit::log::cout() << "Finished outputting" << std::endl;
500
501 timers_values.push_back(MPI_Wtime()-time_start);
502
503 int nb_timers = timers_name.size();
504 bitpit::log::cout()<< std::endl << "Timers" << std::endl;
505 for (int t = 0; t < nb_timers; t++)
506 {
507 bitpit::log::cout() << timers_name.at(t) << ":" << timers_values.at(t) << std::endl;
508 }
509}
510
514int main(int argc, char *argv[])
515{
516 int nProcs = 1;
517 int rank = 0;
518
519#if BITPIT_ENABLE_MPI==1
520 MPI_Init(&argc,&argv);
521 MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
522 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
523 if (nProcs>1)
524 {
525 bitpit::log::cout() << "nProcs > 1 isn't supported at the moment" << std::endl;
526 exit(1);
527 }
528#endif
529
530 // Arguments
531 std::vector<std::string> argList;
532 for(int i=0;i<argc;i++)
533 argList.emplace_back(argv[i]);
534
535 // Default values
536 std::string data_path = "../test/integration_tests/levelset/data/";
537 std::string filename = "cube";
538 std::string parameter_file = "RBF_example_00001.param";
539 if (argc > 3)
540 {
541 data_path = argList[1];
542 filename = argList[2];
543 parameter_file = argList[3];
544 }
545
546 // Initialize the logger
547 log::manager().initialize(log::MODE_COMBINE, true, nProcs, rank);
548 log::cout() << log::fileVerbosity(log::LEVEL_INFO);
550
551 // Run the example
552 try {
553 run(filename,
554 data_path,
555 parameter_file);
556 }
557 catch (const std::exception &exception) {
558 log::cout() << exception.what();
559 exit(1);
560 }
561
562#if BITPIT_ENABLE_MPI==1
563 MPI_Finalize();
564#endif
565 return 0;
566}
The Cell class defines the cells.
Definition cell.hpp:42
Interface class for all objects with respect to whom the levelset function may be computed.
void setCellBulkEvaluationMode(LevelSetBulkEvaluationMode evaluationMode)
virtual double evalCellValue(long id, bool signedLevelSet) const
void enableVTKOutput(const LevelSetFieldset &fieldset, bool enable=true)
Level Set driver class.
Definition levelSet.hpp:51
LevelSetObject & getObject(int) const
Definition levelSet.cpp:569
void setNarrowBandSize(double size=0)
Definition levelSet.cpp:164
void setMesh(VolumeKernel *mesh)
Definition levelSet.cpp:183
void update(const std::vector< adaption::Info > &adaptionData)
Definition levelSet.cpp:113
int addObject(LevelSetBooleanOperation, int, int, int id=levelSetDefaults::OBJECT)
Definition levelSet.tpp:60
void initialize(log::Mode mode, bool reset, int nProcesses, int rank)
Definition logger.cpp:1268
The PiercedStorageRange allow to iterate using range-based loops over a PiercedStorage.
void setMode(RBFMode mode)
Definition rbf.cpp:432
void setSupportRadius(double)
Definition rbf.cpp:375
void setFunction(RBFBasisFunction)
Definition rbf.cpp:125
std::vector< double > evalRBF(const std::array< double, 3 > &)
Definition rbf.cpp:597
double evalBasisPair(int i, int j)
Definition rbf.cpp:897
Class to handle Radial Basis Function with a large set of 3D points as nodes.
Definition rbf.hpp:184
int addNode(const std::array< double, 3 > &)
Definition rbf.cpp:1271
The SurfUnstructured class defines an unstructured surface triangulation.
The SystemSolver class provides methods for building and solving large linear systems.
void restoreSolutionRawPtr(double *raw_solution)
const double * getSolutionRawReadPtr() const
void restoreRHSRawPtr(double *raw_rhs)
void assembly(const SparseMatrix &matrix)
The VolOctree defines a Octree patch.
Definition voloctree.hpp:37
std::array< T, d > abs(const std::array< T, d > &x)
RBFBasisFunction
Enum class defining types of RBF kernel functions that could be used in bitpit::RBF class.
Definition rbf.hpp:40
#define BITPIT_CREATE_WORKSPACE(workspace, item_type, size, stack_size)
@ SIGN_PROPAGATION
Sign is propagated from the narrow band, no other data will be evaluated.
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
LoggerManipulator< log::Level > fileVerbosity(const log::Level &threshold)
Definition logger.cpp:2120
Logger & disableConsole(Logger &logger, const log::Level &level)
Definition logger.cpp:2165
LoggerManager & manager()
Definition logger.cpp:1685
--- layout: doxygen_footer ---