SyFi  0.3
BrezziDouglasMarini.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator