OOFEM 3.0
Loading...
Searching...
No Matches
VoxelGrid.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <vector>
5#include <tuple>
6#include <unordered_map>
7
8#include "CSG.h"
9#include "field.h"
10
14struct VoxelNode {
15 int id = -1;
16 double coords[3] = { 0.0, 0.0, 0.0 };
17 double timeActivated = 0.0;
18};
19
23struct Voxel {
24 int id = -1;
25 std::array<int, 8> nodes;
26 double timeActivated = 0.0;
27 std::vector<std::tuple<double, double> > vofHistory;
28
34 {
35 return this->timeActivated;
36 }
37
42 double vof()
43 {
44 if ( vofHistory.size() == 0 )
45 return 0.0;
46
47 return std::get<1>( vofHistory.back() );
48 }
49 double getVofAt(double time) {
50 if (vofHistory.size() == 0)
51 return 0.0;
52 for (int i = vofHistory.size()-1; i>=0; i--) {
53 if (std::get<0>(vofHistory[i]) <= time) {
54 return std::get<1>(vofHistory[i]);
55 }
56 }
57 return 0.0;
58 }
59};
60
65{
66public:
72 VoxelGrid( std::array<double, 3> steps, std::array<int, 3> sizes ) :
74 {
75 }
76
81 std::array<int, 3> sizes()
82 {
83 return m_sizes;
84 }
85
90 std::array<double, 3> steps()
91 {
92 return m_steps;
93 }
94
102 int get_index( int i, int j, int k )
103 {
104 return i + m_sizes[0] * ( j + m_sizes[1] * k );
105 }
106
112 std::tuple<int, int, int> get_indices( int i )
113 {
114 int x = i % m_sizes[0];
115 int y = ( i / m_sizes[0] ) % m_sizes[1];
116 int z = i / ( m_sizes[0] * m_sizes[1] );
117
118 return std::make_tuple( x, y, z );
119 }
120
126 std::tuple<int, int, int> get_indices_from_point( std::array<double, 3> point )
127 {
128 int x = point[0] / m_steps[0];
129 int y = point[1] / m_steps[1];
130 int z = point[2] / m_steps[2];
131
132 return std::make_tuple( x, y, z );
133 }
134
140 std::array<double, 3> get_vector_3d( int i )
141 {
142 auto [x, y, z] = get_indices( i );
143 return { x * m_steps[0], y * m_steps[1], z * m_steps[2] };
144 }
145
146 std::array<int, 8> giveVoxelNodeIds( int index )
147 {
148 auto [x, y, z] = get_indices( index );
149
150 std::array<int, 8> nodeIds;
151 // top surface
152 nodeIds[0] = get_index( x, y, z + 1 );
153 nodeIds[1] = get_index( x, y + 1, z + 1 );
154 nodeIds[2] = get_index( x + 1, y + 1, z + 1 );
155 nodeIds[3] = get_index( x + 1, y, z + 1 );
156 // bottom surface
157 nodeIds[4] = get_index( x, y, z );
158 nodeIds[5] = get_index( x, y + 1, z );
159 nodeIds[6] = get_index( x + 1, y + 1, z );
160 nodeIds[7] = get_index( x + 1, y, z );
161 return nodeIds;
162 }
163
164 void activateNodes( int index, double timeActivated )
165 {
166 auto voxelNodes = giveVoxelNodeIds( index );
167 for ( int i = 0; i < 8; i++ ) {
168 if ( !is_active_node( voxelNodes[i] ) ) {
169 auto coords = get_vector_3d( voxelNodes[i] );
170 m_nodes[voxelNodes[i]] = VoxelNode();
171 m_nodes[voxelNodes[i]].id = m_nodes.size();
172 m_nodes[voxelNodes[i]].coords[0] = coords[0];
173 m_nodes[voxelNodes[i]].coords[1] = coords[1];
174 m_nodes[voxelNodes[i]].coords[2] = coords[2];
175 m_nodes[voxelNodes[i]].timeActivated = timeActivated;
176 }
177 }
178 }
179
186 Voxel &createVoxel( int index, double timeActivated )
187 {
188 if ( !is_active( index ) ) {
189 // Auto-activate and number nodes
190 activateNodes( index, timeActivated );
191
192 // Create new voxel
193 m_voxels[index] = Voxel();
194
195 // Calculate one-based OOFEM element id
196 m_voxels[index].id = m_voxels.size();
197
198 // Store node ids (OOFEM ids)
199 auto ids = giveVoxelNodeIds( index );
200 for ( int i = 0; i < 8; i++ ) {
201 m_voxels[index].nodes[i] = m_nodes[ids[i]].id;
202 }
203 // Initialize vof history
204 m_voxels[index].vofHistory.push_back( std::make_tuple( 0, 0.0 ) );
205 m_voxels[index].timeActivated = timeActivated;
206 }
207
208 return m_voxels[index];
209 }
210
217 Voxel &activate( int index, double timeActivated, double vofIncrement )
218 {
219 this->createVoxel( index, timeActivated );
220
221 double vof_before = m_voxels[index].vof();
222 double vof_after = vof_before + vofIncrement;
223 if ( vof_after > 1.0 ) {
224 // redistribute the excess material to neighboring voxels
225 double excess = vof_after - 1.0;
226 vof_after = 1.0;
227 m_voxels[index].vofHistory.push_back( std::make_tuple( timeActivated, vof_after ) );
228 // check neighbors in xy plane
229 auto [x, y, z] = get_indices( index );
230 std::vector<int> neighbor_indices, neighbor_indices_workingset;
231 if ( x > 0 )
232 neighbor_indices.push_back( get_index( x - 1, y, z ) );
233 if ( x < m_sizes[0] - 1 )
234 neighbor_indices.push_back( get_index( x + 1, y, z ) );
235 if ( y > 0 )
236 neighbor_indices.push_back( get_index( x, y - 1, z ) );
237 if ( y < m_sizes[1] - 1 )
238 neighbor_indices.push_back( get_index( x, y + 1, z ) );
239 if ( x > 0 && y > 0 )
240 neighbor_indices.push_back( get_index( x - 1, y - 1, z ) );
241 if ( x > 0 && y < m_sizes[1] - 1 )
242 neighbor_indices.push_back( get_index( x - 1, y + 1, z ) );
243 if ( x < m_sizes[0] - 1 && y > 0 )
244 neighbor_indices.push_back( get_index( x + 1, y - 1, z ) );
245 if ( x < m_sizes[0] - 1 && y < m_sizes[1] - 1 )
246 neighbor_indices.push_back( get_index( x + 1, y + 1, z ) );
247
248 double excess_per_neighbor = excess / neighbor_indices.size();
249 std::map<int, double> neighborVof; // to accumulate vof increments per neighbor
250 for ( auto ni : neighbor_indices ) {
251 createVoxel( ni, timeActivated ); // ensure neighbor exists
252 neighborVof[ni] = m_voxels[ni].vof();
253 }
254 neighbor_indices_workingset = neighbor_indices;
255 while ( (excess > 0) && (neighbor_indices_workingset.size() > 0 )) {
256 excess = 0.0;
257 std::vector<int> neighbor_indices2;
258 for ( auto ni : neighbor_indices_workingset ) {
259 if (neighborVof[ni] < 1.0) {
260 double vof_after = neighborVof[ni] + excess_per_neighbor;
261 if (vof_after > 1.0) {
262 excess += vof_after - 1.0;
263 vof_after = 1.0;
264 neighborVof[ni] += excess_per_neighbor;
265 } else {
266 neighborVof[ni] = vof_after;
267 neighbor_indices2.push_back( ni ); // remember voxel with free capacity
268 }
269 } else {
270 excess += excess_per_neighbor;
271 }
272 }
273 excess_per_neighbor = excess / neighbor_indices2.size();
274 neighbor_indices_workingset = neighbor_indices2;
275 }
276 // update neighbors
277 for ( auto ni : neighbor_indices ) {
278 if (neighborVof[ni] > m_voxels[ni].vof()) {
279 m_voxels[ni].vofHistory.push_back( std::make_tuple( timeActivated, neighborVof[ni] ) );
280 }
281 }
282 } else {
283 // vof increment fully accomodated
284 m_voxels[index].vofHistory.push_back( std::make_tuple( timeActivated, vof_after ) );
285 }
286
287 return m_voxels[index];
288 }
289
295 bool is_active( int index )
296 {
297 return m_voxels.find( index ) != m_voxels.end();
298 }
299
305 bool is_active_node( int index )
306 {
307 return m_nodes.find( index ) != m_nodes.end();
308 }
309
315 {
316 return m_voxels.size();
317 }
318
324 {
325 return m_nodes.size();
326 }
327
332 int size()
333 {
334 return m_sizes[0] * m_sizes[1] * m_sizes[2];
335 }
336
342 Voxel &get_voxel( int index )
343 {
344 return m_voxels[index];
345 }
346
352 VoxelNode &get_node( int index )
353 {
354 return m_nodes[index];
355 }
356
361 std::unordered_map<int, Voxel> &giveVoxels()
362 {
363 return m_voxels;
364 }
365
370 std::unordered_map<int, VoxelNode> &giveNodes()
371 {
372 return m_nodes;
373 }
374
380 Model get_model( int index )
381 {
382 auto orig = get_vector_3d( index );
383 double dx = m_steps[0];
384 double dy = m_steps[1];
385 double dz = m_steps[2];
386
387 // std::cout << "C" << orig[0] << " " << orig[1] << " " << orig[2] << std::endl;
388 // std::cout << "S" << dx << " " << dy << " " << dz << std::endl;
389
390 Vertex v1( { { orig[0], orig[1], orig[2] }, { -1, -1, -1 } } );
391 Vertex v2( { { orig[0] + dx, orig[1], orig[2] }, { 1, -1, -1 } } );
392 Vertex v3( { { orig[0] + dx, orig[1] + dy, orig[2] }, { 1, 1, -1 } } );
393 Vertex v4( { { orig[0], orig[1] + dy, orig[2] }, { -1, 1, -1 } } );
394
395 Vertex v5( { { orig[0], orig[1], orig[2] + dz }, { -1, -1, 1 } } );
396 Vertex v6( { { orig[0] + dx, orig[1], orig[2] + dz }, { 1, -1, 1 } } );
397 Vertex v7( { { orig[0] + dx, orig[1] + dy, orig[2] + dz }, { 1, 1, 1 } } );
398 Vertex v8( { { orig[0], orig[1] + dy, orig[2] + dz }, { -1, 1, 1 } } );
399
400 Polygon p1( { v1, v2, v6, v5 } ); // bottom
401 Polygon p2( { v8, v7, v3, v4 } ); // top
402 Polygon p3( { v1, v5, v8, v4 } ); // left
403 Polygon p4( { v6, v2, v3, v7 } ); // right
404 Polygon p5( { v8, v5, v6, v7 } ); // front
405 Polygon p6( { v4, v3, v2, v1 } ); // back
406
407 return modelfrompolygons( { p1, p2, p3, p4, p5, p6 } );
408 }
409
410 void writeVTK( std::string filename )
411 {
412 std::ofstream file( filename );
413 file << "# vtk DataFile Version 2.0\n";
414 file << "Voxels\n";
415 file << "ASCII\n";
416 file << "DATASET UNSTRUCTURED_GRID\n";
417 file << "POINTS " << m_voxels.size() * 8 << " double\n";
418
419 for ( const auto &[i, voxel] : m_voxels ) {
420 auto pt = get_vector_3d( i );
421
422 // Create the 8 points of a cube
423 file << pt[0] << " " << pt[1] << " " << pt[2] << "\n";
424 file << pt[0] + m_steps[0] << " " << pt[1] << " " << pt[2] << "\n";
425 file << pt[0] + m_steps[0] << " " << pt[1] + m_steps[1] << " " << pt[2] << "\n";
426 file << pt[0] << " " << pt[1] + m_steps[1] << " " << pt[2] << "\n";
427
428 file << pt[0] << " " << pt[1] << " " << pt[2] + m_steps[2] << "\n";
429 file << pt[0] + m_steps[0] << " " << pt[1] << " " << pt[2] + m_steps[2] << "\n";
430 file << pt[0] + m_steps[0] << " " << pt[1] + m_steps[1] << " " << pt[2] + m_steps[2] << "\n";
431 file << pt[0] << " " << pt[1] + m_steps[1] << " " << pt[2] + m_steps[2] << "\n";
432 }
433
434 file << "CELLS " << m_voxels.size() << " " << m_voxels.size() * 9 << "\n";
435
436 for ( size_t i = 0; i < m_voxels.size(); i++ ) {
437 file << "8 ";
438 for ( int j = 0; j < 8; j++ ) {
439 file << i * 8 + j << " ";
440 }
441 file << "\n";
442 }
443
444 file << "CELL_TYPES " << m_voxels.size() << "\n";
445
446 for ( size_t i = 0; i < m_voxels.size(); i++ ) {
447 file << "12\n";
448 }
449
450 file << "CELL_DATA " << m_voxels.size() << "\n";
451 file << "SCALARS vof double 1\n";
452 file << "LOOKUP_TABLE default\n";
453
454 for ( auto &[index, voxel] : m_voxels ) {
455 file << voxel.vof() << "\n";
456 }
457 }
458
459private:
460 std::unordered_map<int, Voxel> m_voxels;
461 std::unordered_map<int, VoxelNode> m_nodes;
462
463 std::array<double, 3> m_steps;
464 std::array<int, 3> m_sizes;
465};
466
Model modelfrompolygons(const std::vector< Polygon > &polygons)
Definition CSG.h:924
std::array< double, 3 > steps()
Get the step sizes in each dimension.
Definition VoxelGrid.h:90
int size()
Get the size of the grid.
Definition VoxelGrid.h:332
Voxel & get_voxel(int index)
Get the voxel at a given index.
Definition VoxelGrid.h:342
void activateNodes(int index, double timeActivated)
Definition VoxelGrid.h:164
VoxelGrid(std::array< double, 3 > steps, std::array< int, 3 > sizes)
Constructor for VoxelGrid.
Definition VoxelGrid.h:72
std::array< double, 3 > get_vector_3d(int i)
Get the 3D vector of a voxel (origin) from its 1D index.
Definition VoxelGrid.h:140
bool is_active_node(int index)
Check if a node at a given index is active.
Definition VoxelGrid.h:305
int active_elements()
Get the number of active elements (voxels) in the grid.
Definition VoxelGrid.h:314
std::array< int, 3 > sizes()
Get the number of steps in each dimension.
Definition VoxelGrid.h:81
Voxel & activate(int index, double timeActivated, double vofIncrement)
Activate a voxel at a given index in a given time and store the corresponding vof value.
Definition VoxelGrid.h:217
void writeVTK(std::string filename)
Definition VoxelGrid.h:410
std::unordered_map< int, VoxelNode > m_nodes
Definition VoxelGrid.h:461
std::array< double, 3 > m_steps
Definition VoxelGrid.h:463
std::unordered_map< int, VoxelNode > & giveNodes()
Get the map of nodes in the grid.
Definition VoxelGrid.h:370
std::array< int, 3 > m_sizes
Definition VoxelGrid.h:464
Voxel & createVoxel(int index, double timeActivated)
Create a Vovel at given index and at given time.
Definition VoxelGrid.h:186
bool is_active(int index)
Check if a voxel at a given index is active.
Definition VoxelGrid.h:295
VoxelNode & get_node(int index)
Get the node at a given index.
Definition VoxelGrid.h:352
std::unordered_map< int, Voxel > m_voxels
Definition VoxelGrid.h:460
std::array< int, 8 > giveVoxelNodeIds(int index)
Definition VoxelGrid.h:146
std::tuple< int, int, int > get_indices_from_point(std::array< double, 3 > point)
Get the 3D indices of a voxel from a point in space.
Definition VoxelGrid.h:126
int active_nodes()
Get the number of active nodes in the grid.
Definition VoxelGrid.h:323
int get_index(int i, int j, int k)
Get the 1D index of a voxel in the grid.
Definition VoxelGrid.h:102
std::unordered_map< int, Voxel > & giveVoxels()
Get the map of nodes in the grid.
Definition VoxelGrid.h:361
std::tuple< int, int, int > get_indices(int i)
Get the 3D indices of a voxel from its 1D index.
Definition VoxelGrid.h:112
Model get_model(int index)
Get the triangulated model of a voxel at a given index.
Definition VoxelGrid.h:380
Definition CSG.h:202
Definition CSG.h:186
Definition CSG.h:117
A struct to represent a 3D model.
Definition VoxelGrid.h:14
double coords[3]
Definition VoxelGrid.h:16
double timeActivated
Definition VoxelGrid.h:17
A struct to represent a single voxel.
Definition VoxelGrid.h:23
double getVofAt(double time)
Definition VoxelGrid.h:49
std::vector< std::tuple< double, double > > vofHistory
Definition VoxelGrid.h:27
double vof()
Get the volume of fluid (infill percentage) of the voxel.
Definition VoxelGrid.h:42
double time_activated()
Get the time the voxel was activated.
Definition VoxelGrid.h:33
std::array< int, 8 > nodes
Definition VoxelGrid.h:25
double timeActivated
Definition VoxelGrid.h:26

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011