SyFi  0.3
Nedelec2Hdiv.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 "Nedelec2Hdiv.h"
00019 #include <fstream>
00020 #include "tools.h"
00021 
00022 using std::cout;
00023 using std::endl;
00024 using std::string;
00025 
00026 using GiNaC::exmap;
00027 using namespace GiNaC;
00028 
00029 namespace SyFi
00030 {
00031 
00032         Nedelec2Hdiv:: Nedelec2Hdiv() : StandardFE()
00033         {
00034                 description = "Nedelec2Hdiv";
00035         }
00036 
00037         Nedelec2Hdiv:: Nedelec2Hdiv(Polygon& p, unsigned int order) : StandardFE(p, order)
00038         {
00039                 compute_basis_functions();
00040         }
00041 
00042         void Nedelec2Hdiv:: compute_basis_functions()
00043         {
00044 
00045                 // remove previously computed basis functions and dofs
00046                 Ns.clear();
00047                 dofs.clear();
00048 
00049                 if ( order < 1 )
00050                 {
00051                         throw(std::logic_error("Nedelec2Hdiv elements must be of order 1 or higher."));
00052                 }
00053 
00054                 if ( p == NULL )
00055                 {
00056                         throw(std::logic_error("You need to set a polygon before the basisfunctions can be computed"));
00057                 }
00058 
00059                 if ( p->str().find("Line") != string::npos )
00060                 {
00061 
00062                         cout <<"Can not define the Nedelec2Hdiv element on a line"<<endl;
00063 
00064                 }
00065                 else if ( p->str().find("Triangle") != string::npos )
00066                 {
00067 
00068                         cout <<"Can not define the Nedelec2Hdiv element on a Triangle "<<endl;
00069 
00070                 }
00071                 else if ( p->str().find("Tetrahedron") != string::npos )
00072                 {
00073 
00074                         description = istr( "Nedelec2Hdiv_", order) + "_3D";
00075 
00076                         int k = order;
00077 
00078                         Tetrahedron& tetrahedron= (Tetrahedron&)(*p);
00079                         GiNaC::lst equations;
00080                         GiNaC::lst variables;
00081 
00082                         // create p
00083                         GiNaC::ex P_k = bernsteinv(3,k, tetrahedron, "b");
00084                         GiNaC::ex P_k_x = P_k.op(0).op(0);
00085                         GiNaC::ex P_k_y = P_k.op(0).op(1);
00086                         GiNaC::ex P_k_z = P_k.op(0).op(2);
00087 
00088                         GiNaC::lst pspace = GiNaC::lst( P_k_x, P_k_y, P_k_z);
00089 
00090                         variables = collapse(GiNaC::ex_to<GiNaC::lst>(P_k.op(1)));
00091 
00092                         int counter = 0;
00093                         GiNaC::symbol t("t");
00094                         GiNaC::ex dofi;
00095                         GiNaC::ex bernstein_pol;
00096 
00097                         // dofs related to edges
00098                         for (int i=0; i< 4; i++)
00099                         {
00100                                 Triangle triangle = tetrahedron.triangle(i);
00101                                 GiNaC::lst normal_vec = normal(tetrahedron, i);
00102                                 bernstein_pol = bernstein(order, triangle, istr("a",i));
00103                                 GiNaC::ex basis_space = bernstein_pol.op(2);
00104                                 GiNaC::ex pspace_n = inner(pspace, normal_vec);
00105 
00106                                 GiNaC::ex basis;
00107                                 for (unsigned int j=0; j< basis_space.nops(); j++)
00108                                 {
00109                                         counter++;
00110                                         basis = basis_space.op(j);
00111                                         GiNaC::ex integrand = pspace_n*basis;
00112                                         dofi =  triangle.integrate(integrand);
00113                                         GiNaC::ex eq = dofi == GiNaC::numeric(0);
00114                                         equations.append(eq);
00115                                         //        GiNaC::lst d = GiNaC::lst(triangle.integrate(x*basis),
00116                                         //                                  triangle.integrate(y*basis),
00117                                         //                                  triangle.integrate(z*basis));
00118                                         GiNaC::lst d = GiNaC::lst(GiNaC::lst(triangle.vertex(0),
00119                                                 triangle.vertex(1),
00120                                                 triangle.vertex(2)),j);
00121 
00122                                         dofs.insert(dofs.end(), d);
00123 
00124                                         GiNaC::ex u = GiNaC::matrix(3,1,GiNaC::lst(GiNaC::symbol("v[0]"), GiNaC::symbol("v[1]"), GiNaC::symbol("v[2]")));
00125                                         GiNaC::ex n = GiNaC::matrix(3,1,GiNaC::lst(GiNaC::symbol("normal_vec[0]"), GiNaC::symbol("normal_vec[1]"), GiNaC::symbol("normal_vec[2]")));
00126                                         dof_repr.append(GiNaC::lst(inner(u,n)*basis.subs( x == GiNaC::symbol("xi[0]"))
00127                                                 .subs( y == GiNaC::symbol("xi[1]"))
00128                                                 .subs( z == GiNaC::symbol("xi[2]")), d));
00129 
00130                                 }
00131                         }
00132 
00133                         // dofs related to tetrahedron
00134 
00135                         int tetradofs = 0;
00136                         if ( order > 1 )
00137                         {
00138                                 GiNaC::ex bernstein_pol = bernsteinv(3,k-2, tetrahedron, istr("c", 0));
00139                                 GiNaC::ex basis_space = bernstein_pol.op(2);
00140                                 GiNaC::ex basis;
00141                                 tetradofs += basis_space.nops();
00142                                 for (unsigned int j=0; j<basis_space.nops(); j++)
00143                                 {
00144                                         basis = basis_space.op(j);
00145                                         GiNaC::ex integrand = inner(pspace,basis);
00146                                         dofi = tetrahedron.integrate(integrand);
00147                                         GiNaC::ex eq = dofi == GiNaC::numeric(0);
00148                                         equations.append(eq);
00149 
00150                                         //        GiNaC::lst d = GiNaC::lst(tetrahedron.integrate(x*basis.op(0)),
00151                                         //                                  tetrahedron.integrate(y*basis.op(1)),
00152                                         //                                  tetrahedron.integrate(z*basis.op(2)));
00153 
00154                                         GiNaC::lst d = GiNaC::lst(tetrahedron.vertex(0),
00155                                                 tetrahedron.vertex(1),
00156                                                 tetrahedron.vertex(2),
00157                                                 tetrahedron.vertex(3),j);
00158 
00159                                         dofs.insert(dofs.end(), d);
00160 
00161                                 }
00162                         }
00163 
00164                         // Construction of S_k
00165                         //
00166                         //
00167                         if ( order >= 1 )
00168                         {
00169                                 GiNaC::ex H_k = homogenous_polv(3,k-1, 3, "a");
00170                                 GiNaC::ex H_k_x = H_k.op(0).op(0);
00171                                 GiNaC::ex H_k_y = H_k.op(0).op(1);
00172                                 GiNaC::ex H_k_z = H_k.op(0).op(2);
00173 
00174                                 GiNaC::lst H_variables = collapse(GiNaC::ex_to<GiNaC::lst>(H_k.op(1)));
00175 
00176                                 // Equations that make sure that r*x = 0
00177 
00178                                 GiNaC::ex rx = (H_k_x*x + H_k_y*y + H_k_z*z).expand();
00179                                 exmap pol_map = pol2basisandcoeff(rx);
00180                                 exmap::iterator iter;
00181                                 GiNaC::lst S_k;
00182                                 GiNaC::lst S_k_equations;
00183 
00184                                 GiNaC::lst null_eqs;
00185                                 for (unsigned int i=0; i<H_variables.nops(); i++)
00186                                 {
00187                                         null_eqs.append( H_variables.op(i) == 0);
00188                                 }
00189 
00190                                 for (iter = pol_map.begin(); iter != pol_map.end(); iter++)
00191                                 {
00192                                         GiNaC::ex coeff = (*iter).second;
00193                                         GiNaC::ex basis;
00194                                         if (coeff.nops() > 1  )
00195                                         {
00196                                                 if (coeff.nops()  == 2)
00197                                                 {
00198                                                         S_k_equations.remove_all();
00199                                                         S_k_equations.append(coeff.op(0) == GiNaC::numeric(1));
00200                                                         S_k_equations.append(coeff.op(1) == GiNaC::numeric(-1));
00201                                                         basis = H_k.op(0).subs(S_k_equations).subs(null_eqs);;
00202                                                         S_k.append(basis);
00203                                                 }
00204                                                 else if ( coeff.nops() == 3 )
00205                                                 {
00206                                                         // 2 basis functions is added
00207                                                         // The first:
00208 
00209                                                         S_k_equations.remove_all();
00210                                                         S_k_equations.append(coeff.op(0) == GiNaC::numeric(-1,2));
00211                                                         S_k_equations.append(coeff.op(1) == GiNaC::numeric(1));
00212                                                         S_k_equations.append(coeff.op(2) == GiNaC::numeric(-1,2));
00213                                                         basis = H_k.op(0).subs(S_k_equations).subs(null_eqs);;
00214                                                         S_k.append(basis);
00215 
00216                                                         // The second:
00217                                                         S_k_equations.remove_all();
00218                                                         S_k_equations.append(coeff.op(0) == GiNaC::numeric(-1,2));
00219                                                         S_k_equations.append(coeff.op(1) == GiNaC::numeric(-1,2));
00220                                                         S_k_equations.append(coeff.op(2) == GiNaC::numeric(1));
00221                                                         basis = H_k.op(0).subs(S_k_equations).subs(null_eqs);;
00222                                                         S_k.append(basis);
00223                                                 }
00224                                         }
00225                                 }
00226 
00227                                 std::cout <<"len (S_k) " <<S_k.nops()<<std::endl;
00228 
00229                                 // dofs related to tetrahedron
00230                                 if ( order >= 1 )
00231                                 {
00232                                         GiNaC::ex basis;
00233                                         for (unsigned int j=0; j<S_k.nops(); j++)
00234                                         {
00235                                                 basis = S_k.op(j);
00236                                                 GiNaC::ex integrand = inner(pspace,basis);
00237                                                 dofi = tetrahedron.integrate(integrand);
00238                                                 GiNaC::ex eq = dofi == GiNaC::numeric(0);
00239                                                 equations.append(eq);
00240 
00241                                                 GiNaC::lst d = GiNaC::lst(tetrahedron.vertex(0),
00242                                                         tetrahedron.vertex(1),
00243                                                         tetrahedron.vertex(2),
00244                                                         tetrahedron.vertex(3), tetradofs + j);
00245 
00246                                                 dofs.insert(dofs.end(), d);
00247 
00248                                         }
00249                                 }
00250                         }
00251 
00252                         // invert the matrix:
00253                         // GiNaC has a bit strange way to invert a matrix.
00254                         // It solves the system AA^{-1} = Id.
00255                         // It seems that this way is the only way to do
00256                         // properly with the solve_algo::gauss flag.
00257                         //
00258                         GiNaC::matrix b; GiNaC::matrix A;
00259                         matrix_from_equations(equations, variables, A, b);
00260 
00261                         unsigned int ncols = A.cols();
00262                         GiNaC::matrix vars_sq(ncols, ncols);
00263 
00264                         // matrix of symbols
00265                         for (unsigned r=0; r<ncols; ++r)
00266                                 for (unsigned c=0; c<ncols; ++c)
00267                                         vars_sq(r, c) = GiNaC::symbol();
00268 
00269                         GiNaC::matrix id(ncols, ncols);
00270 
00271                         // identity
00272                         const GiNaC::ex _ex1(1);
00273                         for (unsigned i=0; i<ncols; ++i)
00274                                 id(i, i) = _ex1;
00275 
00276                         // invert the matrix
00277                         GiNaC::matrix m_inv(ncols, ncols);
00278                         m_inv = A.solve(vars_sq, id, GiNaC::solve_algo::gauss);
00279 
00280                         for (unsigned int i=0; i<dofs.size(); i++)
00281                         {
00282                                 b.let_op(i) = GiNaC::numeric(1);
00283                                 GiNaC::ex xx = m_inv.mul(GiNaC::ex_to<GiNaC::matrix>(b));
00284 
00285                                 GiNaC::lst subs;
00286                                 for (unsigned int ii=0; ii<xx.nops(); ii++)
00287                                 {
00288                                         subs.append(variables.op(ii) == xx.op(ii));
00289                                 }
00290                                 GiNaC::ex Nj1 = pspace.op(0).subs(subs);
00291                                 GiNaC::ex Nj2 = pspace.op(1).subs(subs);
00292                                 GiNaC::ex Nj3 = pspace.op(2).subs(subs);
00293                                 Ns.insert(Ns.end(), GiNaC::matrix(3,1,GiNaC::lst(Nj1,Nj2,Nj3)));
00294                                 b.let_op(i) = GiNaC::numeric(0);
00295                         }
00296                 }
00297         }
00298 
00299 }                                                                // namespace SyFi
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator