SyFi
0.3
|
00001 // Copyright (C) 2006-2009 Kent-Andre Mardal and Simula Research Laboratory 00002 // 00003 // This file is part of SyFi. 00004 // 00005 // SyFi is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 2 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // SyFi is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with SyFi. If not, see <http://www.gnu.org/licenses/>. 00017 00018 #include "BrezziDouglasMarini.h" 00019 #include <fstream> 00020 00021 #include "tools.h" 00022 00023 using std::cout; 00024 using std::endl; 00025 using std::string; 00026 00027 namespace SyFi 00028 { 00029 00030 BrezziDouglasMarini:: BrezziDouglasMarini() : StandardFE() 00031 { 00032 description = "BrezziDouglasMarini"; 00033 } 00034 00035 BrezziDouglasMarini:: BrezziDouglasMarini(Polygon& p, int order, bool pointwise_) : StandardFE(p, order) 00036 { 00037 pointwise = pointwise_; 00038 compute_basis_functions(); 00039 } 00040 00041 void BrezziDouglasMarini:: compute_basis_functions() 00042 { 00043 00044 if ( order < 1 ) 00045 { 00046 throw(std::logic_error("Brezzi-Douglas-Marini elements must be of order 1 or higher.")); 00047 } 00048 00049 if ( p == NULL ) 00050 { 00051 throw(std::logic_error("You need to set a polygon before the basisfunctions can be computed")); 00052 } 00053 00054 GiNaC::ex nsymb = GiNaC::symbol("n"); 00055 if (pointwise) 00056 { 00057 00058 if ( p->str().find("ReferenceLine") != string::npos ) 00059 { 00060 00061 cout <<"Can not define the Brezzi-Douglas-Marini element on a line"<<endl; 00062 00063 } 00064 00065 if ( p->str().find("ReferenceTetrahedron") != string::npos ) 00066 { 00067 00068 cout <<"Can not define the Brezzi-Douglas-Marini element on a tetrahedron, see Nedelec2Hdiv"<<endl; 00069 00070 } 00071 else if ( p->str().find("Triangle") != string::npos ) 00072 { 00073 00074 description = istr("BrezziDouglasMarini_", order) + "_2D"; 00075 00076 Triangle& triangle = (Triangle&)(*p); 00077 GiNaC::lst equations; 00078 GiNaC::lst variables; 00079 GiNaC::lst polynom_space = bernsteinv(2,order, triangle, "b"); 00080 GiNaC::ex pspace = polynom_space.op(0); 00081 00082 variables = collapse(GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1))); 00083 00084 GiNaC::symbol t("t"); 00085 GiNaC::ex dofi; 00086 // dofs related to edges 00087 for (int i=0; i< 3; i++) 00088 { 00089 Line line = triangle.line(i); 00090 GiNaC::lst normal_vec = normal(triangle, i); 00091 GiNaC::ex Vn = inner(pspace, normal_vec); 00092 GiNaC::lst points = interior_coordinates(line, order); 00093 00094 GiNaC::ex point; 00095 for (unsigned int j=0; j< points.nops(); j++) 00096 { 00097 point = points.op(j); 00098 dofi = Vn.subs(x == point.op(0)).subs(y == point.op(1)); 00099 GiNaC::ex eq = dofi == GiNaC::numeric(0); 00100 equations.append(eq); 00101 dofs.insert(dofs.end(), GiNaC::lst(point,nsymb)); 00102 } 00103 } 00104 00105 // std::cout <<"no variables "<<variables.nops()<<std::endl; 00106 // std::cout <<"no equations "<<equations.nops()<<std::endl; 00107 00108 // invert the matrix: 00109 // GiNaC has a bit strange way to invert a matrix. 00110 // It solves the system AA^{-1} = Id. 00111 // It seems that this way is the only way to do 00112 // properly with the solve_algo::gauss flag. 00113 // 00114 GiNaC::matrix b; GiNaC::matrix A; 00115 matrix_from_equations(equations, variables, A, b); 00116 00117 unsigned int ncols = A.cols(); 00118 GiNaC::matrix vars_sq(ncols, ncols); 00119 00120 // matrix of symbols 00121 for (unsigned r=0; r<ncols; ++r) 00122 for (unsigned c=0; c<ncols; ++c) 00123 vars_sq(r, c) = GiNaC::symbol(); 00124 00125 GiNaC::matrix id(ncols, ncols); 00126 00127 // identity 00128 const GiNaC::ex _ex1(1); 00129 for (unsigned i=0; i<ncols; ++i) 00130 id(i, i) = _ex1; 00131 00132 // invert the matrix 00133 GiNaC::matrix m_inv(ncols, ncols); 00134 m_inv = A.solve(vars_sq, id, GiNaC::solve_algo::gauss); 00135 00136 for (unsigned int i=0; i<dofs.size(); i++) 00137 { 00138 b.let_op(i) = GiNaC::numeric(1); 00139 GiNaC::ex xx = m_inv.mul(GiNaC::ex_to<GiNaC::matrix>(b)); 00140 00141 GiNaC::lst subs; 00142 for (unsigned int ii=0; ii<xx.nops(); ii++) 00143 { 00144 subs.append(variables.op(ii) == xx.op(ii)); 00145 } 00146 GiNaC::ex Nj1 = pspace.op(0).subs(subs); 00147 GiNaC::ex Nj2 = pspace.op(1).subs(subs); 00148 Ns.insert(Ns.end(), GiNaC::matrix(2,1,GiNaC::lst(Nj1,Nj2))); 00149 b.let_op(i) = GiNaC::numeric(0); 00150 } 00151 } 00152 } 00153 00154 } 00155 00156 } // namespace SyFi