CppNoddy  0.92
Loading...
Searching...
No Matches
TwoD_Mapped_Node_Mesh.cpp
Go to the documentation of this file.
1/// \file TwoD_Mapped_Node_Mesh.cpp
2/// Implementation of a two dimensional (mapped) mesh object. Data
3/// is stored on a (mapped) nodal mesh.
4
5#include <vector>
6#include <fstream>
7#include <iostream>
8#include <iomanip>
9#include <cassert>
10
11#include <Exceptions.h>
12#include <DenseVector.h>
13#include <DenseMatrix.h>
15#include <Utility.h>
16
17namespace CppNoddy {
18
19 template <typename _Type>
20 void TwoD_Mapped_Node_Mesh<_Type>::set_nodes_vars(const std::size_t nodex, const std::size_t nodey, const DenseVector<_Type>& U) {
21#ifdef PARANOID
22 if(U.size() > m_nv) {
23 std::string problem;
24 problem = " The TwoD_Mapped_Node_Mesh.set_nodes_vars method is trying to use a \n";
25 problem += " vector that has more entries than variables stored in the mesh. \n";
26 throw ExceptionRuntime(problem);
27 }
28#endif
29 // assign contents of U to the member data
30 std::size_t offset((nodex * m_ny + nodey) * m_nv);
31 for(std::size_t var = 0; var < m_nv; ++var) {
32 m_vars[ offset++ ] = U[ var ];
33 }
34 }
35
36 template <typename _Type>
37 DenseVector<_Type> TwoD_Mapped_Node_Mesh<_Type>::get_nodes_vars(const std::size_t nodex, const std::size_t nodey) const {
38#ifdef PARANOID
39 if(nodex > m_nx - 1 || nodey > m_ny - 1) {
40 std::string problem;
41 problem = " The TwoD_Mapped_Node_Mesh.get_nodes_vars method is trying to \n";
42 problem += " access a nodal point that is not in the mesh. \n";
43 throw ExceptionRange(problem, m_nx, nodex, m_ny, nodey);
44 }
45#endif
46 // construct a vector with m_nv elements starting from a pointer
47 DenseVector<_Type> nodes_vars(m_nv, &m_vars[(nodex * m_ny + nodey) * m_nv ]);
48 return nodes_vars;
49 }
50
51 template<typename _Type>
53 OneD_Node_Mesh<_Type> xsection(m_Y, m_nv);
54 for(std::size_t nodey = 0; nodey < m_ny; ++nodey) {
55 xsection.set_nodes_vars(nodey, this -> get_nodes_vars(nodex, nodey));
56 }
57 return xsection;
58 }
59
60 template<typename _Type>
62 OneD_Node_Mesh<_Type> xsection(m_X, m_nv);
63 for(std::size_t nodex = 0; nodex < m_nx; ++nodex) {
64 xsection.set_nodes_vars(nodex, this -> get_nodes_vars(nodex, nodey));
65 }
66 return xsection;
67 }
68
69
70 /// Sometimes a useful mapping is painful to invert analytically.
71 /// Here we construct the physical node distribution by finding
72 /// the set of points x_i such that the computation nodes X satisfy
73 /// X_i = FnComp_X(x_i), for example.
74 template <typename _Type>
76 #ifdef DEBUG
77 std::cout << "[DEBUG] Physical domain is [" << m_left << "," << m_right
78 << "] x [" << m_bottom << "," << m_top << "]\n";
79 std::cout << "[DEBUG] Computational domain is ["
80 << FnComp_X(m_left) << "," << FnComp_X(m_right)
81 << "] x [" << FnComp_Y(m_bottom) << "," << FnComp_Y(m_top) << "]\n";
82 #endif
83 {
84 // a uniform mesh in the computational coordinates
85 double comp_left(FnComp_X(m_left));
86 double comp_right(FnComp_X(m_right));
87 const double comp_delta_x = (comp_right - comp_left) / (m_nx - 1);
88 for(std::size_t i = 0; i < m_nx; ++i) {
89 m_compX[i] = comp_left + comp_delta_x * i;
90 }
91 }
92 {
93 // a uniform mesh in the computational coordinates
94 double comp_bottom(FnComp_Y(m_bottom));
95 double comp_top(FnComp_Y(m_top));
96 const double comp_delta_y = (comp_top - comp_bottom) / (m_ny - 1);
97 for(std::size_t j = 0; j < m_ny; ++j) {
98 m_compY[j] = comp_bottom + comp_delta_y * j;
99 }
100 }
101
102 // temporary fill to span the domain -- corrected below
103 m_X = Utility::uniform_node_vector(m_left,m_right,m_nx);
104 m_Y = Utility::uniform_node_vector(m_bottom,m_top,m_ny);
105
106 // we now need the corresponding m_Y coordinates in the physical domain
107 {
108 // start and end points are mapped correctly
109 for(unsigned j = 1; j < m_ny-1; ++j) {
110 // // for each node in m_compY
111 // unsigned kmin(0);
112 // double min(99e9);
113 // for(unsigned k = 0; k < m_ny; ++k) {
114 // // find the y value that is closest to it
115 // if(std::abs(FnComp_Y(m_Y[k]) - m_compY[j]) < min) {
116 // min = std::abs(FnComp_Y(m_Y[k]) - m_compY[j]);
117 // kmin = k;
118 // }
119 // }
120 double y = m_Y[j-1];
121 double delta = 1.e-8;
122 double correction = 1.0;
123 do {
124 double newY = FnComp_Y(y + delta) - m_compY[j];
125 double oldY = FnComp_Y(y) - m_compY[j];
126 double deriv = (newY-oldY)/delta;
127 correction = -oldY/deriv;
128 y += correction;
129 } while(fabs(correction) > 1.e-8);
130 m_Y[ j ] = y;
131 }
132 }
133
134 // we now need the corresponding m_X coordinates in the physical domain
135 {
136 // start and end are already mapped correctly
137 for(unsigned i = 1; i < m_nx-1; ++i) {
138 // use the previous point as an approximate guess at current mapping
139 double x = m_X[i-1];
140 double delta = 1.e-8;
141 double correction = 1.0;
142 do {
143 double newX = FnComp_X(x + delta) - m_compX[i];
144 double oldX = FnComp_X(x) - m_compX[i];
145 double deriv = (newX-oldX)/delta;
146 correction = -oldX/deriv;
147 x += correction;
148 } while(fabs(correction) > 1.e-8);
149 m_X[ i ] = x;
150 }
151 }
152 }
153
154 template <typename _Type>
155 std::pair< double, double> TwoD_Mapped_Node_Mesh<_Type>::get_comp_step_sizes() const {
156 std::pair<double,double> steps;
157 steps.first = m_compX[1]-m_compX[0];
158 steps.second = m_compY[1]-m_compY[0];
159 return steps;
160 }
161
162 template <typename _Type>
163 std::pair< std::size_t, std::size_t > TwoD_Mapped_Node_Mesh<_Type>::get_nnodes() const {
164 std::pair< std::size_t, std::size_t > nodes;
165 nodes.first = m_nx;
166 nodes.second = m_ny;
167 return nodes;
168 }
169
170 template <typename _Type>
172 return m_nv;
173 }
174
175 template <typename _Type>
177 return m_X;
178 }
179
180 template <typename _Type>
182 return m_Y;
183 }
184
185 template<>
186 void TwoD_Mapped_Node_Mesh<double>::normalise(const std::size_t& var) {
187 double maxval(max(var));
188 m_vars.scale(1./maxval);
189 }
190
191 template<>
192 void TwoD_Mapped_Node_Mesh<D_complex>::normalise(const std::size_t& var) {
193 //std::cout << "[DEBUG] asked to normalise a complex mesh\n";
194 unsigned max_nx(0);
195 unsigned max_ny(0);
196 double max(0.0);
197 // step through the nodes
198 for(unsigned nodex = 0; nodex < m_X.size(); ++nodex) {
199 for(unsigned nodey = 0; nodey < m_Y.size(); ++nodey) {
200 if(std::abs(m_vars[(nodex * m_ny + nodey) * m_nv + var ]) > max) {
201 max = std::abs(m_vars[(nodex * m_ny + nodey) * m_nv + var ]);
202 max_nx = nodex;
203 max_ny = nodey;
204 }
205 }
206 }
207 D_complex factor(m_vars[(max_nx * m_ny + max_ny) * m_nv + var ]);
208 //std::cout << "[DEBUG] MAX |variable| had complex value of " << factor << "\n";
209 m_vars.scale(1./factor);
210 }
211
212 template<>
213 void TwoD_Mapped_Node_Mesh<double>::read(std::string filename, bool reset) {
214 std::ifstream dump;
215 dump.open(filename.c_str());
216 if(dump.good() != true) {
217 std::string problem;
218 problem = " The TwoD_Node_Mesh.read method is trying to read a \n";
219 problem += " file (" + filename + ") that doesn't exist.\n";
220 throw ExceptionRuntime(problem);
221 }
222 dump.precision(15);
223 dump.setf(std::ios::showpoint);
224 dump.setf(std::ios::showpos);
225 dump.setf(std::ios::scientific);
226 for(std::size_t i = 0; i < m_nx; ++i) {
227 for(std::size_t j = 0; j < m_ny; ++j) {
228 double x, y;
229 dump >> x;
230 dump >> y;
231 for(std::size_t var = 0; var < m_nv; ++var) {
232 double value;
233 dump >> value;
234 m_vars[(i * m_ny + j) * m_nv + var ] = value;
235 }
236 if(reset != true) {
237 // if not reseting the mesh we should check the node positions
238 if((std::fabs(x - m_X[ i ]) > 1.e-6) || (std::fabs(y - m_Y[ j ]) > 1.e-6)) {
239 std::cout << " Read x = " << x << " Expected x = " << m_X[ i ] << "; Read y = " << y << " Expected y = " << m_Y[ j ] << " \n";
240 std::cout << " Absolute differences are " << fabs(x - m_X[i]) << " and " << fabs(y - m_Y[j]) << "\n";
241 std::string problem;
242 problem = " The TwoD_Node_Mesh.read method is trying to read a \n";
243 problem += " file whose nodal points are in a different position. \n";
244 throw ExceptionRuntime(problem);
245 }
246 } else {
247 m_X[ i ] = x;
248 m_Y[ j ] = y;
249 }
250 }
251 }
252 }
253
254
255 template<>
256 void TwoD_Mapped_Node_Mesh<D_complex>::read(std::string filename, bool reset) {
257 std::ifstream dump;
258 dump.open(filename.c_str());
259 dump.precision(15);
260 dump.setf(std::ios::showpoint);
261 dump.setf(std::ios::showpos);
262 dump.setf(std::ios::scientific);
263 //
264 // 18/06/2017: switched i and j below for consistency with double
265 //
266 for(std::size_t i = 0; i < m_nx; ++i) {
267 for(std::size_t j = 0; j < m_ny; ++j) {
268 double x, y;
269 dump >> x;
270 dump >> y;
271 for(std::size_t var = 0; var < m_nv; ++var) {
272 double value_r, value_i;
273 dump >> value_r;
274 dump >> value_i;
275 m_vars[(i * m_ny + j) * m_nv + var ] = D_complex(value_r, value_i);
276 }
277 if(reset != true) {
278 // if not reseting the mesh we should check the node positions
279 if((std::fabs(x - m_X[ i ]) > 1.e-6) || (std::fabs(y - m_Y[ j ]) > 1.e-6)) {
280 std::cout << " Read x = " << x << " Expected x = " << m_X[ i ] << "; Read y = " << y << " Expected y = " << m_Y[ j ] << " \n";
281 std::cout << " Absolute differences are " << fabs(x - m_X[i]) << " and " << fabs(y - m_Y[j]) << "\n";
282 std::string problem;
283 problem = " The TwoD_Node_Mesh.read method is trying to read a \n";
284 problem += " file whose nodal points are in a different position. \n";
285 throw ExceptionRuntime(problem);
286 }
287 } else {
288 m_X[ i ] = x;
289 m_Y[ j ] = y;
290 }
291 }
292 }
293 }
294
295
296
297 template<>
298 void TwoD_Mapped_Node_Mesh<double>::dump_gnu(std::string filename) const {
299 std::ofstream dump;
300 dump.open(filename.c_str());
301 dump.precision(15);
302 dump.setf(std::ios::showpoint);
303 dump.setf(std::ios::showpos);
304 dump.setf(std::ios::scientific);
305 //
306 for(std::size_t i = 0; i < m_nx; ++i) {
307 for(std::size_t j = 0; j < m_ny; ++j) {
308 dump << m_X[ i ] << " " << m_Y[ j ] << " ";
309 for(std::size_t var = 0; var < m_nv; ++var) {
310 dump << m_vars[(i * m_ny + j) * m_nv + var ] << " ";
311 }
312 dump << "\n";
313 }
314 dump << "\n";
315 }
316 dump.close();
317 }
318
319 template <>
320 void TwoD_Mapped_Node_Mesh<D_complex>::dump_gnu(std::string filename) const {
321 std::ofstream dump;
322 dump.open(filename.c_str());
323 dump.precision(15);
324 dump.setf(std::ios::showpoint);
325 dump.setf(std::ios::showpos);
326 dump.setf(std::ios::scientific);
327 //
328 for(std::size_t i = 0; i < m_nx; ++i) {
329 for(std::size_t j = 0; j < m_ny; ++j) {
330 dump << m_X[ i ] << " " << m_Y[ j ] << " ";
331 for(std::size_t var = 0; var < m_nv; ++var) {
332 dump << real(m_vars[(i * m_ny + j) * m_nv + var ]) << " ";
333 dump << imag(m_vars[(i * m_ny + j) * m_nv + var ]) << " ";
334 }
335 dump << "\n";
336 }
337 dump << "\n";
338 }
339 dump.close();
340 }
341
342 //the templated versions we require are:
343 template class TwoD_Mapped_Node_Mesh<double>
344 ;
346 ;
347
348}
@ U
Definition: BVPKarman.cpp:20
A matrix class that constructs a DENSE matrix as an STL Vector of DenseVectors.
Specification for a templated DenseVector class – a dense, dynamic, vector object.
The collection of CppNoddy exceptions.
A specification for a two dimensional mapped mesh object.
A spec for a collection of utility functions.
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
An exception to indicate that a CppNoddy container has been accessed with index/indices outside the m...
Definition: Exceptions.h:117
A generic runtime exception.
Definition: Exceptions.h:158
A one dimensional mesh utility object.
void set_nodes_vars(const std::size_t node, const DenseVector< _Type > &u)
Set the variables stored at A SPECIFIED node.
A two dimensional (mapped) mesh utility object.
void read(std::string filename, const bool reset=false)
A simple method for reading data from a file.
DenseVector< _Type > get_nodes_vars(const std::size_t nodex, const std::size_t nodey) const
Get the variables stored at A SPECIFIED node – equivalent to mesh(nodex,nodey).
DenseVector< double > & xnodes()
Access the vector of x-nodal positions.
std::pair< double, double > get_comp_step_sizes() const
void init_mapping()
Sometimes a useful mapping is painful to invert analytically.
OneD_Node_Mesh< _Type > get_xsection_at_xnode(const std::size_t nodex) const
Get a cross section of the 2D mesh at a specified (constant) x node.
void set_nodes_vars(const std::size_t nodex, const std::size_t nodey, const DenseVector< _Type > &U)
Set the variables stored at A SPECIFIED node.
std::pair< std::size_t, std::size_t > get_nnodes() const
Get the number of nodes in the two directions of the 2D mesh.
void normalise(const std::size_t &var)
Normalise all data in the mesh based on one variable.
DenseVector< double > & ynodes()
Access the vector of y-nodal positions.
std::size_t get_nvars() const
Get the number of variables that are stored at each node.
void dump_gnu(std::string filename) const
A simple method for dumping data to a file for gnuplot surface plotting.
OneD_Node_Mesh< _Type > get_xsection_at_ynode(const std::size_t nodey) const
Get a cross section of the 2D mesh at a specified (constant) y node.
DenseVector< double > uniform_node_vector(const double &lower, const double &upper, const std::size_t &N)
Return a DENSE vector with the nodal points of a uniform mesh distributed between the upper/lower bou...
Definition: Utility.cpp:113
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...
std::complex< double > D_complex
A complex double precision number using std::complex.
Definition: Types.h:98

© 2012

R.E. Hewitt