You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

156 lines
4.8 KiB

#include <medusa/Medusa_fwd.hpp>
#include <medusa/bits/domains/GeneralFill.hpp>
#include <Eigen/Sparse>
#include <cmath>
/// 2D Wave equation problem on bounded domain.
/// http://e6.ijs.si/medusa/wiki/index.php/Wave_equation
using namespace mm; // NOLINT
using namespace Eigen; // NOLINT
// Helper function calculating linear interpolation/extrapolation y(x) based on
// two data points (x1, y1), (x2, y2) at point x.
double linear(double x1, double y1, double x2, double y2, double x) {
double k = (y2 - y1) / (x2 - x1);
double n = y1 -k*x1;
return k*x + n;
}
int main() {
// parameters
double inner_radius = 0.05;
double outer_radius = 1.0;
int density = 40;
double A = 0.2;
int n = 12; // support size
int m = 3; // monomial basis of second order, i.e. 3 monomials
int fill_seed = 123;
double sigma = 1;
double omega = 128; // frequency of the source
double v = 8; // wave velocity
double time = 0.5; // length of calculation
int t_factor = 500;
double dt = 1e-6; // time step
int t_steps = static_cast<int> (time / dt);
double dx = outer_radius / density;
// Lambda function for setting the density of nodes
auto fill_density = [=](const Vec2d& p) {
double r = p.norm();
double default_value = dx;
double dens = default_value;
double r1 = 15*inner_radius;
double r2 = 0.8*outer_radius;
if (r < r1) dens = linear(inner_radius, 0.8*default_value, r1, default_value, r );
if (r > r2) dens = linear(r2, default_value, outer_radius, 0.8* default_value, r);
return dens;
};
// Create output file
HDF hdf_out("wave_equation_2D.h5", HDF::DESTROY);
// extra boundary labels
int CENTRE = -10;
// Prepare domain
// build circle domain
BallShape<Vec2d> domain({0, 0}, outer_radius);
auto discretization = domain.discretizeBoundaryWithStep(dx);
// build source
BallShape<Vec2d> empty({0, 0}, inner_radius);
auto discretization_empty = empty.discretizeBoundaryWithStep(dx, CENTRE);
// substract the source domain
discretization -= discretization_empty;
GeneralFill<Vec2d> fill;
fill.seed(fill_seed);
discretization.fill(fill, fill_density);
// find support
FindClosest find_support(n);
discretization.findSupport(find_support);
int domain_size = discretization.size();
Range<int> interior = discretization.types() > 0;
Range<int> boundary = discretization.types() < 0;
// Prepare operators and matrix
WLS<Monomials<Vec2d>, GaussianWeight<Vec2d>, ScaleToClosest>
approx(m - 1 , sigma);
auto storage = discretization.computeShapes(approx); // Shape functions are computed.
SparseMatrix<double> M(domain_size, domain_size);
BiCGSTAB<SparseMatrix<double, RowMajor>> solver;
M.reserve(Range<int>(domain_size, n));
VectorXd rhs = VectorXd::Zero(domain_size); // set empty vector for rhs
auto op = storage.implicitOperators(M, rhs); // All nodes, including boundary
VectorXd E0 = VectorXd::Zero(domain_size); // 0-th step
VectorXd E1 = VectorXd::Zero(domain_size); // 1-st step
// Set equation on interior
for (int i : interior) {
-(v*v*dt*dt) * op.lap(i) + op.value(i)= 2*E1(i)-E0(i); // laplace in interior
}
// Set boundary conditions
for (int i : boundary) {
if (discretization.types()[i] == CENTRE) {
op.value(i) = A * std::sin(omega*dt*2);
} else {
op.value(i) = 0.0;
}
}
hdf_out.writeSparseMatrix("M", M);
M.makeCompressed();
solver.compute(M);
// Time stepping
int tt;
int t_save = 0;
hdf_out.writeDouble2DArray("pos", discretization.positions());
hdf_out.openGroup("/step" + std::to_string(t_save));
hdf_out.writeDoubleAttribute("TimeStep", t_save);
hdf_out.writeDoubleAttribute("time", 0.0);
hdf_out.writeDoubleArray("E", E1);
++t_save;
for (tt = 2; tt < t_steps; ++tt) {
// Solve matrix system
VectorXd E2 = solver.solve(rhs);
// Update previous states
E0 = E1;
E1 = E2;
if (tt%(t_factor) == 0) {
// Saving state
hdf_out.openGroup("/step" + std::to_string(t_save));
hdf_out.writeDoubleAttribute("TimeStep", t_save);
std::cout<< "Time step " << t_save << " of " << t_steps/t_factor << "." << std::endl;
++t_save;
hdf_out.writeDoubleArray("E", E2);
hdf_out.writeDoubleAttribute("time", dt * tt);
}
// Update rhs on interior
for (int i : interior) {
rhs(i) = 2*E1(i)-E0(i);
}
// Update rhs on boundary
for (int i : (discretization.types() == CENTRE)) {
rhs(i) = A * std::sin(omega*dt*tt);
}
}
hdf_out.closeFile();
}