OOFEM  2.4
OOFEM.org - Object Oriented Finite Element Solver
particletopologydescription.C
Go to the documentation of this file.
1 /*
2  *
3  * ##### ##### ###### ###### ### ###
4  * ## ## ## ## ## ## ## ### ##
5  * ## ## ## ## #### #### ## # ##
6  * ## ## ## ## ## ## ## ##
7  * ## ## ## ## ## ## ## ##
8  * ##### ##### ## ###### ## ##
9  *
10  *
11  * OOFEM : Object Oriented Finite Element Code
12  *
13  * Copyright (C) 1993 - 2013 Borek Patzak
14  *
15  *
16  *
17  * Czech Technical University, Faculty of Civil Engineering,
18  * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33  */
34 
36 #include "timestep.h"
37 #include "dofiditem.h"
38 #include "spatiallocalizer.h"
39 #include "mathfem.h"
41 #include "topologydescription.h"
42 #include "particlegrid.h"
43 #include "datareader.h"
44 #include "element.h"
45 #include "timer.h"
46 #include "classfactory.h"
47 #include "engngm.h"
48 
50 #include "node.h"
51 #include "activebc.h"
52 #include "activedof.h"
53 #include "masterdof.h"
54 #include "set.h"
55 
56 #include <cstring>
57 #include <list>
58 #include <sstream>
59 #include <cstdio>
60 
61 #ifdef __VTK_MODULE
62  #include <vtkPoints.h>
63  #include <vtkPointData.h>
64  #include <vtkDoubleArray.h>
65  #include <vtkVertex.h>
66  #include <vtkCellArray.h>
67  #include <vtkCellData.h>
68  #include <vtkXMLPolyDataWriter.h>
69  #include <vtkPolyData.h>
70  #include <vtkSmartPointer.h>
71 #endif
72 
73 namespace oofem
74 {
75 REGISTER_TopologyDescription(ParticleTopologyDescription);
76 
78 {}
79 
81 {
82  if ( this->corners.size() ) {
83  this->corners.clear();
84  }
85 }
86 
88 {
89  // Required by IR_GIVE_FIELD macro
90  IRResultType result;
91  InputRecord *ir;
92  std :: string name;
93  int num;
94 
95  int res, nsd;
96  double tubewidth;
97  IntArray resolution;
98  FloatArray bb0, bb1;
99  // Input for geometry types
100  FloatArray x0, x1, center;
101  double radius, alpha0, alpha1;
102  int id, nsegments;
103 
104  // Read topology description
111  tubewidth = 1.1;
114 
115  resolution.resize(nsd);
116  resolution.zero();
117  resolution.add(res);
118 
119  // Mappings
124 
126  int n = this->regionInside.giveSize();
127  this->controlID.resize(n, n);
128  this->mergeID.resize(n, n);
129 
130  this->tubeWidth = ( bb1(0) - bb0(0) ) / res * tubewidth;
131 
132  this->grid.reset( new ParticleGrid< ParticlePoint >(resolution, bb0, bb1) );
133 
134  for ( int i = 1; i <= nsegments; i++ ) {
136  IR_GIVE_RECORD_KEYWORD_FIELD(ir, name, num);
138  if ( name.compare("line") == 0 ) {
140  IR_GIVE_FIELD(ir, x1, _IFT_Line_end);
141  this->addLineSegment(id, x0, x1, *this->grid);
142  } else if ( name.compare("circle") == 0 ) {
143  IR_GIVE_FIELD(ir, center, _IFT_Circle_center);
144  IR_GIVE_FIELD(ir, radius, _IFT_Circle_radius);
145  alpha0 = -180;
146  alpha1 = 180;
149  alpha0 *= M_PI / 180;
150  alpha1 *= M_PI / 180;
151  this->addCircleSegment(id, center, radius, alpha0, alpha1, *this->grid);
152  } else if ( name.compare("cornerpoint") == 0 ) {
153  IR_GIVE_FIELD(ir, center, _IFT_Point_coords);
154  this->addCorner(id, center, *this->grid);
155  } else {
156  OOFEM_ERROR( "Unknown geometry type '%s'", name.c_str() );
157  }
158  ir->finish();
159  }
160 
161  this->checkOverlap();
162 
163 #ifdef DEBUG
164  // this->writeVTKFile("initial_particle.vtp");
165 #endif
166  this->writeVTK = false;
168  return true;
169 }
170 
172 {
173  ParticlePoint *point;
174  double tubeWidth2 = this->tubeWidth * this->tubeWidth;
175  double distance2, xi;
176  double line_length;
177  FloatArray v, new_normal(2), grid_p, new_foot, grid_p_v1;
178  v.beDifferenceOf(p1, p0);
179  line_length = v.computeNorm();
180  v.times(1 / line_length); // v is the directional vector along the line.
181  new_normal(0) = -v(1);
182  new_normal(1) = v(0);
183 
184  // Find the bounding box for the segment
185  FloatArray x0, x1;
186  x0.beMinOf(p0, p1);
187  x0.add(-this->tubeWidth);
188  x1.beMaxOf(p0, p1);
189  x1.add(this->tubeWidth);
190 
191  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->beginAt(x0, x1); !it.end(); ++it ) {
192  it.getGridPoint(grid_p);
193  // Find closest point on line, parameterized by xi
194  grid_p_v1.beDifferenceOf(grid_p, p0);
195  xi = grid_p_v1.dotProduct(v) / line_length;
196  if ( xi < 0 || xi > 1 ) {
197  continue;
198  }
199 
200  // And it's coordinate
201  new_foot = p0;
202  new_foot.add(xi * line_length, v);
203 
204  distance2 = grid_p.distance_square(new_foot);
205 
206  if ( distance2 < tubeWidth2 ) {
207  if ( ( point = it.getPoint() ) ) {
208  if ( point->distance2 <= distance2 ) {
209  continue; // If distance already is smaller, then skip this.
210  }
211  }
212  point = new ParticlePoint(new_foot, id, new_normal, distance2);
213  it.setPoint(point);
214  }
215  }
216 }
217 
218 void ParticleTopologyDescription :: addCircleSegment(int id, const FloatArray &c, double r, double v0, double v1,
220 {
221  ParticlePoint *point;
222  FloatArray new_foot(2), new_normal(2), grid_p;
223  double distance2, tubeWidth2 = this->tubeWidth * this->tubeWidth;
224 
225  // Find the bounding box for the segment
226  FloatArray x0, x1;
227  this->getBoundingBox(x0, x1, c, r + this->tubeWidth);
228 
229  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->beginAt(x0, x1); !it.end(); ++it ) {
230  it.getGridPoint(grid_p);
231 
232  double v = atan2( grid_p(1) - c(1), grid_p(0) - c(0) );
233  if ( v < v0 || v > v1 ) {
234  continue;
235  }
236 
237  new_normal(0) = cos(v);
238  new_normal(1) = sin(v);
239  new_foot(0) = c(0) + cos(v) * r;
240  new_foot(1) = c(1) + sin(v) * r;
241 
242  distance2 = grid_p.distance_square(new_foot);
243 
244  if ( distance2 < tubeWidth2 ) {
245  if ( ( point = it.getPoint() ) ) {
246  if ( point->distance2 <= distance2 ) {
247  continue; // If distance already is smaller, then skip this.
248  }
249  }
250  point = new ParticlePoint(new_foot, id, new_normal, distance2);
251  it.setPoint(point);
252  }
253  }
254 }
255 
257 {
259  ParticlePoint corner;
260  corner.id = id;
261  corner.foot = c;
262  this->corners.push_front(corner);
263 
264  ParticlePoint *point;
265  // Find the bounding box for the segment
266  FloatArray x0, x1;
267  this->getBoundingBox(x0, x1, c, this->tubeWidth);
268 
269  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->beginAt(x0, x1); !it.end(); ++it ) {
270  if ( ( point = it.getPoint() ) ) {
271  if ( point->id == id ) {
272  if ( point->corner.giveSize() < 0 || point->foot.distance_square(point->corner) > point->foot.distance_square(c) ) {
273  point->corner = c;
274  }
275  }
276  }
277  }
278 }
279 
281 {
282  Timer timer;
283  timer.startTimer();
284 
285  TopologyState ts = TS_OK;
286 
287  FloatArray displacement, grid_coord;
288  ParticlePoint *p;
289  this->maxdisp2 = 0; // Determines whether grid should be resampled.
290 
291  // Update all foot points
292  this->d->giveSpatialLocalizer()->init(true); // For SL we need to update every time step.
293 
294  this->resampled = false;
295  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
296  if ( ( p = it.getPoint() ) != NULL ) {
297  bool state = this->findDisplacement(displacement, p->id, p->foot, tStep);
298  if ( state ) {
299  p->foot.add(displacement);
300  p->total_displacement.add(displacement);
302 
303 #if 0
304  if ( p->corner.giveSize() > 0 ) {
305  this->findDisplacement(displacement, p->id, p->foot, tStep);
306  p->foot.add(displacement);
307  p->total_displacement.add(displacement);
309  }
310 #endif
311  } else { // Can't find a suitable element to interpolate from, then just drop the point.
312  grid->clearPosition( it.getIndex() );
313  }
314  }
315  }
316 
317  // Remove this
318 #if 1
319  for ( std :: list< ParticlePoint > :: iterator it = this->corners.begin(); it != this->corners.end(); ++it ) {
320  bool state = this->findDisplacement(displacement, it->id, it->foot, tStep);
321  if ( !state ) {
322  OOFEM_ERROR("This always needs to find a displacement");
323  }
324  it->foot.add(displacement);
325  it->total_displacement.add(displacement);
326  }
327 #endif
328 
329  ts = this->checkOverlap();
330  if ( ts != TS_OK || this->maxdisp2 > this->tubeWidth * this->tubeWidth ) {
331  OOFEM_LOG_INFO("ParticleTopologyDescription :: updateYourself - Resampling\n");
332  this->resample();
333  }
334 
335  timer.stopTimer();
336  OOFEM_LOG_INFO( "ParticleTopologyDescription: user time consumed by updating: %.2fs\n", timer.getUtime() );
337 
338  return ts;
339 }
340 
341 
343 {
344  TopologyState ts = TS_OK;
345  FloatArray x0, x1;
346  std :: list< ParticlePoint * >points;
347  ParticlePoint *p0;
348  FloatArray p0p1;
349  double normal_limit = 0.5, distance_limit = 0.0; // Very lenient requirement...
350  distance_limit = this->tubeWidth / 2;
351 
352  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
353  if ( ( p0 = it.getPoint() ) != NULL && p0->id > 0 ) {
354  // Use either total distance or the local?
355  this->getBoundingBox(x0, x1, p0->foot, this->tubeWidth + 2 * p0->total_displacement.computeNorm() + distance_limit);
356  this->grid->getPointsWithin(points, x0, x1);
357 
358  std :: list< ParticlePoint * > :: iterator it_points;
359  for ( it_points = points.begin(); it_points != points.end(); it_points++ ) {
360  ParticlePoint *p1 = * it_points;
361  if ( p1->id == p0->id ) { // For same surfaces, just merge them
362  if ( p1->normal.dotProduct(p0->normal) < normal_limit ) {
363  p0p1.beDifferenceOf(p1->foot, p0->foot);
364  // TODO: Is this a good criteria?
365  //if (p0->normal.dotProduct(p0p1) < distance_limit ) {
366  if ( p0p1.computeNorm() < distance_limit ) {
367  // Mark both for removal.
368  p0->removal = true;
369  p1->removal = true;
370  //ts = TS_NeedsRemeshing;
371  }
372  }
373  }
374  // This part turned out to be incredibly difficult; Merging of different surfaces (creating a new one, with end points accordingly).
375 #if 0
376  else {
377  double distance = p0->foot.distance_square(p1->foot);
378  if ( distance < distance_limit ) {
379  if ( p0->corner.giveSize() > 0 && distance < p0->foot.distance_square(p0->corner) ) {
380  p0->removal = true;
381  p1->removal = true;
382  } else {
383  OOFEM_ERROR("Conditions for merging surface not implemented yet.");
384  // Not this simple, but something along these lines...
385  int newpid = ( int ) this->mergeID.at(p0->id, p1->id);
386  int control = ( int ) this->controlID.at(p0->id, p1->id);
387  if ( p0->id == control ) {
388  p0->id = newpid;
389  p1->removal = true;
390  } else {
391  p1->id = newpid;
392  p0->removal = true;
393  }
394  ts = TS_NeedsRemeshing;
395  }
396  }
397  }
398 #endif
399  }
400  }
401  }
402 
403  this->removePoints(*this->grid);
404  return ts;
405 }
406 
408 {
409  ParticlePoint *p;
410  FloatArray grid_coord;
412 
413  for ( int ind = 0; ind < g.getTotal(); ind++ ) {
414  if ( g.getPoint(p, ind) ) {
415  if ( p->removal ) {
416  g.clearPosition(ind);
417  }
418  } else if ( this->grid->getSubGrid(sg, ind) ) {
419  this->removePoints(*sg);
420  // If all subpoint were removed, then remove the whole grid.
421  if ( sg->isEmpty() ) {
422  sg->clearPosition(ind);
423  }
424  }
425  }
426 }
427 
428 void ParticleTopologyDescription :: calculateShortestDistance(const ParticlePoint *p0, std :: list< ParticlePoint * > &neighbors, ParticleGrid< ParticlePoint > &g) const
429 // This routine is the most complicated one, and it's no unique in it's possible design.
430 // Current implementation does
431 // 1. Curve fit a second order polynomial
432 // 2. Calculate new shortest distances.
433 {
434  int n = neighbors.size();
435  FloatArray a; // Coefficients for the polynomial
436  FloatArray tfooti; // Foot origin and mapped foot point.
437  FloatArray temp;
438  FloatArray normal;
439 
440  // The matrix representing the mapping to the normal space.
441  FloatMatrix N;
442 
443  normal = p0->normal;
444  for ( std :: list< ParticlePoint * > :: iterator it = neighbors.begin(); it != neighbors.end(); ++it ) {
445  normal.add( ( * it )->normal );
446  }
447  normal.normalize();
448  N.beLocalCoordSys(normal);
449 
450  // The limits of txi
451  double txi_min = 0, txi_max = 0;
452 
453  FloatArray tx(n + 1), ty(n + 1);
454  tx(0) = ty(0) = 0; // Center point
455  int i = 1;
456  for ( std :: list< ParticlePoint * > :: iterator it = neighbors.begin(); it != neighbors.end(); ++it, ++i ) {
457  // Calculate foot points in local coord.sys.
458  temp.beDifferenceOf( ( * it )->foot, p0->foot );
459  tfooti.beProductOf(N, temp);
460  tx(i) = tfooti(0);
461  ty(i) = tfooti(1);
462  if ( tx(i) < txi_min ) {
463  txi_min = tx(i);
464  } else if ( tx(i) > txi_max ) {
465  txi_max = tx(i);
466  }
467  }
468  ls2fit(tx, ty, a);
469 
470  FloatArray x0, x1;
471  IntArray ind0, ind1;
472  double radius = this->tubeWidth + max(txi_max, -txi_min);
473  this->getBoundingBox(x0, x1, p0->foot, radius);
474  g.getBoundingBox(x0, x1, ind0, ind1);
475  double tubeWidth2 = this->tubeWidth * this->tubeWidth;
476  FloatArray new_foot, new_normal;
477 
478  double distance2;
479  ParticlePoint *point;
481  FloatArray grid_point;
482  IntArray pos(2);
484  for ( pos(0) = ind0(0); pos(0) < ind1(0); pos(0)++ ) {
485  for ( pos(1) = ind0(1); pos(1) < ind1(1); pos(1)++ ) {
486  g.getGridCoord(grid_point, pos);
487  if ( grid_point.distance_square(p0->foot) > radius * radius ) { // Quick optimization (might give false negatives, but that is acceptable.)
488  continue;
489  }
490 
491  // Find the closest foot point
492  distance2 = this->shortestDistanceFromCurve(a, txi_min, txi_max, normal, p0->foot,
493  grid_point, new_foot, new_normal);
494 
495  if ( distance2 < tubeWidth2 ) { // Otherwise we ignore it
496  if ( g.getPoint(point, pos) ) {
497  if ( point->distance2 < distance2 ) {
498  continue;
499  }
500  } else if ( g.getSubGrid(subgrid, pos) ) {
501  OOFEM_ERROR("Not implemented");
502  }
503  point = new ParticlePoint(new_foot, p0->id, new_normal, distance2);
504  g.setPoint(point, pos);
505  }
506  }
507  }
508 }
509 
510 double ParticleTopologyDescription :: shortestDistanceFromCurve(const FloatArray &a, double txi_min, double txi_max,
511  const FloatArray &n0, const FloatArray &y0, const FloatArray &p, FloatArray &foot, FloatArray &normal) const
512 {
513  double b3, b2, b1, b0; // Coefficients for the polynomial
514  double temp1, temp2;
515  FloatArray p_y0(2), t0(2);
516 
517  // Tangent
518  t0(0) = n0(1);
519  t0(1) = -n0(0);
520 
521  p_y0(0) = y0(0) - p(0);
522  p_y0(1) = y0(1) - p(1);
523 
524  p_y0.beDifferenceOf(y0, p);
525  temp1 = n0(0) * p_y0(0) + n0(1) * p_y0(1); //n0.dotProduct(p_y0);
526  temp2 = t0(0) * p_y0(0) + t0(1) * p_y0(1); //t0.dotProduct(p_y0);
527 
528  // Same as [1]
529  b3 = 2 * a(2) * a(2);
530  b2 = 3 * a(1) * a(2);
531  // Last terms with "tempX" missing in article [1]
532  b1 = a(1) * a(1) + 2 * a(0) * a(2) + 1 + 2 * a(2) * temp1;
533  b0 = a(0) * a(1) + a(1) * temp1 + temp2;
534 
535  // Find the roots
536  int roots;
537  double r [ 3 ] = {
538  0, 0, 0
539  };
540  cubic(b3, b2, b1, b0, & r [ 0 ], & r [ 1 ], & r [ 2 ], & roots);
541  // The potential points
542  double limit = 0.6; // Found to be absolutely necessary for stability of surfaces when corner cases are included.
543  double txi_list [ 5 ] = {
544  txi_min *limit, txi_max * limit
545  };
546  int points = 0;
547  for ( int i = 0; i < roots; i++ ) {
548  if ( txi_min * limit < r [ i ] && r [ i ] < txi_max * limit ) {
549  txi_list [ points ] = r [ i ];
550  points++;
551  }
552  }
553 
554  // Normal and foot point in mapped domain (thus the t-prefix)
555  double min_distance2 = 0.0, min_txi = 0.0;
556  double dx, dy, distance2, f, fp, txi;
557  for ( int i = 0; i < points; i++ ) {
558  txi = txi_list [ i ];
559  f = a(0) + a(1) * txi + a(2) * txi * txi;
560 
561  dx = n0(0) * f + t0(0) * txi + p_y0(0);
562  dy = n0(1) * f + t0(1) * txi + p_y0(1);
563 
564  distance2 = dx * dx + dy * dy;
565 
566  if ( i == 0 || distance2 < min_distance2 ) {
567  min_distance2 = distance2;
568  min_txi = txi;
569  }
570  }
571 
572  if ( min_txi < txi_min || min_txi > txi_max ) {
573  return 2 * this->tubeWidth * this->tubeWidth;
574  }
575 
576  f = a(0) + a(1) * min_txi + a(2) * min_txi * min_txi;
577  fp = a(1) + 2 * a(2) * min_txi;
578 
579  foot.resize(2);
580  foot(0) = n0(0) * f + t0(0) * min_txi + y0(0);
581  foot(1) = n0(1) * f + t0(1) * min_txi + y0(1);
582 
583  normal.resize(2);
584  normal(0) = n0(0) + t0(0) * ( -fp );
585  normal(1) = n0(1) + t0(1) * ( -fp );
586  normal.normalize();
587 
588  return foot.distance_square(p);
589 }
590 
592 // Copy structure from old grid for a new resampled grid.
593 {
594  if ( this->resampled ) {
595  return;
596  }
597  std :: list< ParticlePoint * >neighbours;
598  ParticlePoint *origin;
599  FloatArray grid0;
600  FloatArray new_foot, new_normal;
601  std :: unique_ptr< ParticleGrid< ParticlePoint > > new_grid( new ParticleGrid< ParticlePoint >(this->grid.get()) );
602 
603  double maxdisp = sqrt(this->maxdisp2);
604  int total_points = 0;
605  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
606  total_points++;
607  if ( ( origin = it.getPoint() ) != NULL ) {
608  this->collectNeighbors(neighbours, origin, maxdisp);
609  this->calculateShortestDistance(origin, neighbours, *new_grid);
610  }
611  }
612 
613  this->grid = std :: move( new_grid );
614  this->resampled = true;
615 }
616 
618 {
619  x0 = c;
620  x0.add(-width);
621  x1 = c;
622  x1.add(width);
623 }
624 
625 // Helper to sort the pairs
626 static bool compare_second(std :: pair< ParticlePoint *, double >a, std :: pair< ParticlePoint *, double >b)
627 {
628  return fabs(a.second) < fabs(b.second);
629 }
630 
631 void ParticleTopologyDescription :: collectNeighbors(std :: list< ParticlePoint * > &answer, const ParticlePoint *origin, double dist) const
632 {
633  answer.clear();
634 
635  FloatArray temp;
636  FloatArray lcoord;
637  FloatMatrix toLocalCoord;
638 
639  toLocalCoord.beLocalCoordSys(origin->normal);
640 
641  // The algorithm uses a large bounding box, which should incorporate at least n points for well formed input.
642  std :: list< ParticlePoint * >points;
643 
644  // Bounding box around grid point and collect all the potential points.
645  FloatArray x0, x1;
646  this->getBoundingBox(x0, x1, origin->foot, 1.1 * this->tubeWidth + dist);
647  this->grid->getPointsWithin(points, x0, x1);
648 
649  typedef std :: pair< ParticlePoint *, double >dist_pair;
650  std :: list< dist_pair >valid_points;
651 
653  for ( std :: list< ParticlePoint > :: const_iterator it_corners = corners.begin(); it_corners != this->corners.end(); ++it_corners ) {
654  ParticlePoint *p = ( ParticlePoint * ) & ( * it_corners );
655  if ( p->id != origin->id ) {
656  continue;
657  }
658 
659  if ( origin->foot.distance_square(p->foot) > 4 * this->tubeWidth * this->tubeWidth ) {
660  continue;
661  }
662  temp.beDifferenceOf(p->foot, origin->foot);
663  lcoord.beProductOf(toLocalCoord, temp);
664  valid_points.push_front( dist_pair( p, lcoord(0) ) );
665  }
666 
667  // Apply rejection criteria based on normals (and other things?)
668  std :: list< ParticlePoint * > :: iterator it_points;
669  for ( it_points = points.begin(); it_points != points.end(); ++it_points ) {
670  ParticlePoint *p = * it_points;
671  if ( p->id != origin->id ) {
672  continue;
673  }
674 
675  double projection = p->normal.dotProduct(origin->normal);
676  if ( projection < 0.5 ) {
677  continue;
678  }
679  temp.beDifferenceOf(p->foot, origin->foot);
680  lcoord.beProductOf(toLocalCoord, temp);
681  valid_points.push_front( dist_pair( p, lcoord(0) ) );
682  }
683 
684  valid_points.sort(compare_second);
685  //valid_points.unique(same_point);
686 
687  // Some special effort to take neighbors from both sides as well as
688  int m_smaller = 0, m_larger = 0;
689  double limit = 0.01 * this->grid->getGridStep(0);
690  double smaller = -limit, larger = limit;
691  // Copy them over to answer
692  std :: list< dist_pair > :: iterator it = valid_points.begin();
693  for ( int i = 0; i < ( int ) valid_points.size(); i++, it++ ) {
694  if ( m_larger > 0 && m_smaller > 0 && m_larger + m_smaller >= this->m ) {
695  break;
696  }
697  if ( it->second > larger ) {
698  if ( m_larger >= this->m ) {
699  continue;
700  } else {
701  larger = it->second + limit;
702  m_larger++;
703  }
704  } else if ( it->second < smaller ) {
705  if ( m_smaller >= this->m ) {
706  continue;
707  } else {
708  smaller = it->second - limit;
709  m_smaller++;
710  }
711  } else { // To close to center, skip it.
712  continue;
713  }
714  answer.push_front(it->first);
715  }
716 }
717 
718 bool ParticleTopologyDescription :: findDisplacement(FloatArray &displacement, int id, const FloatArray &footpoint, TimeStep *tStep) const
719 {
720  FloatArray lcoords, closest, offset;
721  IntArray region(1);
722  region(0) = id;
723  // Finds a single element close to this point.
724  Element *e = this->d->giveSpatialLocalizer()->giveElementClosestToPoint(lcoords, closest, footpoint, id);
725  if ( !e ) { // No element at all for this domain. Then there is no displacement;
726  OOFEM_WARNING("Couldn't find any element to interpolate from");
727  displacement.resize( footpoint.giveSize() );
728  displacement.zero();
729  return false;
730  }
731  offset.beDifferenceOf(closest, footpoint);
732  double dist = offset.computeSquaredNorm();
733  if ( dist > 0.25 * this->grid->getGridStep(0) * this->grid->getGridStep(0) ) { // TODO: Maybe also check normals?
734  OOFEM_WARNING( "Foot point far from element (%e) (%e, %e)->(%e, %e).\n", sqrt(dist), footpoint.at(1), footpoint.at(2), closest.at(1), closest.at(2) );
735  return false;
736  }
737 
738 
739  if ( this->useDisplacements ) {
740  e->computeField(VM_Incremental, tStep, lcoords, displacement); // Displacement
741  } else {
742  FloatArray fields;
743  IntArray dofIds;
744  displacement.resize( this->d->giveNumberOfSpatialDimensions() );
745  displacement.zero();
746  double dt = tStep->giveTimeIncrement();
747  e->computeField(VM_Total, tStep, lcoords, fields); // Velocities + pressures most likely.
748  e->giveElementDofIDMask(dofIds);
749  for ( int i = 0; i < dofIds.giveSize(); i++ ) {
750  if ( dofIds(i) == V_u ) {
751  displacement(0) = fields(i) * dt;
752  } else if ( dofIds(i) == V_v ) {
753  displacement(1) = fields(i) * dt;
754  } else if ( dofIds(i) == V_w ) {
755  displacement(2) = fields(i) * dt;
756  }
757  }
758  }
759  displacement.add(offset);
760  return true;
761 }
762 
764 {
765  std :: ostringstream name;
766  name << this->d->giveEngngModel()->giveOutputBaseFileName() << "." << tStep->giveNumber() << ".vtp";
767  if ( writeVTK ) {
768  this->writeVTKFile( name.str().c_str() );
769  }
770 }
771 
772 
774 {
775  // Dumps everything in a ASCII table.
776  FILE *fid = fopen(name, "w");
777 
778  int dims;
779  FloatArray grid_coord;
780  ParticlePoint *p;
781 
782  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
783  if ( ( p = it.getPoint() ) != NULL ) {
784  it.getGridPoint(grid_coord);
785 
786  dims = grid_coord.giveSize();
787  // First write the grid coordinate
788  for ( int i = 0; i < dims; i++ ) {
789  fprintf( fid, "%e ", grid_coord(i) );
790  }
791  // Then the foot point
792  for ( int i = 0; i < dims; i++ ) {
793  fprintf( fid, "%e ", p->foot(i) );
794  }
795  // Auxiliary information, like normal
796  for ( int i = 0; i < dims; i++ ) {
797  fprintf( fid, "%e ", p->normal(i) );
798  }
799  fprintf(fid, "%d ", p->id);
800  fprintf(fid, "\n");
801  }
802  }
803 
804  fclose(fid);
805 }
806 
808 {
809 #ifdef __VTK_MODULE
810  ParticlePoint *p;
811  int dims = this->grid->giveDimensions();
812  // Create points and normals
813  int npoints = this->grid->getNumberOfPoints();
814  vtkSmartPointer< vtkPoints >points = vtkSmartPointer< vtkPoints > :: New();
815  vtkSmartPointer< vtkVertex >vertex;
816  vtkSmartPointer< vtkCellArray >vertices = vtkSmartPointer< vtkCellArray > :: New();
817  vtkSmartPointer< vtkDoubleArray >pointNormalsArray = vtkSmartPointer< vtkDoubleArray > :: New();
818  vtkSmartPointer< vtkIntArray >pointIDArray = vtkSmartPointer< vtkIntArray > :: New();
819  vtkSmartPointer< vtkDoubleArray >pointEndPointsArray = vtkSmartPointer< vtkDoubleArray > :: New();
820 
821  pointIDArray->SetNumberOfComponents(1);
822  pointNormalsArray->SetNumberOfComponents(3);
823  pointEndPointsArray->SetNumberOfComponents(3);
824 
825  pointIDArray->SetName("ID");
826  pointNormalsArray->SetName("Normals");
827  pointEndPointsArray->SetName("End points");
828 
829  pointIDArray->SetNumberOfTuples(npoints);
830  pointNormalsArray->SetNumberOfTuples(npoints);
831  pointEndPointsArray->SetNumberOfTuples(npoints);
832 
833  int i = 0;
834  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
835  if ( ( p = it.getPoint() ) != NULL ) {
836  points->InsertNextPoint(p->foot(0), p->foot(1), dims == 3 ? p->foot(2) : 0.0);
837  vertex = vtkSmartPointer< vtkVertex > :: New();
838  vertex->GetPointIds()->SetId(0, i);
839  vertices->InsertNextCell(vertex);
840  pointIDArray->SetTuple1(i, p->id);
841  pointNormalsArray->SetTuple3(i, p->normal(0), p->normal(1), dims == 3 ? p->normal(2) : 0.0);
842  if ( p->corner.giveSize() > 0 ) {
843  pointEndPointsArray->InsertNextTuple3(p->corner(0) - p->foot(0), p->corner(1) - p->foot(1), dims == 3 ? p->corner(2) - p->foot(2) : 0.0);
844  } else {
845  pointEndPointsArray->InsertNextTuple3(0.0, 0.0, 0.0);
846  }
847  ++i;
848  }
849  }
850 
851  // Create a polydata object and add the points to it.
852  vtkSmartPointer< vtkPolyData >polydata = vtkSmartPointer< vtkPolyData > :: New();
853  polydata->SetPoints(points);
854  polydata->SetVerts(vertices);
855  polydata->GetPointData()->SetNormals(pointNormalsArray);
856  polydata->GetPointData()->SetVectors(pointEndPointsArray);
857  polydata->GetPointData()->SetScalars(pointIDArray);
858 
859  // Write the file
860  vtkSmartPointer< vtkXMLPolyDataWriter >writer = vtkSmartPointer< vtkXMLPolyDataWriter > :: New();
861  writer->SetFileName(name);
862  writer->SetInput(polydata);
863  // Optional - set the mode. The default is binary.
864  //writer->SetDataModeToBinary();
865  //writer->SetDataModeToAscii();
866  writer->Write();
867 #else
868  OOFEM_WARNING("Not compiled with VTK support.");
869 #endif
870 }
871 
872 class edge
873 {
874 public:
875  int first;
876  int second;
877  int id;
878 };
879 
880 class node
881 {
882 public:
884  int id;
885 };
886 
887 static bool sort_edge(edge a, edge b)
888 {
889  return ( a.first == b.first ) ? a.second > b.second : a.first > b.first;
890 }
891 
892 static bool compare_edge(edge a, edge b)
893 {
894  return a.first == b.first && a.second == b.second;
895 }
896 
897 // There are much room for improvement here. In particular, it should be similar to
899 {
900  this->resample();
901 
902  FloatArray lcoord, temp;
903  FloatMatrix toLocalCoord;
904 
905  // First enumerate all the nodes, removing duplicates
906  ParticlePoint *origin;
907  std :: list< node >nodes;
908  std :: list< ParticlePoint * >points;
909  FloatArray x0, x1, grid_coord;
910 
911  // Nodal merge limit (for very close points, 1/10 of the grid step).
912  double merge2 = this->grid->getGridStep(1) * this->grid->getGridStep(1) * 1e-2;
913  // PSLG simplification limit, 1/10 of the grid step.
914  double limit = this->grid->getGridStep(1) * 0.5;
915 
916  int total_nodes = 0;
917 
918  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
919  if ( ( origin = it.getPoint() ) != NULL ) {
920  origin->node = 0;
921  }
922  }
923 
924  for ( std :: list< ParticlePoint > :: iterator cit = this->corners.begin(); cit != this->corners.end(); ++cit ) {
925  cit->node = 0;
926  }
927 
928  // Enumerate the corner nodes first;
929  for ( std :: list< ParticlePoint > :: iterator cit = this->corners.begin(); cit != this->corners.end(); ++cit ) {
930  if ( cit->node != 0 ) {
931  continue;
932  }
933  total_nodes++;
934  cit->node = total_nodes;
935  node n;
936  n.id = cit->id;
937  n.c = cit->foot;
938  nodes.push_back(n);
939  for ( std :: list< ParticlePoint > :: iterator cit_ = this->corners.begin(); cit_ != this->corners.end(); ++cit_ ) {
940  if ( cit->foot.distance_square(cit_->foot) <= merge2 && cit_->node == 0 ) {
941  cit_->node = cit->node;
942  cit_->foot = cit->foot; // For consistency, merge the points which are merged in the mesh
943  }
944  }
945 
946  this->getBoundingBox(x0, x1, cit->foot, 2 * this->tubeWidth);
947  this->grid->getPointsWithin(points, x0, x1);
948  for ( auto pit = points.begin(); pit != points.end(); pit++ ) {
949  if ( ( cit->foot.distance_square( ( * pit )->foot ) <= merge2 ) && ( * pit )->node == 0 ) {
950  ( * pit )->node = cit->node;
951  ( * pit )->foot = cit->foot;
952  }
953  }
954  }
955 
956  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
957  if ( ( origin = it.getPoint() ) != NULL ) {
958  if ( origin->node != 0 ) {
959  continue;
960  }
961  toLocalCoord.beLocalCoordSys(origin->normal);
962  total_nodes++;
963  origin->node = total_nodes;
964  node n;
965  n.id = origin->id;
966  n.c = origin->foot;
967  nodes.push_back(n);
968 
969  this->getBoundingBox(x0, x1, origin->foot, 2 * this->tubeWidth);
970  this->grid->getPointsWithin(points, x0, x1);
971  for ( auto pit = points.begin(); pit != points.end(); pit++ ) {
972  if ( ( * pit )->node == 0 ) {
973  /*
974  * temp.beDifferenceOf((*pit)->foot, origin->foot);
975  * lcoord.beProductOf(toLocalCoord, temp);
976  * double ln = lcoord.at(lcoord.giveSize()); // Treating the buggy offset differently.
977  * lcoord.at(lcoord.giveSize()) = 0.0;
978  * if ( lcoord.computeSquaredNorm() <= limit*limit && (ln < this->tubeWidth && origin->normal.dotProduct((*pit)->normal) ) {
979  */
980  if ( origin->foot.distance_square( ( * pit )->foot ) <= merge2 ) {
981  ( * pit )->node = origin->node;
982  ( * pit )->foot = origin->foot;
983  }
984  }
985  }
986  }
987  }
988 
989  // Find segments
990  std :: list< edge >edges;
991  double max_value = 2 * this->tubeWidth; // No connections further away than this.
992  double front_dist, back_dist, b_front_dist, b_back_dist;
993  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
994  if ( ( origin = it.getPoint() ) != NULL ) {
995  toLocalCoord.beLocalCoordSys(origin->normal);
996 
997  edge e0, e1;
998  e0.id = origin->id;
999  e1.id = origin->id;
1000  e0.second = origin->node;
1001  e1.first = origin->node;
1002  e0.first = 0;
1003  e1.second = 0;
1004  front_dist = max_value;
1005  back_dist = -max_value;
1006 
1007  bool found_front = false, found_back = false;
1008 
1009  // Backup values
1010  b_front_dist = -max_value;
1011  b_back_dist = max_value;
1012 
1013  this->getBoundingBox(x0, x1, origin->foot, max_value);
1014  this->grid->getPointsWithin(points, x0, x1);
1015 
1016  // Loop over corner nodes as well
1017  for ( std :: list< ParticlePoint > :: iterator cit = this->corners.begin(); cit != this->corners.end(); ++cit ) {
1018  points.push_front(& * cit);
1019  }
1020 
1021  for ( auto pit = points.begin(); pit != points.end(); ++pit ) {
1022  ParticlePoint *p = * pit;
1023 
1024  if ( p->id != origin->id || origin->node == p->node ) {
1025  continue;
1026  }
1027 
1028  temp.beDifferenceOf(p->foot, origin->foot);
1029 
1030  if ( temp.computeSquaredNorm() > max_value * max_value ) {
1031  continue;
1032  }
1033 
1034  lcoord.beProductOf(toLocalCoord, temp);
1035 
1036  double projection = p->normal.giveSize() > 0 ? p->normal.dotProduct(origin->normal) : 1.0;
1037  if ( projection < 0.0 ) { // Then take the furthest point
1038 #if 1
1039  if ( lcoord(0) > b_front_dist && !found_front ) {
1040  b_front_dist = lcoord(0);
1041  e1.second = p->node;
1042  }
1043  if ( lcoord(0) < b_back_dist && !found_back ) {
1044  b_back_dist = lcoord(0);
1045  e0.first = p->node;
1046  }
1047 #endif
1048  continue;
1049  }
1050 
1051  if ( lcoord(0) > 0 ) {
1052  if ( lcoord(0) < front_dist ) {
1053  found_front = true;
1054  front_dist = lcoord(0);
1055  e1.second = p->node;
1056  }
1057  } else {
1058  if ( lcoord(0) > back_dist ) {
1059  found_back = true;
1060  back_dist = lcoord(0);
1061  e0.first = p->node;
1062  }
1063  }
1064  }
1065  if ( e0.first != 0 ) {
1066  edges.push_front(e0);
1067  }
1068  if ( e1.second != 0 ) {
1069  edges.push_front(e1);
1070  }
1071  }
1072  }
1073  edges.sort(sort_edge);
1074  edges.unique(compare_edge);
1075 
1076  Triangle_PSLG fine;
1077  fine.nx.resize( nodes.size() );
1078  fine.ny.resize( nodes.size() );
1079  std :: list< node > :: iterator it_node;
1080  int n = 0;
1081  for ( it_node = nodes.begin(); it_node != nodes.end(); it_node++ ) {
1082  fine.nx(n) = it_node->c(0);
1083  fine.ny(n) = it_node->c(1);
1084  n++;
1085  }
1086 
1087  fine.segment_a.resize( edges.size() );
1088  fine.segment_b.resize( edges.size() );
1089  fine.segment_marker.resize( edges.size() );
1090  std :: list< edge > :: iterator it_edge;
1091  n = 0;
1092  for ( it_edge = edges.begin(); it_edge != edges.end(); it_edge++ ) {
1093  fine.segment_a(n) = it_edge->first;
1094  fine.segment_b(n) = it_edge->second;
1095  fine.segment_marker(n) = it_edge->id;
1096  n++;
1097  }
1098 
1099 #if 0
1100  pslg.nx = fine.nx;
1101  pslg.ny = fine.ny;
1102  pslg.segment_a = fine.segment_a;
1103  pslg.segment_b = fine.segment_b;
1104  pslg.segment_marker = fine.segment_marker;
1105 #else
1106  TriangleMesherInterface :: simplifyPSLG(pslg, fine, limit);
1107 #endif
1108 
1109  // DEBUG: Print all to matlab file
1110 #if 1
1111  this->writeVTKFile("initial_particle.vtp");
1112 
1113  FILE *file = fopen("pslg.m", "w");
1114 
1115  fprintf(file, "edges = [");
1116  for ( int i = 0; i < pslg.segment_a.giveSize(); i++ ) {
1117  fprintf( file, "%d, %d, %d;\n", pslg.segment_a(i), pslg.segment_b(i), pslg.segment_marker(i) );
1118  }
1119  fprintf(file, "];\n");
1120 
1121  fprintf(file, "nodes = [");
1122  for ( int i = 0; i < pslg.nx.giveSize(); i++ ) {
1123  fprintf( file, "%e, %e;\n", pslg.nx(i), pslg.ny(i) );
1124  }
1125  fprintf(file, "];\n");
1126 
1127  fprintf(file, "colors = 'grbkmcygrbkmcygrbkmcy';\n");
1128  fprintf(file, "hold on, axis equal\n");
1129  fprintf(file, "for i = 1:size(nodes,1)\n plot(nodes(i,1),nodes(i,2),'rx'); %%text(nodes(i,1),nodes(i,2),num2str(i)); \nend\n");
1130  //fprintf(file, "for i = 1:size(edges,1)\n plot(nodes(edges(i,1:2),1),nodes(edges(i,1:2),2),colors(edges(i,3)));\nend\n");
1131  fprintf(file, "for i = 1:size(edges,1)\n quiver(nodes(edges(i,1),1),nodes(edges(i,1),2),nodes(edges(i,2),1)-nodes(edges(i,1),1),nodes(edges(i,2),2)-nodes(edges(i,1),2),1,colors(edges(i,3)));\nend\n");
1132  fprintf(file, "for i = 1:size(edges,1)\n %%text(mean(nodes(edges(i,1:2),1)),mean(nodes(edges(i,1:2),2)),['\\color{red} ',num2str(i)]);\nend\n");
1133 
1134  fclose(file);
1135 #endif
1136 }
1137 
1138 void ParticleTopologyDescription :: generateMesh(std :: vector< FloatArray > &nodes, std :: vector< IntArray > &elements, std :: vector< IntArray > &segments,
1139  std :: vector< IntArray > &n_markers, IntArray &e_markers, IntArray &s_markers, IntArray &e_egt, IntArray &s_egt)
1140 {
1141  double maxArea = 0.05;
1142  IntArray r_markers;
1143 
1144  TriangleMesherInterface tmi(30, maxArea, true);
1145 
1146  Triangle_PSLG pslg;
1147  this->generatePSLG(pslg);
1148  tmi.meshPSLG(pslg,
1149  //holes, regions, r_markers,
1150  this->regionOutside, this->regionInside, // Input
1151  nodes, n_markers, elements, e_markers, segments, s_markers); // Output
1152 
1153  // Append the corner nodes manually. Didn't see any pretty way to do this.
1154 #if 0 // Replace by this...
1155  for ( ParticleGrid< ParticlePoint > :: iterator it = this->grid->begin(); !it.end(); ++it ) {
1156  ParticlePoint *origin;
1157  if ( ( origin = it.getPoint() ) != NULL ) {
1158  double dist2, min_dist2 = 1e100;
1159  int min_i = 0;
1160  for ( int i = 1; i <= ( int ) nodes.size(); ++i ) {
1161  dist2 = nodes [ i - 1 ].distance_square(point->foot);
1162  if ( dist2 < min_dist2 ) {
1163  min_dist2 = dist2;
1164  min_i = i;
1165  }
1166  }
1167  n_markers.at(min_i)->insertSortedOnce(point->id);
1168  }
1169  }
1170 #else
1171  for ( std :: list< ParticlePoint > :: iterator cit = this->corners.begin(); cit != this->corners.end(); ++cit ) {
1172  double dist2, min_dist2 = 1e100;
1173  int min_i = 0;
1174  for ( int i = 1; i <= ( int ) nodes.size(); ++i ) {
1175  dist2 = nodes [ i - 1 ].distance_square(cit->foot);
1176  if ( dist2 < min_dist2 ) {
1177  min_dist2 = dist2;
1178  min_i = i;
1179  }
1180  }
1181  n_markers [ min_i - 1 ].insertSortedOnce(cit->id);
1182  }
1183 #endif
1184 
1185 #if 1 // DEBUG: Print all to matlab file
1186  printf("Printing mesh.m\n");
1187  FILE *file = fopen("mesh.m", "w");
1188  fprintf(file, "nodes = [");
1189  for ( int i = 1; i <= ( int ) nodes.size(); i++ ) {
1190  FloatArray &x = nodes [ i - 1 ];
1191  for ( int j = 1; j <= 2; j++ ) {
1192  fprintf( file, "%e, ", x.at(j) );
1193  }
1194  fprintf( file, " %d", n_markers [ i - 1 ].at(1) );
1195  fprintf(file, ";\n");
1196  }
1197  fprintf(file, "];\n");
1198 
1199  fprintf(file, "triangles = [");
1200  for ( int i = 1; i <= ( int ) elements.size(); i++ ) {
1201  IntArray &x = elements [ i - 1 ];
1202  for ( int j = 1; j <= x.giveSize(); j++ ) {
1203  fprintf( file, "%d, ", x.at(j) );
1204  }
1205  fprintf( file, "%d", e_markers.at(i) );
1206  fprintf(file, ";\n");
1207  }
1208  fprintf(file, "];\n");
1209 
1210  fprintf(file, "segments = [");
1211  for ( int i = 1; i <= ( int ) segments.size(); i++ ) {
1212  IntArray &x = segments [ i - 1 ];
1213  for ( int j = 1; j <= x.giveSize(); j++ ) {
1214  fprintf( file, "%d, ", x.at(j) );
1215  }
1216  fprintf( file, "%d", s_markers.at(i) );
1217  fprintf(file, ";\n");
1218  }
1219  fprintf(file, "];\n");
1220 
1221  //fprintf(file, "clf\nhold on\nfor i = 1:size(triangles,1); plot(nodes(triangles(i,[1:3,1]),1), nodes(triangles(i,[1:3,1]),2), 'r'); end\n");
1222  fprintf(file, "clf\nhold on\n xx = nodes(:,1); yy = nodes(:,2); patch(xx(triangles(:,1:3))',yy(triangles(:,1:3))',triangles(:,end)'); \n");
1223  fprintf(file, "for i = 1:size(segments,1); plot(nodes(segments(i,1:2),1), nodes(segments(i,1:2),2), 'b'); end\n");
1224 
1225  fclose(file);
1226 #endif
1227 }
1228 
1230 {
1231  std :: vector< FloatArray >nodes;
1232  std :: vector< IntArray >elements, segments, n_markers;
1234  std :: vector< IntArray >boundarySets( regionSet.maximum() );
1235  //std::vector< IntArray >buldSets( regionSet.maximum() );
1236  IntArray e_markers, s_markers, e_egt, s_egt;
1237  this->generateMesh(nodes, elements, segments, n_markers, e_markers, s_markers, e_egt, s_egt);
1238 
1239  for ( int i = 1; i <= ( int ) elements.size(); ++i ) {
1240  int r = e_markers.at(i);
1241  int set = regionSet.at(r);
1242  if ( set ) {
1243  boundarySets [ set - 1 ].followedBy(i);
1244  boundarySets [ set - 1 ].followedBy(0);
1245  }
1246  }
1247  for ( int i = 1; i <= ( int ) segments.size(); ++i ) {
1248  int r = s_markers.at(i);
1249  int set = regionSet.at(r);
1250  if ( set ) {
1251  boundarySets [ set - 1 ].followedBy( i + elements.size() );
1252  boundarySets [ set - 1 ].followedBy(0);
1253  }
1254  }
1255 
1256  // Replace all the elements with the new set.
1257  Domain *new_d;
1258  // Should i use a new domain and replace it instead?
1259  new_d = this->d;
1260 
1261  // Clear everything old;
1262  new_d->resizeElements( elements.size() + segments.size() );
1263  new_d->resizeDofManagers( nodes.size() );
1264  new_d->resizeSets( regionSet.giveSize() );
1265 
1266  for ( int i = 1; i <= ( int ) nodes.size(); ++i ) {
1267  //DynamicInputRecord *dir = new DynamicInputRecord(_IFT_Node_Name, i);
1268  //dir->setField(nodes[i-1], _IFT_Node_coords);
1269  //dr->insertInputRecord(IR_dofmanRec, dir);
1270  Node *node = new Node(i, new_d);
1271  node->setCoordinates(nodes [ i - 1 ]);
1272  new_d->setDofManager(i, node);
1273  }
1274 
1275  for ( int i = 1; i <= ( int ) elements.size(); ++i ) {
1276  int r = e_markers.at(i);
1277  //DynamicInputRecord *dir = new DynamicInputRecord(regionElementType[ r-1 ], i);
1278  //dir->setField(r, _IFT_Element_crosssect);
1279  //dir->setField(elements[i-1], _IFT_Element_nodes);
1280  //dr->insertInputRecord(IR_elemRec, dir);
1281  Element *element = classFactory.createElement(this->regionElementType [ r - 1 ].c_str(), i, new_d);
1282  element->setGlobalNumber(i);
1283  element->setCrossSection(r);
1284  element->setDofManagers(elements [ i - 1 ]);
1285  element->setParallelMode(Element_local);
1286  new_d->setElement(element->giveNumber(), element);
1287  }
1288 
1289  for ( int i = 1; i <= ( int ) segments.size(); ++i ) {
1290  int r = s_markers.at(i);
1291  //DynamicInputRecord *dir = new DynamicInputRecord(regionElementType[ r-1 ], segments.size() + i);
1292  //dir->setField(r, _IFT_Element_crosssect);
1293  //dir->setField(segments[i-1], _IFT_Element_nodes);
1294  //dr->insertInputRecord(IR_elemRec, dir);
1295  Element *element = classFactory.createElement(regionElementType [ r - 1 ].c_str(), elements.size() + i, new_d);
1296  if ( !element ) {
1297  printf( "Couldn't create: %s\n", regionElementType [ r - 1 ].c_str() );
1298  }
1299  element->setGlobalNumber( i + elements.size() );
1300  element->setCrossSection(r);
1301  element->setDofManagers(segments [ i - 1 ]);
1302  element->setParallelMode(Element_local);
1303  new_d->setElement(element->giveNumber(), element);
1304  }
1305 
1306  for ( int i = 1; i <= ( int ) boundarySets.size(); ++i ) {
1307  //DynamicInputRecord *dir = new DynamicInputRecord(_IFT_Set_Name, i);
1308  //dir->setField(boundarySets[i-1], _IFT_Set_elementBoundaries);
1309  //dr->insertInputRecord(IR_setRec, dir);
1310  Set *set = new Set(1, new_d);
1311  set->setBoundaryList(boundarySets [ i - 1 ]);
1312  new_d->setSet(i, set);
1313  }
1314 
1315  new_d->postInitialize();
1316  new_d->giveEngngModel()->checkConsistency();
1317  new_d->giveEngngModel()->forceEquationNumbering(); // TODO: This shouldn't be necessary
1318 }
1319 }
void removePoints(ParticleGrid< ParticlePoint > &g) const
Clears all points marked for removal.
void addLineSegment(int id, const FloatArray &p0, const FloatArray &p1, ParticleGrid< ParticlePoint > &grid) const
Used for initialization, calculating the distance from primitives.
std::string giveOutputBaseFileName()
Returns base output file name to which extensions, like .out .vtu .osf should be added.
Definition: engngm.h:363
void resizeDofManagers(int _newSize)
Resizes the internal data structure to accommodate space for _newSize dofManagers.
Definition: domain.C:444
Class and object Domain.
Definition: domain.h:115
#define _IFT_ParticleTopologyDescription_numberOfSegments
bool writeVTK
Conditional for printing VTK output.
static void getBoundingBox(FloatArray &x0, FloatArray &x1, const FloatArray &c, double width)
Helper for common task of fetching a bounding box around a point.
IntArray segment_b
Second segment connection.
IntArray regionOutside
Mapping of regions from delimited by each id.
void resizeSets(int _newSize)
Resizes the internal data structure to accommodate space for _newSize sets.
Definition: domain.C:452
#define _IFT_Meshing_elementType
#define _IFT_Circle_center
Definition: geometry.h:54
static bool compare_edge(edge a, edge b)
virtual void writeVTKFile(const char *name) const
FloatArray corner
Corner particle (for open surfaces).
A recursive iterator for a grid with refinements.
Definition: particlegrid.h:49
void zero()
Sets all component to zero.
Definition: intarray.C:52
double & at(int i)
Coefficient access function.
Definition: floatarray.h:131
int max(int i, int j)
Returns bigger value form two given decimals.
Definition: mathfem.h:71
void postInitialize()
Performs post-initialization for all the domain contents (which is called after initializeFrom).
Definition: domain.C:960
static void simplifyPSLG(Triangle_PSLG &coarse, const Triangle_PSLG &pslg, double limit, double minlen=0.0)
Simplifies a PSLG while respecting topology, running in linear time.
REGISTER_TopologyDescription(ParticleTopologyDescription)
int getTotal() const
Total number potential points.
Definition: particlegrid.h:127
bool meshPSLG(const Triangle_PSLG &pslg, const IntArray &outside, const IntArray &inside, std::vector< FloatArray > &nodes, std::vector< IntArray > &n_markers, std::vector< IntArray > &triangles, IntArray &t_markers, std::vector< IntArray > &segments, IntArray &s_markers) const
Constructs a mesh from a PSLG.
#define _IFT_Point_coords
Indicates that everything is OK with respect to topology.
EngngModel * giveEngngModel()
Returns engineering model to which receiver is associated.
Definition: domain.C:433
virtual TopologyState updateYourself(TimeStep *tStep)
Updates the topology from the FE solution.
#define _IFT_ParticleTopologyDescription_boundingBoxA
Abstract base class for all finite elements.
Definition: element.h:145
void resizeElements(int _newSize)
Resizes the internal data structure to accommodate space for _newSize elements.
Definition: domain.C:445
Class representing the abstraction for input data source.
Definition: datareader.h:50
Indicates that the topology has reached a need for remeshing, as the case with merging surfaces...
#define _IFT_Circle_end
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition: domain.C:1067
Particle grid data structure for n-D grids.
Definition: particlegrid.h:57
#define _IFT_ParticleTopologyDescription_boundingBoxB
Class implementing an array of integers.
Definition: intarray.h:61
int & at(int i)
Coefficient access function.
Definition: intarray.h:103
void beMaxOf(const FloatArray &a, const FloatArray &b)
Sets receiver to maximum of a or b&#39;s respective elements.
Definition: floatarray.C:288
virtual bool instanciateYourself(DataReader &dr)
Instanciates itself.
void setParallelMode(elementParallelMode _mode)
Sets parallel mode of element.
Definition: element.h:1071
virtual void doOutput(TimeStep *tStep)
File output of the current state of the topology description.
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Sets receiver to be a - b.
Definition: floatarray.C:341
#define _IFT_ParticleTopologyDescription_nsd
double giveTimeIncrement()
Returns solution step associated time increment.
Definition: timestep.h:150
#define _IFT_Circle_start
FloatArray ny
Nodes y coordinates.
FloatArray total_displacement
Total displacement since last resampling.
#define _IFT_Meshing_set
void cubic(double a, double b, double c, double d, double *r1, double *r2, double *r3, int *num)
Solves cubic equation for real roots.
Definition: mathfem.C:43
FloatArray foot
Closest coordinate on surface.
#define _IFT_ParticleTopologyDescription_neighbors
#define _IFT_Line_end
Definition: geometry.h:58
#define _IFT_Line_start
Definition: geometry.h:57
virtual void writeDataToFile(const char *name) const
void beMinOf(const FloatArray &a, const FloatArray &b)
Sets receiver to be minimum of a or b&#39;s respective elements.
Definition: floatarray.C:315
#define _IFT_ParticleTopologyDescription_baseResolution
int giveNumber()
Returns receiver&#39;s number.
Definition: timestep.h:129
#define OOFEM_LOG_INFO(...)
Definition: logger.h:127
#define _IFT_ParticleTopologyDescription_regionInside
#define M_PI
Definition: mathfem.h:52
#define _IFT_ParticleTopologyDescription_regionOutside
double dotProduct(const FloatArray &x) const
Computes the dot product (or inner product) of receiver and argument.
Definition: floatarray.C:463
static bool compare_second(std::pair< ParticlePoint *, double >a, std::pair< ParticlePoint *, double >b)
bool resampled
Denotes if the active grid is newly resampled.
#define OOFEM_ERROR(...)
Definition: error.h:61
double computeSquaredNorm() const
Computes the square of the norm.
Definition: floatarray.C:846
std::unique_ptr< ParticleGrid< ParticlePoint > > grid
The grid of points, the actual topological information.
Set of elements, boundaries, edges and/or nodes.
Definition: set.h:66
SpatialLocalizer * giveSpatialLocalizer()
Returns receiver&#39;s associated spatial localizer.
Definition: domain.C:1184
double shortestDistanceFromCurve(const FloatArray &a, double txi_min, double txi_max, const FloatArray &n0, const FloatArray &y0, const FloatArray &p, FloatArray &foot, FloatArray &normal) const
Helper for calculateShortestDistance.
#define IR_GIVE_RECORD_KEYWORD_FIELD(__ir, __name, __value)
Macro facilitating the use of input record reading methods.
Definition: inputrecord.h:86
int maximum() const
Finds the maximum component in the array.
Definition: intarray.C:195
void beLocalCoordSys(const FloatArray &normal)
Makes receiver the local coordinate for the given normal.
Definition: floatmatrix.C:515
Domain * d
Domain which topology belongs to.
virtual void setCrossSection(int csIndx)
Sets the cross section model of receiver.
Definition: element.h:653
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Receiver becomes the result of the product of aMatrix and anArray.
Definition: floatarray.C:676
virtual void generateMesh(std::vector< FloatArray > &nodes, std::vector< IntArray > &elements, std::vector< IntArray > &segments, std::vector< IntArray > &n_markers, IntArray &e_markers, IntArray &s_markers, IntArray &e_egt, IntArray &s_egt)
Generates a mesh from the topology.
virtual void replaceFEMesh()
Generates the FE components from the bare mesh.
Default point type for describing topology.
#define N(p, q)
Definition: mdm.C:367
virtual void giveElementDofIDMask(IntArray &answer) const
Returns element dof mask for node.
Definition: element.h:498
Plane straight line graph used as input for meshing with triangle.
double at(int i, int j) const
Coefficient access function.
Definition: floatmatrix.h:176
double distance_square(const FloatArray &iP1, const FloatArray &iP2, double &oXi, double &oXiUnbounded) const
Definition: floatarray.C:499
void resize(int n)
Checks size of receiver towards requested bounds.
Definition: intarray.C:124
#define _IFT_ParticleTopologyDescription_identification
void ls2fit(const FloatArray &x, const FloatArray &y, FloatArray &a)
Least-square fit of 2nd degree polynomial .
Definition: mathfem.C:271
void addCorner(int id, const FloatArray &c, ParticleGrid< ParticlePoint > &grid)
Adds a corner node.
void collectNeighbors(std::list< ParticlePoint * > &answer, const ParticlePoint *p, double dist=0) const
Collects neighboring points according to some specification.
void setDofManagers(const IntArray &dmans)
Sets receiver dofManagers.
Definition: element.C:550
virtual InputRecord * giveInputRecord(InputRecordType irType, int recordId)=0
Returns input record corresponding to given InputRecordType value and its record_id.
void add(int val)
Adds given scalar to all values of receiver.
Definition: intarray.C:58
Class representing vector of real numbers.
Definition: floatarray.h:82
virtual int checkConsistency()
Allows programmer to test some receiver&#39;s internal data, before computation begins.
Definition: engngm.h:995
virtual int init(bool force=false)
Initialize receiver data structure if not done previously If force is set to true, the initialization is enforced (useful if domain geometry has changed)
Element is local, there are no contributions from other domains to this element.
Definition: element.h:101
Implementation of matrix containing floating point numbers.
Definition: floatmatrix.h:94
#define _IFT_Circle_radius
Definition: geometry.h:53
IRResultType
Type defining the return values of InputRecord reading operations.
Definition: irresulttype.h:47
int m
Number of points to use for resampling.
void setCoordinates(FloatArray coords)
Sets node coordinates to given array.
Definition: node.h:126
void setDofManager(int i, DofManager *obj)
Sets i-th component. The component will be further managed and maintained by domain object...
Definition: domain.C:454
double computeNorm() const
Computes the norm (or length) of the vector.
Definition: floatarray.C:840
void resize(int rows, int cols)
Checks size of receiver towards requested bounds.
Definition: floatmatrix.C:1358
virtual Element * giveElementClosestToPoint(FloatArray &lcoords, FloatArray &closest, const FloatArray &coords, int region=0)=0
Returns the element closest to a given point.
Class representing the general Input Record.
Definition: inputrecord.h:101
void zero()
Zeroes all coefficients of receiver.
Definition: floatarray.C:658
Class implementing single timer, providing wall clock and user time capabilities. ...
Definition: timer.h:46
int node
Node number (for meshing)
void setGlobalNumber(int num)
Sets receiver globally unique number.
Definition: element.h:1064
void setElement(int i, Element *obj)
Sets i-th component. The component will be further managed and maintained by domain object...
Definition: domain.C:455
Abstract class for topology description.
void times(double s)
Multiplies receiver with scalar.
Definition: floatarray.C:818
ClassFactory & classFactory
Definition: classfactory.C:59
Interface to Triangle (Delaunay mesher).
double tubeWidth
Width of the tube around the interfaces.
void push_back(const double &iVal)
Add one element.
Definition: floatarray.h:118
void calculateShortestDistance(const ParticlePoint *p, std::list< ParticlePoint * > &points, ParticleGrid< ParticlePoint > &grid) const
Shortest distance from least square fit based on 2nd order polynomial.
std::list< ParticlePoint > corners
Corner nodes.
void addCircleSegment(int id, const FloatArray &c, double r, double v0, double v1, ParticleGrid< ParticlePoint > &grid) const
Used for initialization, calculating the distance from primitives.
double maxdisp2
Maximum squared displacement of any particle.
FloatArray normal
Surface normal at foot point.
virtual int forceEquationNumbering(int i)
Forces equation renumbering on given domain.
Definition: engngm.C:408
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Macro facilitating the use of input record reading methods.
Definition: inputrecord.h:78
int giveSize() const
Definition: intarray.h:203
TopologyState checkOverlap()
Deactivates points with inconsistent information.
int giveSize() const
Returns the size of receiver.
Definition: floatarray.h:218
#define _IFT_ParticleTopologyDescription_tubeWidth
virtual void computeField(ValueModeType mode, TimeStep *tStep, const FloatArray &lcoords, FloatArray &answer)
Computes the unknown vector interpolated at the specified local coordinates.
Definition: element.h:508
FloatArray nx
Nodes x coordinates.
the oofem namespace is to define a context or scope in which all oofem names are defined.
static bool sort_edge(edge a, edge b)
Class implementing node in finite element mesh.
Definition: node.h:87
void generatePSLG(Triangle_PSLG &PSLG)
Generates the PSLG for meshing with Triangle.
virtual void finish(bool wrn=true)=0
Terminates the current record session and if the flag is true, warning is printed for unscanned token...
#define IR_GIVE_FIELD(__ir, __value, __id)
Macro facilitating the use of input record reading methods.
Definition: inputrecord.h:69
int giveNumber() const
Definition: femcmpnn.h:107
double normalize()
Normalizes receiver.
Definition: floatarray.C:828
Element * createElement(const char *name, int num, Domain *domain)
Creates new instance of element corresponding to given keyword.
Definition: classfactory.C:159
bool useDisplacements
Determines if velocity or displacements dofs should be used to update geometry.
std::vector< std::string > regionElementType
Mapping from region to FE components.
bool isEmpty() const
Returns true if the entire grid is empty.
Definition: particlegrid.h:306
void startTimer()
Definition: timer.C:69
double getUtime()
Returns total user time elapsed in seconds.
Definition: timer.C:105
TopologyState
Determines the state of the evolving topology.
bool findDisplacement(FloatArray &answer, int id, const FloatArray &footpoint, TimeStep *tStep) const
Finds the displacement for the underlying FE-mesh.
void setSet(int i, Set *obj)
Sets i-th component. The component will be further managed and maintained by domain object...
Definition: domain.C:462
#define OOFEM_WARNING(...)
Definition: error.h:62
Class representing solution step.
Definition: timestep.h:80
double distance2
Squared distance stored for efficiency.
void stopTimer()
Definition: timer.C:77
void add(const FloatArray &src)
Adds array src to receiver.
Definition: floatarray.C:156
IntArray segment_a
First segment connection.
bool getPoint(Point *&answer, const IntArray &pos) const
Gives the point at the position.
Definition: particlegrid.h:447
IntArray segment_marker
Segment markers.
iterator beginAt(const FloatArray &x0, const FloatArray &x1)
Returns an iterator over specified region.
Definition: particlegrid.h:390
void clearPosition(const IntArray &pos)
Deletes any preexisting data at position.
Definition: particlegrid.h:486
void resize(int s)
Resizes receiver towards requested size.
Definition: floatarray.C:631

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:30 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011