diff --git a/src/dg.cc b/src/dg.cc index 559b3447a3a9b3ea801c019164269cbe7b64ee45..23d2a9b00cfb03197f8069c021aa19079090e9b1 100644 --- a/src/dg.cc +++ b/src/dg.cc @@ -67,10 +67,17 @@ int main(int argc, char** argv) const auto q = [](const Coordinate& x) {return x.two_norm();}; //source term const int order = 3; //order of the quadrature rule + + //we use the basis + // phi_elem,0 (x) = indicator(elem); + // phi_elem,i (x) = x[i]*indicator(elem); + //for elem in elements(gridView) and i = 1,...,dim for (const auto& elem : elements(gridView)) { - const auto& geo = elem.geometry(); const int elemIdx = mapper.index(elem); + const auto& geo = elem.geometry(); + const double elemVol = geo.volume(); + //TODO: can be done outside of the loop? const Dune::QuadratureRule<double,dim>& rule = Dune::QuadratureRules<double,dim>::rule(geo.type(),order); @@ -81,60 +88,210 @@ int main(int argc, char** argv) //NOTE: is the volume of the element taken into account automatically? const auto weight = ip.weight(); - //basis function phi_{elem,0}(x) = indicator(elem); + //quadrature for int_elem q*phi_elem,0 dV b[(1 + dim)*elemIdx] += weight * q(qp); + + //quadrature for int_elem q*phi_elem,i dV for (int i = 0; i < dim; i++) { - //basis function phi_{elem,i}(x) = x[i]*indicator(elem); b[(1 + dim)*elemIdx + i + 1] += weight * qp[i] * q(qp); } } for (int i = 0; i < dim; i++) { - //basis function phi_{elem,i}(x) = x[i]*indicator(elem); - A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + i + 1] = - K * geo.volume(); // \int_elem K\nabla\phi_i\cdot\nabla\phi_i dV + //exact evaluation of + // int_elem K*grad(phi_elem,i)*grad(phi_elem,i) dV + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + i + 1] = K * elemVol; } - //NOTE: Is there a neat way to evaluate the jump and average operators? - // (loop over facets?) - //NOTE: jump / average operators disappear as basis function are supported - //on a single element? - //iterate over all intersection with the boundary of elem for (const auto& intersct : intersections(gridView, elem)) { - const auto& outerNormal = intersct.centerUnitOuterNormal(); + const auto& normal = intersct.centerUnitOuterNormal(); const auto& intersctGeo = intersct.geometry(); + const double intersctVol = intersctGeo.volume(); + const auto& intersctCenter = intersctGeo.center(); - const Dune::QuadratureRule<double,dim-1>& rule = - Dune::QuadratureRules<double,dim-1>::rule(intersct.type(),order); + const Dune::QuadratureRule<double,dim-1>& secondOrderRule = + Dune::QuadratureRules<double,dim-1>::rule(intersct.type(), 2); - A[(1 + dim)*elemIdx][(1 + dim)*elemIdx] += mu * intersctGeo.volume(); + //storage for multiply used integral values, + //note that only the lower diagonal and diagonal entries of + //quadraticIntregrals are used + Dune::FieldVector<double, dim> linearIntegrals(0.0); + Dune::FieldMatrix<double, dim, dim> quadraticIntregrals(0.0); - for (const auto& ip : rule) + for (int i = 0; i < dim; i++) { - const auto qp = ip.position(); - const auto weight = ip.weight(); - - //TODO + //use midpoint rule for exact evaluation of + // int_intersct x_i ds + linearIntegrals[i] = mu * intersctVol * 0.5 * intersctCenter[i]; + + for (int j = 0; j <= i; j++) + { + //use second order quadrature rule for exact evaluation of + // int_intersct x_i*x_j ds + //NOTE: use Simpson's rule instead manually? + for (const auto& ip : secondOrderRule) + { + const auto& qp = ip.position(); + quadraticIntregrals[i][j] += //NOTE: volume necessary? + ip.weight() * qp[i] * qp[j] * intersctVol; + } + } } - + //exact evaluation of + // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,0) ds + A[(1 + dim)*elemIdx][(1 + dim)*elemIdx] += mu * intersctGeo.volume(); if (intersct.neighbor()) //intersct has neighboring element { //index of the neighboring element - const int neighborIndex = mapper.index(intersct.outside()); - - // A[][] = 0.5* ...; //note that interior facets are considered twice - - //TODO + const int neighborIdx = mapper.index(intersct.outside()); + + for (int i = 0; i < dim; i++) + { //we use the relations + // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,i) ds + // = mu * int_intersct x_i ds + //and + // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,0) ds + // = 0.5 * K * normal[i] * vol(intersct) + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx] = + mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol; + + //stiffness matrix A is symmetric + A[(1 + dim)*elemIdx][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx]; + + for (int j = 0; j <= i; j++) + { + //we use the relations + // int_intersct mu*jump(phi_elem,i)*jump(phi_elem,j) ds + // = mu * int_intersct x_i*x_j ds + //and + // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,j) ds + // = 0.5 * K * normal[i] * int_intersct x_j ds + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + j + 1] = + mu * quadraticIntregrals[i][j] - 0.5 * K * (normal[i] * + linearIntegrals[j] + normal[j] * linearIntegrals[i]); + + //stiffness matrix A is symmetric + A[(1 + dim)*elemIdx + j + 1][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + j + 1]; + } + } + + if (neighborIdx > elemIdx) + { //make sure that each facet is considered only once + continue; + } + + //exact evaluation of + // int_intersct mu*jump(phi_elem,0)*jump(phi_neighbor,0) ds + A[(1 + dim)*elemIdx][(1 + dim)*neighborIdx] = -mu * intersctVol; + + //stiffness matrix A is symmetric + A[(1 + dim)*neighborIdx][(1 + dim)*elemIdx] = + A[(1 + dim)*elemIdx][(1 + dim)*neighborIdx]; + + for (int i = 0; i < dim; i++) + { + //we use the relations + // int_intersct mu*jump(phi_elem,i)*jump(phi_neighbor,0) ds + // = -mu*int_intersct x_i ds + //and + // int_intersct avg(K*grad(phi_neighbor,i))*jump(phi_elem,0) ds + // = 0.5 * K * normal[i] * vol(intersct) + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*neighborIdx] = + -mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol; + + //we use the relations + // int_intersct mu*jump(phi_elem,0)*jump(phi_neighbor,i) ds + // = -mu*int_intersct x_i ds + //and + // int_intersct avg(K*grad(phi_neighbor,i))*jump(phi_elem,0) ds + // = 0.5 * K * normal[i] * vol(intersct) + A[(1 + dim)*elemIdx][(1 + dim)*neighborIdx + i + 1] = + -mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol; + + //stiffness matrix A is symmetric + A[(1 + dim)*neighborIdx][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*neighborIdx]; + A[(1 + dim)*neighborIdx + i + 1][(1 + dim)*elemIdx] = + A[(1 + dim)*elemIdx][(1 + dim)*neighborIdx + i + 1]; + + for (int j = 0; j <= i; j++) + { + //we use the relations + // int_intersct mu*jump(phi_elem,i)*jump(phi_neighbor,j) ds + // = -mu*int_intersct x_i*x_j ds + //and + // int_intersct avg(K*grad(phi_neighbor,j))*jump(phi_elem,i) ds + // = 0.5 * K * normal[j] * int_intersct x_i ds + //as well as + // int_intersct avg(K*grad(phi_elem,i))*jump(phi_neighbor,j) ds + // = -0.5 * K * normal[i] * int_intersct x_j ds + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*neighborIdx + j + 1] = + -mu * quadraticIntregrals[i][j] + - 0.5 * K * (normal[j] * linearIntegrals[i] + - normal[i] * linearIntegrals[j]); + + // int_intersct mu*jump(phi_elem,j)*jump(phi_neighbor,i) ds + // = -mu*int_intersct x_i*x_j ds + //and + // int_intersct avg(K*grad(phi_neighbor,i))*jump(phi_elem,j) ds + // = 0.5 * K * normal[i] * int_intersct x_j ds + //as well as + // int_intersct avg(K*grad(phi_elem,j))*jump(phi_neighbor,i) ds + // = -0.5 * K * normal[j] * int_intersct x_i ds + A[(1 + dim)*elemIdx + j + 1][(1 + dim)*neighborIdx + i + 1] = + -mu * quadraticIntregrals[i][j] + - 0.5 * K * (normal[i] * linearIntegrals[j] + - normal[j] * linearIntegrals[i]); + + //stiffness matrix A is symmetric + A[(1 + dim)*neighborIdx + j + 1][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*neighborIdx + j + 1]; + A[(1 + dim)*neighborIdx + i + 1][(1 + dim)*elemIdx + j + 1] = + A[(1 + dim)*elemIdx + j + 1][(1 + dim)*neighborIdx + i + 1]; + } + } } - else //boundary element + else //boundary facet { - //TODO + for (int i = 0; i < dim; i++) + { //we use the relations + // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,i) ds + // = mu * int_intersct x_i ds + //and for boundary facets + // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,0) ds + // = K * normal[i] * vol(intersct) + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx] = + mu * linearIntegrals[i] - K * normal[i] * intersctVol; + + //stiffness matrix A is symmetric + A[(1 + dim)*elemIdx][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx]; + + for (int j = 0; j <= i; j++) + { + //we use the relations + // int_intersct mu*jump(phi_elem,i)*jump(phi_elem,j) ds + // = mu * int_intersct x_i*x_j ds + //and for boundary facets + // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,j) ds + // = 0.5 * K * normal[i] * int_intersct x_j ds + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + j + 1] = + mu * quadraticIntregrals[i][j] - K * (normal[i] * + linearIntegrals[j] + normal[j] * linearIntegrals[i]); + + //stiffness matrix A is symmetric + A[(1 + dim)*elemIdx + j + 1][(1 + dim)*elemIdx + i + 1] = + A[(1 + dim)*elemIdx + i + 1][(1 + dim)*elemIdx + j + 1]; + } + } } } }