-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpoisson_test_problem.h
187 lines (150 loc) · 5.74 KB
/
poisson_test_problem.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
#ifndef OOMPH_POISSON_TEST_PROBLEM_H
#define OOMPH_POISSON_TEST_PROBLEM_H
/*
description of file goes here
*/
#include "./generic_poisson_problem.h"
// Mesh for running Poisson tests
#include "meshes/simple_rectangular_quadmesh.h"
namespace oomph
{
namespace Factories
{
template<class ELEMENT>
Mesh* poisson_surface_mesh_factory(Mesh* bulk_mesh_pt,
const Vector<unsigned> &boundaries)
{
Mesh* flux_mesh_pt = new Mesh;
// Loop over boundaries which need a surface mesh
for(unsigned i=0, ni=boundaries.size(); i<ni; i++)
{
// Get boundary number
unsigned b = boundaries[i];
// Loop over the bulk elements adjacent to boundary b
for(unsigned e=0, ne=bulk_mesh_pt->nboundary_element(b); e<ne; e++)
{
// Get pointer to the bulk element that is adjacent to boundary b
FiniteElement* bulk_elem_pt = bulk_mesh_pt->boundary_element_pt(b, e);
// Get the index of the face of the bulk element e on bondary b
int face_index = bulk_mesh_pt->face_index_at_boundary(b, e);
// Build the corresponding prescribed-flux element
ELEMENT* flux_element_pt = new ELEMENT(bulk_elem_pt, face_index);
// Add the prescribed-flux element to the surface mesh
flux_mesh_pt->add_element_pt(flux_element_pt);
}
}
return flux_mesh_pt;
}
}
// =================================================================
/// Functions for Poisson tests
// =================================================================
namespace TanhSolnForPoisson
{
/// Parameter for steepness of "step"
double Alpha=1.0;
/// Parameter for angle Phi of "step"
double TanPhi=0.0;
/// Exact solution as a Vector
void get_exact_u(const Vector<double>& x, Vector<double>& u)
{
u[0] = tanh(1.0-Alpha*(TanPhi*x[0]-x[1]));
}
/// Source function required to make the solution above an exact solution
void source_function(const Vector<double>& x, double& source)
{
source = 2.0*tanh(-1.0+Alpha*(TanPhi*x[0]-x[1]))*
(1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*
Alpha*Alpha*TanPhi*TanPhi+2.0*tanh(-1.0+Alpha*(TanPhi*x[0]-x[1]))*
(1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*Alpha;
}
/// Flux required by the exact solution on a boundary on which x is fixed
void prescribed_flux_on_fixed_x_boundary(const Vector<double>& x,
double& flux)
{
//The outer unit normal to the boundary is (1,0)
double N[2] = {1.0, 0.0};
//The flux in terms of the normal is
flux =
-(1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*TanPhi*N[0]+(
1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*N[1];
}
} // end of namespace
// =================================================================
/// Basic Poisson problem for tests
// =================================================================
class GenericPoissonForTests : public GenericPoissonProblem
{
public:
/// Constructor - build a Poisson problem with some of each type of
/// boundary and preset source function.
GenericPoissonForTests()
{
// Make a mesh
Mesh* Bulk_mesh_pt =
new SimpleRectangularQuadMesh<QTFPoissonElement<2,3> >(4,4,1.0,2.0);
// Set the factory function used to create the surface mesh for
// Neumman boundaries.
set_flux_mesh_factory(&Factories::
poisson_surface_mesh_factory<QTFPoissonFluxElement<2,3> >);
// Assign b.c.s
for(unsigned b=0; b<Bulk_mesh_pt->nboundary(); b++)
{
if(b != 1)
{
this->add_dirichlet_boundary(Bulk_mesh_pt, b,
&TanhSolnForPoisson::get_exact_u);
}
}
add_neumann_boundary(Bulk_mesh_pt, 1,
&TanhSolnForPoisson::prescribed_flux_on_fixed_x_boundary);
// Assign function pointers
this->set_source_fct_pt(&TanhSolnForPoisson::source_function);
this->exact_solution_fct_pt() = &TanhSolnForPoisson::get_exact_u;
// Finish building the problem
Vector<Mesh*> mesh_pts;
mesh_pts.push_back(Bulk_mesh_pt);
this->build(mesh_pts);
}
int run_test()
{
// Self test
if (self_test() != 0)
{
std::cerr << "Self test failed" << std::endl;
return 5;
}
// Set the orientation of the "step" to 45 degrees
TanhSolnForPoisson::TanPhi=1.0;
// Initial value for the steepness of the "step"
TanhSolnForPoisson::Alpha=1.0;
// List of roughly the error norms allowed for different alpha values
// (based on previous runs).
Vector<double> Allowed_error;
Allowed_error.push_back(0.01);
Allowed_error.push_back(0.05);
Allowed_error.push_back(0.1);
Allowed_error.push_back(0.5);
// Do a couple of solutions for different forcing functions
unsigned nstep=4;
for (unsigned istep=0;istep<nstep;istep++)
{
// Increase the steepness of the step:
TanhSolnForPoisson::Alpha+=2.0;
// Solve the problem
newton_solve();
double error_norm = get_error_norm();
if(error_norm > Allowed_error[istep])
{
std::cerr << "Generic poisson test FAILED: error norm = "
<< error_norm
<< " is too large."
<< std::endl;
return 1;
}
}
return 0;
}
};
}
#endif