Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Search for

# Nedelec.cpp

Go to the documentation of this file.

    00001 #include <Nedelec.h>
    00002 #include <fstream>
    00003
    00004
    00005 int Nedelec:: nbf() {
    00006   return Ns.size();
    00007 }
    00008
    00009 void Nedelec:: compute_basis_functions() {
    00010
    00011   if ( order < 1 ) {
    00012     cout <<"Nedelec elements must be of order 1 or higher."<<endl;
    00013     return;
    00014   }
    00015
    00016
    00017   if ( p == NULL ) {
    00018     cout <<"You need to set a polygon before the basisfunctions can be computed"<<endl;
    00019     return;
    00020   }
    00021
    00022
    00023
    00024   if (p->str() == "ReferenceLine" || p->str() == "Line" ) {
    00025
    00026     cout <<"Can not define the Nedelec element on a line"<<endl;
    00027
    00028   } else if (p->str() == "ReferenceTriangle" || p->str() == "Triangle" ) {
    00029
    00030     int k = order;
    00031     int removed_dofs=0;
    00032
    00033     Triangle& triangle = (Triangle&)(*p);
    00034     GiNaC::lst equations;
    00035     GiNaC::lst variables;
    00036
    00037     // create r
    00038     GiNaC::ex R_k = homogenous_polv(2,k+1, 2, "a");
    00039     GiNaC::ex R_k_x = R_k.op(0).op(0);
    00040     GiNaC::ex R_k_y = R_k.op(0).op(1);
    00041
    00042
    00043     // Equations that make sure that r*x = 0
    00044     GiNaC::ex rx = (R_k_x*x + R_k_y*y).expand();
    00045     ex_ex_map pol_map = pol2basisandcoeff(rx);
    00046     ex_ex_it iter;
    00047     for (iter = pol_map.begin(); iter != pol_map.end(); iter++) {
    00048       if ((*iter).second != 0 ) {
    00049         equations.append((*iter).second == 0 );
    00050         removed_dofs++;
    00051       }
    00052     }
    00053
    00054
    00055
    00056     // create p
    00057     GiNaC::ex P_k = bernsteinv(2,k, triangle, "b");
    00058     GiNaC::ex P_k_x = P_k.op(0).op(0);
    00059     GiNaC::ex P_k_y = P_k.op(0).op(1);
    00060
    00061
    00062
    00063     // collect the variables of r and p  in one list
    00064     variables = collapse(GiNaC::lst(collapse(GiNaC::ex_to<GiNaC::lst>(R_k.op(1))),
    00065                                     collapse(GiNaC::ex_to<GiNaC::lst>(P_k.op(1)))));
    00066
    00067     // create the polynomial space
    00068     GiNaC::lst pspace = GiNaC::lst( R_k_x + P_k_x,
    00069                                     R_k_y + P_k_y);
    00070
    00071     int counter = 0;
    00072     GiNaC::symbol t("t");
    00073     GiNaC::ex dofi;
    00074     // dofs related to edges
    00075     for (int i=1; i<= 3; i++) {
    00076       Line line = triangle.line(i);
    00077       GiNaC::lst tangent_vec = tangent(triangle, i);
    00078       GiNaC::ex bernstein_pol = bernstein(order, line, istr("a",i));
    00079       GiNaC::ex basis_space = bernstein_pol.op(2);
    00080       GiNaC::ex pspace_t = inner(pspace, tangent_vec);
    00081
    00082       GiNaC::ex basis;
    00083       for (int j=0; j< basis_space.nops(); j++) {
    00084         counter++;
    00085         basis = basis_space.op(j);
    00086         GiNaC::ex integrand = pspace_t*basis;
    00087         dofi =  line.integrate(integrand);
    00088         dofs.insert(dofs.end(), dofi);
    00089         GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00090         equations.append(eq);
    00091       }
    00092     }
    00093
    00094     // dofs related to the whole triangle
    00095     GiNaC::lst bernstein_polv;
    00096     if ( order > 0) {
    00097       counter++;
    00098       bernstein_polv = bernsteinv(2,order-1, triangle, "a");
    00099       GiNaC::ex basis_space = bernstein_polv.op(2);
    00100       for (int i=0; i< basis_space.nops(); i++) {
    00101         GiNaC::lst basis = GiNaC::ex_to<GiNaC::lst>(basis_space.op(i));
    00102         GiNaC::ex integrand = inner(pspace, basis);
    00103         dofi = triangle.integrate(integrand);
    00104         dofs.insert(dofs.end(), dofi);
    00105         GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00106         equations.append(eq);
    00107       }
    00108     }
    00109
    00110
    00111
    00112     // invert the matrix:
    00113     // GiNaC has a bit strange way to invert a matrix.
    00114     // It solves the system AA^{-1} = Id.
    00115     // It seems that this way is the only way to do
    00116     // properly with the solve_algo::gauss flag.
    00117     GiNaC::matrix b; GiNaC::matrix A;
    00118     matrix_from_equations(equations, variables, A, b);
    00119
    00120     int ncols = A.cols();
    00121     GiNaC::matrix vars_sq(ncols, ncols);
    00122
    00123     // matrix of symbols
    00124     for (unsigned r=0; r<ncols; ++r)
    00125       for (unsigned c=0; c<ncols; ++c)
    00126         vars_sq(r, c) = GiNaC::symbol();
    00127
    00128     GiNaC::matrix id(ncols, ncols);
    00129
    00130     // identity
    00131     const GiNaC::ex _ex1(1);
    00132     for (unsigned i=0; i<ncols; ++i)
    00133       id(i, i) = _ex1;
    00134
    00135
    00136     // invert the matrix
    00137     GiNaC::matrix m_inv(ncols, ncols);
    00138     m_inv = A.solve(vars_sq, id, GiNaC::solve_algo::gauss);
    00139
    00140
    00141     for (int i=0; i<dofs.size(); i++) {
    00142       b.let_op(removed_dofs + i) = GiNaC::numeric(1);
    00143       GiNaC::ex xx = m_inv.mul(GiNaC::ex_to<GiNaC::matrix>(b));
    00144
    00145       GiNaC::lst subs;
    00146       for (int ii=0; ii<xx.nops(); ii++) {
    00147         subs.append(variables.op(ii) == xx.op(ii));
    00148       }
    00149       GiNaC::ex Nj1 = pspace.op(0).subs(subs);
    00150       GiNaC::ex Nj2 = pspace.op(1).subs(subs);
    00151       Ns.insert(Ns.end(), GiNaC::matrix(1,2,GiNaC::lst(Nj1,Nj2)));
    00152       b.let_op(removed_dofs + i) = GiNaC::numeric(0);
    00153     }
    00154
    00155   } else if ( p->str() == "ReferenceTetrahedron" || p->str() == "Tetrahedron" ) {
    00156
    00157     int k = order;
    00158     int removed_dofs=0;
    00159
    00160     Tetrahedron& tetrahedron= (Tetrahedron&)(*p);
    00161     GiNaC::lst equations;
    00162     GiNaC::lst variables;
    00163
    00164     // create r
    00165     GiNaC::ex R_k = homogenous_polv(3,k+1, 3, "a");
    00166     GiNaC::ex R_k_x = R_k.op(0).op(0);
    00167     GiNaC::ex R_k_y = R_k.op(0).op(1);
    00168     GiNaC::ex R_k_z = R_k.op(0).op(2);
    00169
    00170     // Equations that make sure that r*x = 0
    00171     GiNaC::ex rx = (R_k_x*x + R_k_y*y + R_k_z*z).expand();
    00172     ex_ex_map pol_map = pol2basisandcoeff(rx);
    00173     ex_ex_it iter;
    00174     for (iter = pol_map.begin(); iter != pol_map.end(); iter++) {
    00175       if ((*iter).second != 0 ) {
    00176         equations.append((*iter).second == 0 );
    00177         removed_dofs++;
    00178       }
    00179     }
    00180
    00181
    00182     // create p
    00183     GiNaC::ex P_k = bernsteinv(3,k, tetrahedron, "b");
    00184     GiNaC::ex P_k_x = P_k.op(0).op(0);
    00185     GiNaC::ex P_k_y = P_k.op(0).op(1);
    00186     GiNaC::ex P_k_z = P_k.op(0).op(2);
    00187
    00188     // collect the variables of r and p  in one list
    00189     variables = collapse(GiNaC::lst(collapse(GiNaC::ex_to<GiNaC::lst>(R_k.op(1))),
    00190                                     collapse(GiNaC::ex_to<GiNaC::lst>(P_k.op(1)))));
    00191
    00192
    00193
    00194     // create the polynomial space
    00195     GiNaC::lst pspace = GiNaC::lst( R_k_x + P_k_x,
    00196                                     R_k_y + P_k_y,
    00197                                     R_k_z + P_k_z);
    00198
    00199
    00200     int counter = 0;
    00201     GiNaC::symbol t("t");
    00202     GiNaC::ex dofi;
    00203
    00204     // dofs related to edges
    00205     for (int i=1; i<= 6; i++) {
    00206       Line line = tetrahedron.line(i);
    00207       GiNaC::ex line_repr = line.repr(t);
    00208       GiNaC::lst tangent_vec = GiNaC::lst(line_repr.op(0).rhs().coeff(t,1),
    00209                                           line_repr.op(1).rhs().coeff(t,1),
    00210                                           line_repr.op(2).rhs().coeff(t,1));
    00211
    00212
    00213       GiNaC::ex bernstein_pol = bernstein(order, line, istr("a",i));
    00214       GiNaC::ex basis_space = bernstein_pol.op(2);
    00215       GiNaC::ex pspace_t = inner(pspace, tangent_vec);
    00216
    00217       GiNaC::ex basis;
    00218       for (int j=0; j< basis_space.nops(); j++) {
    00219         counter++;
    00220         basis = basis_space.op(j);
    00221         GiNaC::ex integrand = pspace_t*basis;
    00222         dofi =  line.integrate(integrand);
    00223         dofs.insert(dofs.end(), dofi);
    00224         GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00225         equations.append(eq);
    00226       }
    00227     }
    00228
    00229
    00230     // dofs related to faces
    00231     if ( order > 0 ) {
    00232       for (int i=1; i<= 4; i++){
    00233         Triangle triangle = tetrahedron.triangle(i);
    00234         GiNaC::ex bernstein_pol = bernsteinv(3,order-1, triangle, istr("b", i));
    00235         GiNaC::ex basis_space = bernstein_pol.op(2);
    00236
    00237         GiNaC::ex basis;
    00238         GiNaC::lst normal_vec = normal(tetrahedron, i);
    00239         GiNaC::ex pspace_n = cross(pspace, normal_vec);
    00240         if ( normal_vec.op(0) != GiNaC::numeric(0) &&
    00241              normal_vec.op(1) != GiNaC::numeric(0) &&
    00242              normal_vec.op(2) != GiNaC::numeric(0) )
    00243         {
    00244           for (int j=0; j<basis_space.nops(); j++) {
    00245             basis = basis_space.op(j);
    00246             if ( basis.op(0) != 0 || basis.op(1) != 0 ) {
    00247               GiNaC::ex integrand = inner(pspace_n,basis);
    00248               if ( integrand != GiNaC::numeric(0) ) {
    00249                 dofi = triangle.integrate(integrand);
    00250                 GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00251                 equations.append(eq);
    00252               }
    00253             }
    00254           }
    00255
    00256         } else {
    00257           for (int j=0; j<basis_space.nops(); j++) {
    00258             basis = basis_space.op(j);
    00259             GiNaC::ex integrand = inner(pspace_n,basis);
    00260             if ( integrand != GiNaC::numeric(0) ) {
    00261               dofi = triangle.integrate(integrand);
    00262               GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00263               equations.append(eq);
    00264             }
    00265           }
    00266         }
    00267       }
    00268     }
    00269
    00270     // dofs related to tetrahedron
    00271     if ( order > 1 ) {
    00272       GiNaC::ex bernstein_pol = bernsteinv(3,order-2, tetrahedron, istr("c", 0));
    00273       GiNaC::ex basis_space = bernstein_pol.op(2);
    00274       GiNaC::ex basis;
    00275       for (int j=0; j<basis_space.nops(); j++) {
    00276         basis = basis_space.op(j);
    00277         GiNaC::ex integrand = inner(pspace,basis);
    00278         dofi = tetrahedron.integrate(integrand);
    00279         GiNaC::ex eq = dofi == GiNaC::numeric(0);
    00280         equations.append(eq);
    00281       }
    00282     }
    00283
    00284
    00285     // invert the matrix:
    00286     // GiNaC has a bit strange way to invert a matrix.
    00287     // It solves the system AA^{-1} = Id.
    00288     // It seems that this way is the only way to do
    00289     // properly with the solve_algo::gauss flag.
    00290     GiNaC::matrix b; GiNaC::matrix A;
    00291     matrix_from_equations(equations, variables, A, b);
    00292
    00293     int ncols = A.cols();
    00294     GiNaC::matrix vars_sq(ncols, ncols);
    00295
    00296     // matrix of symbols
    00297     for (unsigned r=0; r<ncols; ++r)
    00298       for (unsigned c=0; c<ncols; ++c)
    00299         vars_sq(r, c) = GiNaC::symbol();
    00300
    00301     GiNaC::matrix id(ncols, ncols);
    00302
    00303     // identity
    00304     const GiNaC::ex _ex1(1);
    00305     for (unsigned i=0; i<ncols; ++i)
    00306       id(i, i) = _ex1;
    00307
    00308
    00309     // invert the matrix
    00310     GiNaC::matrix m_inv(ncols, ncols);
    00311     m_inv = A.solve(vars_sq, id, GiNaC::solve_algo::gauss);
    00312
    00313
    00314     for (int i=0; i<dofs.size(); i++) {
    00315       b.let_op(removed_dofs + i) = GiNaC::numeric(1);
    00316       GiNaC::ex xx = m_inv.mul(GiNaC::ex_to<GiNaC::matrix>(b));
    00317
    00318       GiNaC::lst subs;
    00319       for (int ii=0; ii<xx.nops(); ii++) {
    00320         subs.append(variables.op(ii) == xx.op(ii));
    00321       }
    00322       GiNaC::ex Nj1 = pspace.op(0).subs(subs);
    00323       GiNaC::ex Nj2 = pspace.op(1).subs(subs);
    00324       GiNaC::ex Nj3 = pspace.op(2).subs(subs);
    00325       Ns.insert(Ns.end(), GiNaC::matrix(1,2,GiNaC::lst(Nj1,Nj2,Nj3)));
    00326       b.let_op(removed_dofs + i) = GiNaC::numeric(0);
    00327     }
    00328
    00329
    00330
    00331
    00332
    00333   }
    00334
    00335 }
    00336
    00337
    00338 void Nedelec:: set(Polygon& p_) {
    00339   StandardFE:: set(p_);
    00340 }
    00341
    00342
    00343 void Nedelec:: set(int order_) {
    00344   StandardFE:: set(order_);
    00345 }
    00346
    00347
    00348 GiNaC::ex Nedelec:: dof(int i) {
    00349   return StandardFE::dof(i);
    00350 }
    00351
    00352
    00353 GiNaC::ex Nedelec::N(int i) {
    00354   return StandardFE::N(i);
    00355 }
    00356
    00357
    00358