-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodal_quadrature.h
311 lines (239 loc) · 7.82 KB
/
nodal_quadrature.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
#ifndef OOMPH_NODAL_QUADRATURE_H
#define OOMPH_NODAL_QUADRATURE_H
#include <memory>
#include "../../src/generic/Vector.h"
#include "../../src/generic/integral.h"
#include "../../src/generic/elements.h"
#include "oomph_factories.h"
namespace oomph
{
/// Class for nodal quadrature in micromagnetics, as defined in
/// e.g. Cimrak2008. Essentially we just use nodes as knots and \int
/// shape(x) dx as weights. This allows some nice conservation properties.
class NodalQuadrature : public Integral
{
protected:
/// Storage for pointer to the element we are integrating over
const FiniteElement* Ele_pt;
/// Storage for weight values
Vector<double> Weight;
public:
/// Dummy constructor
NodalQuadrature()
{
Ele_pt = 0;
}
/// Real constructor
NodalQuadrature(const FiniteElement* ele_pt)
{
Ele_pt = ele_pt;
build();
}
/// Actually set up the integration scheme
virtual void build()
{
// Construct integration scheme for integration of shape
// function. Use factory so that we don't have to hard code (or
// template by) the dimension/shape of the elements. Have to store in
// pointer to use factory, use smart ptr so that it is deleted
// automatically.
std::auto_ptr<Integral> int_pt
(Factories::gauss_integration_factory(ele_pt()->dim(),
ele_pt()->nnode_1d(),
ele_pt()->element_geometry()));
// Get constants
const unsigned nnode = ele_pt()->nnode();
const unsigned dim = ele_pt()->dim();
const unsigned nipt = int_pt->nweight();
// Initialise storage for weights
Weight.assign(nnode, 0);
// Integrate each shape function over the element and store in
// Weight. Loops reordered for efficiency.
for(unsigned i=0; i<nipt; i++)
{
// Get integration point information
Vector<double> s(dim);
for(unsigned j=0; j<dim; j++)
{s[j] = int_pt->knot(i, j);}
const double w = int_pt->weight(i);
// Jacobian of transformation at integration point
const double J = J_eulerian(s);
// Shape function values at integration point
Shape shape(nnode);
ele_pt()->shape(s, shape);
// Add contribution for each node/shape function
for(unsigned j=0; j<nnode; j++)
{
Weight[j] += w * J * shape(j);
}
}
}
/// Should the elemental jacobian be 1 for this quadrature?
virtual bool unit_jacobian() const
{
return false;
}
/// Get Jacobian of transformation at point s (separate function so
/// that it can be overloaded by other nodal quadrature schemes).
virtual double J_eulerian(const Vector<double>& s) const
{
return ele_pt()->J_eulerian(s);
}
/// Get ele_pt, with paranoid check
const FiniteElement* ele_pt() const
{
#ifdef PARANOID
if(Ele_pt == 0)
{
std::string err = "Element pointer not set.";
throw OomphLibError(err, OOMPH_CURRENT_FUNCTION,
OOMPH_EXCEPTION_LOCATION);
}
#endif
return Ele_pt;
}
/// Set ele_pt
void set_ele_pt(const FiniteElement* ele_pt)
{
Ele_pt = ele_pt;
}
/// Return number of integration points
unsigned nweight() const {return ele_pt()->nnode();}
/// Return jth s-coordinate of ith node/integration point.
double knot(const unsigned &i, const unsigned &j) const
{
// This is dumb but it's the only way I can find to get the local
// coordinate of a node.
return knot(i)[j];
}
/// Return local coordinates of i-th intergration point.
Vector<double> knot(const unsigned &i) const
{
Vector<double> s;
ele_pt()->local_coordinate_of_node(i, s);
return s;
}
/// Return weight of i-th node (= integral of shape dx)
double weight(const unsigned &i) const {return Weight[i];}
};
/// Class to handle ??ds
class RescaledNodalQuadrature : public NodalQuadrature
{
public:
/// Constructor
RescaledNodalQuadrature() {}
/// Virtual destructor
virtual ~RescaledNodalQuadrature() {}
/// Real constructor
RescaledNodalQuadrature(const FiniteElement* ele_pt,
const double& mean_element_volume)
{
Ele_pt = ele_pt;
Mean_element_volume = mean_element_volume;
build();
}
void build()
{
// Build as normal
NodalQuadrature::build();
// Rescale by mean element volume
const unsigned ni = Weight.size();
for(unsigned i=0; i<ni; i++)
{
Weight[i] /= Mean_element_volume;
}
}
protected:
double Mean_element_volume;
private:
/// Broken copy constructor
RescaledNodalQuadrature(const RescaledNodalQuadrature& dummy)
{BrokenCopy::broken_copy("RescaledNodalQuadrature");}
/// Broken assignment operator
void operator=(const RescaledNodalQuadrature& dummy)
{BrokenCopy::broken_assign("RescaledNodalQuadrature");}
};
/// As nodal quadrature but do the weight calculation on a standard
/// element (local coordinates) without mapping back to global. This is
/// done by setting the Jacobian of the transformation (used for the
/// weight integration only) to 1.
class LocalNodalQuadrature : public NodalQuadrature
{
public:
/// Constructor
LocalNodalQuadrature() {}
/// Virtual destructor
virtual ~LocalNodalQuadrature() {}
/// Real constructor
LocalNodalQuadrature(const FiniteElement* ele_pt)
{
Ele_pt = ele_pt;
build();
}
virtual double J_eulerian(const Vector<double>& s) const
{
return 1;
}
private:
/// Broken copy constructor
LocalNodalQuadrature(const LocalNodalQuadrature& dummy)
{BrokenCopy::broken_copy("LocalNodalQuadrature");}
/// Broken assignment operator
void operator=(const LocalNodalQuadrature& dummy)
{BrokenCopy::broken_assign("LocalNodalQuadrature");}
};
/// As nodal quadrature but do everything on the global level. Not sure
/// if this works...
class GlobalNodalQuadrature : public NodalQuadrature
{
public:
/// Constructor
GlobalNodalQuadrature() {}
/// Virtual destructor
virtual ~GlobalNodalQuadrature() {}
/// Real constructor
GlobalNodalQuadrature(const FiniteElement* ele_pt)
{
Ele_pt = ele_pt;
build();
}
/// Should the elemental jacobian be 1 for this quadrature?
virtual bool unit_jacobian() const
{
return true;
}
private:
/// Broken copy constructor
GlobalNodalQuadrature(const GlobalNodalQuadrature& dummy)
{BrokenCopy::broken_copy("GlobalNodalQuadrature");}
/// Broken assignment operator
void operator=(const GlobalNodalQuadrature& dummy)
{BrokenCopy::broken_assign("GlobalNodalQuadrature");}
};
/// Nodal quadrature with all weights set to 1, should work better with
/// integration on standard elements.
class UnitWeightNodalQuadrature : public NodalQuadrature
{
public:
/// Constructor
UnitWeightNodalQuadrature() {}
/// Virtual destructor
virtual ~UnitWeightNodalQuadrature() {}
/// Real constructor
UnitWeightNodalQuadrature(const FiniteElement* ele_pt)
: NodalQuadrature(ele_pt) {}
virtual void build()
{
// Set all weights to 1
Weight.assign(ele_pt()->nnode(), 1);
}
private:
/// Broken copy constructor
UnitWeightNodalQuadrature(const UnitWeightNodalQuadrature& dummy)
{BrokenCopy::broken_copy("UnitWeightNodalQuadrature");}
/// Broken assignment operator
void operator=(const UnitWeightNodalQuadrature& dummy)
{BrokenCopy::broken_assign("UnitWeightNodalQuadrature");}
};
} // End of oomph namespace
#endif