LBIBCell
 All Classes Functions Variables Friends Pages
Connection.cpp
1 /* Copyright (c) 2013 David Sichau <mail"at"sichau"dot"eu>
2  * 2013-2015 Simon Tanaka <tanakas"at"gmx"dot"ch>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 #include <LbmLib/include/geometry/Connection.hpp>
23 #include <LbmLib/include/nodes/BoundaryNode.hpp>
24 #include <LbmLib/include/nodes/GeometryNode.hpp>
25 #include <LbmLib/include/nodes/PhysicalNode.hpp>
26 
27 #include <LbmLib/include/Constants.hpp>
28 
29 #include <UtilLib/include/Log.hpp>
30 #include <algorithm>
31 #include <random>
32 #include <cassert>
33 #include <cmath>
34 #include <fstream>
35 #include <iomanip>
36 #include <iostream>
37 #include <list>
38 #include <map>
39 #include <string>
40 #include <utility>
41 #include <vector>
42 #include <omp.h>
43 
44 namespace LbmLib {
45 namespace geometry {
46 class GeometryNode;
47 
52  std::shared_ptr<nodes::GeometryNode> const p1,
53  std::shared_ptr<nodes::GeometryNode> const p2,
54  const std::map<std::string, std::vector<std::string> > connectionType,
55  unsigned int domainId) : points_(std::make_pair(p1, p2)),
56  connectionType_(connectionType),
57  domainIdentifier_(domainId)
58 {
59  //p1->setConnection<0>(std::make_shared<Connection>(this));
60  //p2->setConnection<1>(std::shared_ptr<Connection>(this));
61 }
62 
64 {
68 }
69 
70 namespace {
78 double getYPos(
79  double m,
80  double x,
81  double n) {
82  return m * x + n;
83 }
84 
92 double getXPos(
93  double m,
94  double y,
95  double n) {
96  return (y - n) / m;
97 }
98 
107 double getGradient(
108  double x1,
109  double x2,
110  double y1,
111  double y2) {
112  return (y2 - y1) / (x2 - x1);
113 }
114 
123 double getAxisIntercept(
124  double x1,
125  double x2,
126  double y1,
127  double y2) {
128  return y1 - (y2 - y1) / (x2 - x1) * x1;
129 }
130 
138 double getAxisIntercept(
139  double x,
140  double y,
141  double m) {
142  return y - m * x;
143 }
144 }
145 
146 Field<double> Connection::calculateVelocity(const nodes::BoundaryNode& bNode) {
147  const double l = getDistance(*points_.first,bNode);
148  const double L = getDistance(*points_.second, *points_.first);
149  const double vx1 = this->points_.first->getXVelocity();
150  const double vy1 = this->points_.first->getYVelocity();
151  const double vx2 = this->points_.second->getXVelocity();
152  const double vy2 = this->points_.second->getYVelocity();
153  const double vx = (vx2-vx1) * l/L + vx1;
154  const double vy = (vy2-vy1) * l/L + vy1;
155  assert(std::isfinite(l));
156  assert(std::isfinite(L));
157  assert(std::isfinite(vx1));
158  assert(std::isfinite(vy1));
159  assert(std::isfinite(vx2));
160  assert(std::isfinite(vy2));
161  assert(std::isfinite(vx));
162  assert(std::isfinite(vy));
163  Field<double> f;
164  f.x = vx;
165  f.y = vy;
166  return f;
167  //return ((points_.second->getVelocity() - points_.first->getVelocity()) / getDistance(*points_.second, *points_.first)) * getDistance(*points_.first,bNode) + points_.first->getVelocity();
168 }
169 
170 void Connection::writeConnection(std::ofstream* const stream) {
171  (*stream) << points_.first->getId() << '\t' << points_.second->getId() <<
172  '\t' << domainIdentifier_;
173  for (const auto& bSolver : connectionType_) {
174  for (const auto& cdeSolver : bSolver.second) {
175  (*stream) << '\t' << bSolver.first << '\t' << cdeSolver;
176  }
177  }
178  (*stream) << '\n';
179 }
180 
181 void Connection::insertBoundaryNode(nodes::BoundaryNode* const newBoundaryNode,
182  nodes::PhysicalNode* const physicalNode,
183  const Direction& d,
184  std::unordered_set<nodes::BoundaryNode *> &boundaryNodes) {
185  assert(newBoundaryNode != nullptr);
186  assert(physicalNode != nullptr);
187  nodes::BoundaryNode* old = physicalNode->getBoundaryNeighbour(
188  getInverseDirection(d));
189 
190  // not a boundary node yet
191  if (old == nullptr) {
192  Field<double> ftemp = calculateVelocity(*newBoundaryNode);
193  assert(std::isfinite(ftemp.x));
194  assert(std::isfinite(ftemp.y));
195  newBoundaryNode->setVelocity(ftemp);
196 #pragma omp critical // boundaryNodes is not thread safe
197  {
198  boundaryNodes.insert(newBoundaryNode);
199  }
200  newBoundaryNode->setPhysicalNeighbours(physicalNode, d);
201  } else if (getSquaredDistance(*physicalNode,
202  *newBoundaryNode) <
203  getSquaredDistance(*physicalNode, *old)) {
204  // it has a boundary node but the new is closer
205  Field<double> ftemp = calculateVelocity(*newBoundaryNode);
206  assert(std::isfinite(ftemp.x));
207  assert(std::isfinite(ftemp.y));
208  newBoundaryNode->setVelocity(ftemp);
209 
210 #pragma omp critical // boundaryNodes is not thread safe
211  {
212  boundaryNodes.insert(newBoundaryNode);
213  }
214 #pragma omp critical // boundaryNodes is not thread safe
215  {
216  boundaryNodes.erase(old);
217  }
218  newBoundaryNode->setPhysicalNeighbours(physicalNode, d);
219  } else {
220  delete newBoundaryNode; // the old boundary node is closer
221  }
222 }
223 
224 void Connection::generateBoundaryNodes(const std::vector<std::vector<nodes::PhysicalNode*> >& physicalNodes,
225  std::unordered_set<nodes::BoundaryNode *> &boundaryNodes) {
226  assert(std::isfinite(this->points_.first->getXPos()));
227  assert(std::isfinite(this->points_.first->getYPos()));
228  assert(std::isfinite(this->points_.second->getXPos()));
229  assert(std::isfinite(this->points_.second->getYPos()));
230  double maxX = std::max(this->points_.first->getXPos(), this->points_.second->getXPos());
231  double maxY = std::max(this->points_.first->getYPos(), this->points_.second->getYPos());
232  double minX = std::min(this->points_.first->getXPos(), this->points_.second->getXPos());
233  double minY = std::min(this->points_.first->getYPos(), this->points_.second->getYPos());
234 
235  // compute slope:
236  double m = getGradient(points_.first->getXPos(),
237  points_.second->getXPos(),
238  points_.first->getYPos(), points_.second->getYPos());
239 
240  // compute intercept:
241  double n = getAxisIntercept(
242  points_.first->getXPos(),
243  points_.second->getXPos(),
244  points_.first->getYPos(), points_.second->getYPos());
245 
246  if (std::isfinite(m)) {
247  // with vertical lattice lines:
248  for (int i = std::ceil(minX); i <= std::floor(maxX); i++) {
249  nodes::BoundaryNode* bpS; // south
250  nodes::BoundaryNode* bpN; // north
251  if (points_.first->getXPos() < points_.second->getXPos()) {
252  // the north is inside
253  bpN = new nodes::BoundaryNode(i, getYPos(m,
254  i,
255  n), connectionType_,
256  this->domainIdentifier_);
257  bpS = new nodes::BoundaryNode(i, getYPos(m,
258  i,
259  n), connectionType_,
260  0);
261  } else {
262  // the south is inside
263  bpN = new nodes::BoundaryNode(i, getYPos(m,
264  i,
265  n), connectionType_,
266  0);
267  bpS = new nodes::BoundaryNode(i, getYPos(m,
268  i,
269  n), connectionType_,
270  this->domainIdentifier_);
271  }
272 
273  nodes::PhysicalNode* fluidS =
274  physicalNodes[std::floor(getYPos(m, i, n))][i];
275  nodes::PhysicalNode* fluidN =
276  physicalNodes[std::ceil(getYPos(m, i, n))][i];
277 
278  this->insertBoundaryNode(bpS, fluidS, S, boundaryNodes);
279  this->insertBoundaryNode(bpN, fluidN, N, boundaryNodes);
280  }
281 
282  // with horizontal lattice lines:
283  for (int i = std::ceil(minY); i <= std::floor(maxY); i++) {
284  nodes::BoundaryNode* bpE;
285  nodes::BoundaryNode* bpW;
286  if (points_.first->getYPos() > points_.second->getYPos()) {
287  // east is inside
288  bpW = new nodes::BoundaryNode(getXPos(m,
289  i,
290  n), i, connectionType_,
291  0);
292  bpE = new nodes::BoundaryNode(getXPos(m,
293  i,
294  n), i, connectionType_,
295  this->domainIdentifier_);
296  } else {
297  // west is inside
298  bpW = new nodes::BoundaryNode(getXPos(m,
299  i,
300  n), i, connectionType_,
301  this->domainIdentifier_);
302  bpE = new nodes::BoundaryNode(getXPos(m,
303  i,
304  n), i, connectionType_,
305  0);
306  }
307  nodes::PhysicalNode* fluidW =
308  physicalNodes[i][std::floor(getXPos(m, i, n))];
309  nodes::PhysicalNode* fluidE =
310  physicalNodes[i][std::ceil(getXPos(m, i, n))];
311 
312  this->insertBoundaryNode(bpW, fluidW, W, boundaryNodes);
313  this->insertBoundaryNode(bpE, fluidE, E, boundaryNodes);
314  }
315  } else {
316  std::stringstream message;
317  message << std::setprecision(12);
318  message << "This can only happen if something went wrong with the perturbation of the connection. ";
319  message << "p1.x="<<points_.first->getXPos()<<", p1.y="<<points_.first->getYPos();
320  message << ", p2.x="<<points_.second->getXPos()<<", p2.y="<<points_.second->getYPos();
321 #pragma omp critical
322  lbm_fail(message.str().c_str());
323  }
324 }
325 
326 std::pair<const std::shared_ptr<nodes::GeometryNode>,
327  const std::shared_ptr<nodes::GeometryNode> > Connection::
329  return points_;
330 }
331 
333  const int seed = 1; // for debugging
334  static std::random_device rd;
335  //static std::mt19937 gen(rd());
336  static std::mt19937 gen(seed);
337  static std::uniform_real_distribution<> dis(-PERTURBATION, PERTURBATION);
338  double temprand;
339  if (std::abs(points_.first->getXPos() - points_.second->getXPos()) <
340  EPSILON) {
341  std::stringstream message;
342  message << std::setprecision(12)
343  << "Perturbation of Connection ("
344  << this->points_.first->getId() << "->" << this->points_.second->getId()<<") " // ID
345  << "(" << this->points_.first->getXPos() << "," << this->points_.first->getYPos() << ")" // first GeometryNode
346  << "->"
347  << "(" << this->points_.second->getXPos() << "," << this->points_.second->getYPos() << ") " // second GeometryNode
348  << " to ";
349  temprand = 0.0;
350  while(std::abs(temprand) < 5.0*EPSILON) {
351  temprand = dis(gen);
352  }
353  points_.first->setPos(
354  points_.first->getXPos() + temprand,
355  points_.first->getYPos());
356  message << "(" << this->points_.first->getXPos() << "," << this->points_.first->getYPos() << ")" // first GeometryNode
357  << "->"
358  << "(" << this->points_.second->getXPos() << "," << this->points_.second->getYPos() << ") "; // second GeometryNode
359 #pragma omp critical
360  LOG(UtilLib::logINFO) << message.str().c_str();
361  }
362 
363  if (std::abs(points_.first->getYPos() - points_.second->getYPos()) <
364  EPSILON) {
365  std::stringstream message;
366  message << std::setprecision(12)
367  << "Perturbation of Connection ("
368  << this->points_.first->getId() << "->" << this->points_.second->getId()<<") " // ID
369  << "(" << this->points_.first->getXPos() << "," << this->points_.first->getYPos() << ")" // first GeometryNode
370  << "->"
371  << "(" << this->points_.second->getXPos() << "," << this->points_.second->getYPos() << ") " // second GeometryNode
372  << " to ";
373  temprand = 0.0;
374  while(std::abs(temprand) < 5.0*EPSILON) {
375  temprand = dis(gen);
376  }
377  points_.first->setPos(
378  points_.first->getXPos(),
379  points_.first->getYPos() + temprand);
380  message << "(" << this->points_.first->getXPos() << "," << this->points_.first->getYPos() << ")" // first GeometryNode
381  << "->"
382  << "(" << this->points_.second->getXPos() << "," << this->points_.second->getYPos() << ") "; // second GeometryNode
383 
384 #pragma omp critical
385  LOG(UtilLib::logINFO) << message.str().c_str();
386  }
387 }
388 
389 double Connection::getLength() const {
390  return std::sqrt((this->points_.first->getXPos() - this->points_.second->getXPos()) *
391  (this->points_.first->getXPos() - this->points_.second->getXPos()) +
392  (this->points_.first->getYPos() - this->points_.second->getYPos()) *
393  (this->points_.first->getYPos() - this->points_.second->getYPos()));
394 }
395 
396 unsigned int Connection::getDomainIdentifier() const {
397  return this->domainIdentifier_;
398 }
399 
400 const std::map<std::string, std::vector<std::string> > Connection::getBoundaryConditionDescriptor() const {
401  return this->connectionType_;
402 }
403 
404 void Connection::setDomainIdentifier(const unsigned int domainIdentifier)
405 {
406  this->domainIdentifier_ = domainIdentifier;
407 }
408 
409 
410 } // end namespace
411 } // end namespace
void setDomainIdentifier(const unsigned int domainIdentifier)
Setter for the domainIdentifier_.
Definition: Connection.cpp:404
virtual void setVelocity(Field< double > velocity)
setVelocity Set the velocity
void writeConnection(std::ofstream *const stream)
writes the connection ot the stream
Definition: Connection.cpp:170
const std::map< std::string, std::vector< std::string > > getBoundaryConditionDescriptor() const
Getter for the boundary condition descriptor.
Definition: Connection.cpp:400
unsigned int getDomainIdentifier() const
Getter for the domainID on the left side of this connection.
Definition: Connection.cpp:396
void perturbConnection()
perturbConnection makes sure that the connection has a slope not near to 0 or infinitive ...
Definition: Connection.cpp:332
class representing a physical node
T x
x the value in x direction
Definition: Field.hpp:50
~Connection()
~Connection non-virutal Destructor
Definition: Connection.cpp:63
double getLength() const
Compute the length of the connection.
Definition: Connection.cpp:389
Connection(std::shared_ptr< nodes::GeometryNode > const p1, std::shared_ptr< nodes::GeometryNode > const p2, const std::map< std::string, std::vector< std::string > > connectionType, unsigned int domainId)
Connection A simple connection connecting two geometry nodes.
Definition: Connection.cpp:51
std::pair< std::shared_ptr< nodes::GeometryNode > const, std::shared_ptr< nodes::GeometryNode > const > getGeometryNodes() const
getGeometryNodes Getter method for the geometry nodes defining this connection
Definition: Connection.cpp:328
BoundaryNode * getBoundaryNeighbour(const Direction &d) const
getBoundaryNeighbour Getter method to access the Boundary Neighbour
class representing a boundary node
void generateBoundaryNodes(const std::vector< std::vector< nodes::PhysicalNode * > > &physicalNode, std::unordered_set< nodes::BoundaryNode * > &boundaryNodes)
generateBoundaryNodes Calculates all possible boundary points defined by this connection, generates and connects them accordingly
Definition: Connection.cpp:224
T y
y the value in y direction
Definition: Field.hpp:54
void setPhysicalNeighbours(PhysicalNode *const physicalNode, const Direction &dir)
setPhysicalNeighbours Sets the corresponding Physical neighbours of this node