SyFi  0.3
Lagrange.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 <sstream>
00019 
00020 #include "Lagrange.h"
00021 #include "ElementComputations.h"
00022 #include "tools.h"
00023 
00024 using std::cout;
00025 using std::endl;
00026 using std::string;
00027 
00028 namespace SyFi
00029 {
00030 
00031         Lagrange::Lagrange() : StandardFE()
00032         {
00033                 description = "Lagrange";
00034         }
00035 
00036         Lagrange::Lagrange(Polygon& p, unsigned int order) : StandardFE(p, order)
00037         {
00038                 compute_basis_functions();
00039         }
00040 
00041         void Lagrange:: compute_basis_functions()
00042         {
00043 
00044                 // NOTE: in the below code dof(i) is not used to
00045                 // determine the basis functions
00046 
00047                 // remove previously computed basis functions and dofs
00048                 Ns.clear();
00049                 dofs.clear();
00050 
00051                 if ( order < 1 )
00052                 {
00053                         throw(std::logic_error("Lagrangian elements must be of order 1 or higher."));
00054                 }
00055 
00056                 if ( p == NULL )
00057                 {
00058                         throw(std::logic_error("You need to set a polygon before the basisfunctions can be computed"));
00059                 }
00060 
00061                 GiNaC::lst equations;
00062                 GiNaC::lst variables;
00063                 GiNaC::ex polynom;
00064 
00065                 if (p->str().find("ReferenceLine") != string::npos)
00066                 {
00067 
00068                         description = istr("Lagrange_", order) + "_1D";
00069 
00070                         // Look at the case with the Triangle for a documented code
00071 
00072                         //    polynom = pol(order, 1, "a");
00073                         //    variables = coeffs(polynom);
00074                         GiNaC::ex polynom_space = bernstein(order, *p, "a");
00075                         //    GiNaC::ex polynom_space = pol(order, 1, "a");
00076                         polynom = polynom_space.op(0);
00077                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00078 
00079                         GiNaC::ex increment = GiNaC::numeric(1,order);
00080 
00081                         GiNaC::ex Nj;
00082                         for (GiNaC::ex p=0; p<= 1 ; p += increment )
00083                         {
00084                                 GiNaC::ex eq = polynom == GiNaC::numeric(0);
00085                                 equations.append(eq.subs(x == p));
00086                                 dofs.insert(dofs.end(), GiNaC::lst(p));
00087                         }
00088                 }
00089                 else if (p->str().find("Line") != string::npos  )
00090                 {
00091                         description = istr("Lagrange_", order) + "_1D";
00092 
00093                         // Look at the case with the Triangle for a documented code
00094 
00095                         //    polynom = pol(order, 1, "a");
00096                         //    variables = coeffs(polynom);
00097                         GiNaC::ex polynom_space = bernstein(order, *p, "a");
00098                         //    GiNaC::ex polynom_space = pol(order, 1, "a");
00099                         polynom = polynom_space.op(0);
00100                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00101 
00102                         Polygon& pp = *p;
00103                         Line& l = (Line&) pp;
00104                         GiNaC::lst points = bezier_ordinates(l,order);
00105 
00106                         GiNaC::ex Nj;
00107                         for (unsigned int i=1; i<= points.nops() ; i++ )
00108                         {
00109                                 GiNaC::ex point = points.op(i-1);
00110                                 GiNaC::ex eq = polynom == GiNaC::numeric(0);
00111                                 if (point.nops() == 0) eq = eq.subs(x == point);
00112                                 if (point.nops() > 0) eq = eq.subs(x == point.op(0));
00113                                 if (point.nops() > 1) eq = eq.subs(y == point.op(1));
00114                                 if (point.nops() > 2) eq = eq.subs(z == point.op(2));
00115                                 equations.append(eq);
00116                                 dofs.insert(dofs.end(), GiNaC::lst(point));
00117                         }
00118 
00119                 }
00120                 else if (p->str().find("ReferenceTriangle") != string::npos  )
00121                 {
00122 
00123                         description = istr("Lagrange_", order) + "_2D";
00124 
00125                         // Look at the case with the Triangle for a documented code
00126 
00127                         //    polynom = pol(order, 2, "b");
00128                         //    variables = coeffs(polynom);
00129                         GiNaC::ex polynom_space = bernstein(order, *p, "b");
00130                         //    GiNaC::ex polynom_space = pol(order, 2, "a");
00131                         polynom = polynom_space.op(0);
00132                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00133 
00134                         GiNaC::ex increment = GiNaC::numeric(1,order);
00135 
00136                         GiNaC::ex Nj;
00137                         GiNaC::numeric one = 1;
00138                         for (GiNaC::ex q=0; q<= one  ; q += increment )
00139                         {
00140                                 for (GiNaC::ex p=0; p<= one-q ; p += increment )
00141                                 {
00142                                         GiNaC::ex eq = polynom == GiNaC::numeric(0);
00143                                         equations.append(eq.subs(GiNaC::lst(x == p, y == q)));
00144                                         dofs.insert(dofs.end(), GiNaC::lst(p,q));
00145                                 }
00146                         }
00147                 }
00148                 else if ( p->str().find("Triangle") != string::npos)
00149                 {
00150 
00151                         description = istr("Lagrange_", order) + "_2D";
00152 
00153                         // Look HERE for the documented code
00154 
00155                         //        GiNaC::ex polynom_space = pol(order, 2, "a");
00156                         GiNaC::ex polynom_space = bernstein(order, *p, "b");
00157                         // the polynomial spaces on the form:
00158                         // first item:     a0 + a1*x + a2*y + a3*x^2 + a4*x*y ...     the polynom
00159                         // second item:    a0, a1, a2, ...                            the coefficents
00160                         // third  item     1, x, y, x^2, ..                           the basis
00161                         // Could also do:
00162                         // GiNaC::ex polynom_space = bernstein(order, t, "a");
00163 
00164                         polynom = polynom_space.op(0);
00165                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00166 
00167                         GiNaC::ex Nj;
00168                         Polygon& pp = *p;
00169                         Triangle& t = (Triangle&) pp;
00170                         // The bezier ordinates (in which the basis function should be either 0 or 1)
00171                         GiNaC::lst points = bezier_ordinates(t,order);
00172 
00173                         for (unsigned int i=1; i<= points.nops() ; i++ )
00174                         {
00175                                 GiNaC::ex point = points.op(i-1);
00176                                 GiNaC::ex eq = polynom == GiNaC::numeric(0);
00177                                 equations.append(eq.subs(GiNaC::lst(x == point.op(0) , y == point.op(1))));
00178                                 dofs.insert(dofs.end(), GiNaC::lst(point.op(0),point.op(1)));
00179                         }
00180                 }
00181 
00182                 else if ( p->str().find("ReferenceRectangle") != string::npos)
00183                 {
00184 
00185                         description = istr("Lagrange_", order) + "_2D";
00186 
00187                         // create 1D element, then create tensor product
00188                         ReferenceLine line;
00189                         Lagrange fe(line, order);
00190 
00191                         for (unsigned int i=0; i< fe.nbf(); i++)
00192                         {
00193                                 for (unsigned int j=0; j< fe.nbf(); j++)
00194                                 {
00195                                         Ns.insert(Ns.end(), fe.N(i)*fe.N(j).subs(x==y));
00196                                         dofs.insert(dofs.end(), GiNaC::lst(fe.dof(i).op(0), fe.dof(j).op(0)));
00197                                 }
00198                         }
00199                         return;
00200 
00201                         /* OLD CODE
00202 
00203                            GiNaC::ex polynom_space = legendre(order, 2, "b");
00204 
00205                            polynom = polynom_space.op(0);
00206                            variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00207 
00208                         GiNaC::ex Nj;
00209                         Polygon& pp = *p;
00210                         ReferenceRectangle& b = (ReferenceRectangle&) pp;
00211 
00212                         int no_points = (order+1)*(order+1);
00213                         GiNaC::ex increment = GiNaC::numeric(1,order);
00214 
00215                         GiNaC::numeric one=1.0;
00216 
00217                         for (GiNaC::ex q=0; q <= one  ; q += increment )
00218                         {
00219                         for (GiNaC::ex p=0; p <= one ; p += increment )
00220                         {
00221                         GiNaC::ex eq = polynom == GiNaC::numeric(0);
00222                         equations.append(eq.subs(GiNaC::lst(x == p, y == q)));
00223                         dofs.push_back(GiNaC::lst(p,q));
00224                         }
00225                         }
00226                         */
00227                 }
00228                 else if ( p->str().find("ReferenceTetrahedron") != string::npos)
00229                 {
00230 
00231                         description = istr("Lagrange_", order) + "_3D";
00232 
00233                         // Look at the case with the Triangle for a documented code
00234 
00235                         //    polynom = pol(order, 3, "b");
00236                         //    GiNaC::ex polynom_space = pol(order, 3, "a");
00237                         GiNaC::ex polynom_space = bernstein(order, *p, "b");
00238                         polynom = polynom_space.op(0);
00239                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00240 
00241                         int nno =0;
00242                         for (unsigned int j=0; j<= order; j++)
00243                         {
00244                                 nno += (j+1)*(j+2)/2;
00245                         }
00246 
00247                         GiNaC::ex increment = GiNaC::numeric(1,order);
00248 
00249                         GiNaC::ex Nj;
00250                         for (GiNaC::ex r=0; r<= 1 ; r += increment )
00251                         {
00252                                 for (GiNaC::ex q=0; q<= 1-r ; q += increment )
00253                                 {
00254                                         for (GiNaC::ex p=0; p<= 1-r-q ; p += increment )
00255                                         {
00256                                                 GiNaC::ex eq = polynom == GiNaC::numeric(0);
00257                                                 equations.append(eq.subs(GiNaC::lst(x == p, y == q, z == r )));
00258                                                 dofs.push_back(GiNaC::lst(p,q,r));
00259                                         }
00260                                 }
00261                         }
00262                 }
00263                 else if ( p->str().find("Tetrahedron") != string::npos)
00264                 {
00265 
00266                         description = istr("Lagrange_", order) + "_3D";
00267 
00268                         // Look at the case with the Triangle for a documented code
00269 
00270                         GiNaC::ex polynom_space = pol(order, 3, "a");
00271                         //    GiNaC::ex polynom_space = bernstein(order, *p, "b");
00272                         polynom = polynom_space.op(0);
00273                         variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00274 
00275                         GiNaC::ex increment = GiNaC::numeric(1,order);
00276 
00277                         GiNaC::ex Nj;
00278                         Polygon& pp = *p;
00279                         Tetrahedron& t = (Tetrahedron&) pp;
00280                         GiNaC::lst points = bezier_ordinates(t,order);
00281                         for (unsigned int i=1; i<= points.nops() ; i++ )
00282                         {
00283                                 GiNaC::ex point = points.op(i-1);
00284                                 GiNaC::ex eq = polynom == GiNaC::numeric(0);
00285                                 equations.append(eq.subs(GiNaC::lst(x == point.op(0) , y == point.op(1), z == point.op(2))));
00286                                 dofs.push_back(GiNaC::lst(point.op(0),point.op(1),point.op(2)));
00287                         }
00288                 }
00289                 else if ( p->str().find("ReferenceBox") != string::npos)
00290                 {
00291 
00292                         description = istr("Lagrange_", order) + "_3D";
00293 
00294                         ReferenceLine line;
00295                         Lagrange fe(line, order);
00296 
00297                         for (unsigned int i=0; i< fe.nbf(); i++)
00298                         {
00299                                 for (unsigned int j=0; j< fe.nbf(); j++)
00300                                 {
00301                                         for (unsigned int k=0; k< fe.nbf(); k++)
00302                                         {
00303                                                 Ns.insert(Ns.end(), fe.N(i)*fe.N(j).subs(x==y)*fe.N(k).subs(x==z));
00304                                                 dofs.insert(dofs.end(), GiNaC::lst(fe.dof(i).op(0), fe.dof(j).op(0), fe.dof(k).op(0)));
00305                                         }
00306                                 }
00307                         }
00308                         return;
00309 
00310                         /* OLD CODE
00311 
00312                            GiNaC::ex polynom_space = legendre(order, 3, "b");
00313 
00314                            polynom = polynom_space.op(0);
00315                            variables = GiNaC::ex_to<GiNaC::lst>(polynom_space.op(1));
00316 
00317                         GiNaC::ex Nj;
00318                         Polygon& pp = *p;
00319                         ReferenceRectangle& b = (ReferenceRectangle&) pp;
00320 
00321                         int no_points = (order+1)*(order+1)*(order+1);
00322                         GiNaC::ex increment = GiNaC::numeric(1,order);
00323 
00324                         GiNaC::numeric one = 1;
00325                         for (GiNaC::ex p=0; p <= one ; p += increment) {
00326                         for (GiNaC::ex q=0; q <= one  ; q += increment) {
00327                         for (GiNaC::ex r=0; r <= one ; r += increment) {
00328                         GiNaC::ex eq = polynom == GiNaC::numeric(0);
00329                         equations.append(eq.subs(GiNaC::lst(x == p, y == q, z==r)));
00330                         dofs.push_back(GiNaC::lst(p,q,r));
00331                         }
00332                         }
00333                         }
00334 
00335                         / *
00336                                 GiNaC::ex subs = lsolve(equations, variables);
00337                                 Nj = polynom.subs(subs);
00338                                 Ns.push_back(Nj);
00339                                 */
00340                 }
00341 
00342                 // invert the matrix:
00343                 // GiNaC has a bit strange way to invert a matrix.
00344                 // It solves the system AA^{-1} = Id.
00345                 // It seems that this way is the only way to do
00346                 // properly with the solve_algo::gauss flag.
00347                 //
00348 
00349                 //    std::cout <<"no variables "<<variables.nops()<<std::endl;
00350                 //    std::cout <<"no equations "<<equations.nops()<<std::endl;
00351                 //    print(equations);
00352                 //    print(variables);
00353                 GiNaC::matrix b; GiNaC::matrix A;
00354                 matrix_from_equations(equations, variables, A, b);
00355 
00356                 unsigned int ncols = A.cols();
00357                 GiNaC::matrix vars_sq(ncols, ncols);
00358 
00359                 // matrix of symbols
00360                 for (unsigned r=0; r<ncols; ++r)
00361                         for (unsigned c=0; c<ncols; ++c)
00362                                 vars_sq(r, c) = GiNaC::symbol();
00363 
00364                 GiNaC::matrix id(ncols, ncols);
00365 
00366                 // identity
00367                 const GiNaC::ex _ex1(1);
00368                 for (unsigned i=0; i<ncols; ++i)
00369                         id(i, i) = _ex1;
00370 
00371                 // invert the matrix
00372                 GiNaC::matrix m_inv(ncols, ncols);
00373                 m_inv = A.solve(vars_sq, id, GiNaC::solve_algo::gauss);
00374 
00375                 for (unsigned int i=0; i<dofs.size(); i++)
00376                 {
00377                         b.let_op(i) = GiNaC::numeric(1);
00378                         GiNaC::ex xx = m_inv.mul(GiNaC::ex_to<GiNaC::matrix>(b));
00379 
00380                         GiNaC::lst subs;
00381                         for (unsigned int ii=0; ii<xx.nops(); ii++)
00382                         {
00383                                 subs.append(variables.op(ii) == xx.op(ii));
00384                         }
00385                         GiNaC::ex Nj = polynom.subs(subs);
00386                         Ns.insert(Ns.end(), Nj);
00387                         b.let_op(i) = GiNaC::numeric(0);
00388                 }
00389         }
00390 
00391         // ------------VectorLagrange ---
00392 
00393         VectorLagrange::VectorLagrange() : StandardFE()
00394         {
00395                 description = "VectorLagrange";
00396         }
00397 
00398         VectorLagrange::VectorLagrange(Polygon& p, unsigned int order, unsigned int size_) : StandardFE(p, order)
00399         {
00400                 size = size_ < 0 ? nsd: size_;
00401                 compute_basis_functions();
00402         }
00403 
00404         void VectorLagrange:: compute_basis_functions()
00405         {
00406 
00407                 // remove previously computed basis functions and dofs
00408                 Ns.clear();
00409                 dofs.clear();
00410 
00411                 if ( order < 1 )
00412                 {
00413                         throw(std::logic_error("Lagrangian elements must be of order 1 or higher."));
00414                 }
00415 
00416                 if ( p == NULL )
00417                 {
00418                         throw(std::logic_error("You need to set a polygon before the basisfunctions can be computed"));
00419                 }
00420 
00421                 if ( size == 0)
00422                 {
00423                         throw(std::logic_error("You need to set the size of the vector before the basisfunctions can be computed"));
00424                 }
00425 
00426                 Lagrange fe;
00427                 fe.set_order(order);
00428                 fe.set_polygon(*p);
00429                 fe.compute_basis_functions();
00430                 GiNaC::lst zero_list;
00431                 for (unsigned int s=1; s<= size ; s++)
00432                 {
00433                         zero_list.append(0);
00434                 }
00435 
00436                 for (unsigned int s=0; s< size ; s++)
00437                 {
00438                         for (unsigned int i=0; i< fe.nbf() ; i++)
00439                         {
00440                                 GiNaC::lst Nis = zero_list;
00441                                 Nis.let_op(s) = fe.N(i);
00442                                 GiNaC::ex Nmat = GiNaC::matrix(size,1,Nis);
00443                                 Ns.insert(Ns.end(), Nmat);
00444 
00445                                 GiNaC::lst dof = GiNaC::lst(fe.dof(i), s) ;
00446                                 dofs.insert(dofs.end(), dof);
00447                         }
00448                 }
00449 
00450                 description = "Vector" + fe.str();
00451         }
00452 
00453         void VectorLagrange:: set_size(unsigned int size_)
00454         {
00455                 size = size_;
00456         }
00457 
00458         // ------------TensorLagrange ---
00459 
00460         TensorLagrange::TensorLagrange() : StandardFE()
00461         {
00462                 description = "TensorLagrange";
00463         }
00464 
00465         TensorLagrange::TensorLagrange(Polygon& p, unsigned int order, unsigned int size_) : StandardFE(p, order)
00466         {
00467                 size = size_ < 0 ? nsd: size_;
00468                 compute_basis_functions();
00469         }
00470 
00471         void TensorLagrange:: compute_basis_functions()
00472         {
00473 
00474                 // remove previously computed basis functions and dofs
00475                 Ns.clear();
00476                 dofs.clear();
00477 
00478                 if ( order < 1 )
00479                 {
00480                         throw(std::logic_error("Lagrangian elements must be of order 1 or higher."));
00481                 }
00482 
00483                 if ( p == NULL )
00484                 {
00485                         throw(std::logic_error("You need to set a polygon before the basisfunctions can be computed"));
00486                 }
00487 
00488                 if ( size == 0)
00489                 {
00490                         throw(std::logic_error("You need to set the size of the vector before the basisfunctions can be computed"));
00491                 }
00492 
00493                 Lagrange fe;
00494                 fe.set_order(order);
00495                 fe.set_polygon(*p);
00496                 fe.compute_basis_functions();
00497                 GiNaC::lst zero_list;
00498                 for (unsigned int s=1; s<= size*size ; s++)
00499                 {
00500                         zero_list.append(0);
00501                 }
00502 
00503                 for (unsigned int r=0; r< size ; r++)
00504                 {
00505                         for (unsigned int s=0; s< size ; s++)
00506                         {
00507                                 for (unsigned int i=0; i< fe.nbf() ; i++)
00508                                 {
00509                                         GiNaC::lst Nis = zero_list;
00510                                         Nis.let_op((size)*r + s) = fe.N(i);
00511                                         GiNaC::ex Nmat = GiNaC::matrix(size,size,Nis);
00512                                         Ns.insert(Ns.end(), Nmat);
00513 
00514                                         GiNaC::lst dof = GiNaC::lst(fe.dof(i), r, s) ;
00515                                         dofs.insert(dofs.end(), dof);
00516                                 }
00517                         }
00518                 }
00519 
00520                 description = "Tensor" + fe.str();
00521         }
00522 
00523         void TensorLagrange:: set_size(unsigned int size_)
00524         {
00525                 size = size_;
00526         }
00527 
00528         GiNaC::ex lagrange(unsigned int order, Polygon& p, const std::string & a)
00529         {
00530                 if ( order < 1 )
00531                 {
00532                         throw(std::logic_error("Can not create polynomials of order less than 1!"));
00533                 }
00534 
00535                 GiNaC::ex A;
00536                 GiNaC::ex ret;
00537                 GiNaC::lst basis;
00538 
00539                 Lagrange fe(p,order);
00540                 A = get_symbolic_matrix(1, fe.nbf(), a);
00541 
00542                 for (unsigned int i=0; i<fe.nbf(); i++)
00543                 {
00544                         ret += A.op(i)*fe.N(i);
00545                         basis.append(fe.N(i));
00546                 }
00547                 return GiNaC::lst(ret,matrix_to_lst2(A),basis);
00548         }
00549 
00550         GiNaC::lst lagrangev(unsigned int no_fields, unsigned int order, Polygon& p, const std::string & a)
00551         {
00552                 if ( order < 1 )
00553                 {
00554                         throw(std::logic_error("Can not create polynomials of order less than 1!"));
00555                 }
00556 
00557                 GiNaC::ex A;
00558                 GiNaC::ex ret;
00559                 GiNaC::lst basis;
00560 
00561                 VectorLagrange fe(p,order);
00562                 A = get_symbolic_matrix(1, fe.nbf(), a);
00563 
00564                 for (unsigned int i=0; i<fe.nbf(); i++)
00565                 {
00566                         ret += A.op(i)*fe.N(i);
00567                         basis.append(fe.N(i));
00568                 }
00569                 return GiNaC::lst(ret,matrix_to_lst2(A),basis);
00570         }
00571 
00572 }                                                                // namespace SyFi
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator