MFEM v2.0
nurbs.hpp
Go to the documentation of this file.
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
00003 // reserved. See file COPYRIGHT for details.
00004 //
00005 // This file is part of the MFEM library. For more information and source code
00006 // availability see http://mfem.googlecode.com.
00007 //
00008 // MFEM is free software; you can redistribute it and/or modify it under the
00009 // terms of the GNU Lesser General Public License (as published by the Free
00010 // Software Foundation) version 2.1 dated February 1999.
00011 
00012 #ifndef MFEM_NURBS
00013 #define MFEM_NURBS
00014 
00015 class KnotVector
00016 {
00017 protected:
00018    static const int MaxOrder;
00019 
00020    Vector knot;
00021    int Order, NumOfControlPoints, NumOfElements;
00022 
00023 public:
00025    KnotVector() { }
00026    KnotVector(istream &input);
00027    KnotVector(int Order_, int NCP);
00028    KnotVector(const KnotVector &kv){ (*this) = kv; }
00029 
00030    KnotVector &operator=(const KnotVector &kv);
00031 
00032    int GetNE()    const { return NumOfElements; }
00033    int GetNKS()   const { return NumOfControlPoints - Order; }
00034    int GetNCP()   const { return NumOfControlPoints; }
00035    int GetOrder() const { return Order; }
00036    int Size()     const { return knot.Size(); }
00037 
00039    void GetElements();
00040 
00041    bool isElement(int i) const { return (knot(Order+i) != knot(Order+i+1)); }
00042 
00043    double getKnotLocation(double xi, int ni) const
00044    { return (xi*knot(ni+1) + (1. - xi)*knot(ni)); }
00045 
00046    int findKnotSpan(double u) const;
00047 
00048    void CalcShape (Vector &shape, int i, double xi);
00049    void CalcDShape(Vector &grad,  int i, double xi);
00050 
00051    void Difference(const KnotVector &kv, Vector &diff) const;
00052    void UniformRefinement(Vector &newknots) const;
00055    KnotVector *DegreeElevate(int t) const;
00056 
00057    void Flip();
00058 
00059    void Print(ostream &out) const;
00060 
00062    ~KnotVector() { }
00063 
00064    double &operator[](int i) { return knot(i); }
00065    const double &operator[](int i) const { return knot(i); }
00066 };
00067 
00068 
00069 class NURBSPatch
00070 {
00071 protected:
00072    int     ni, nj, nk, Dim;
00073    double *data;
00074 
00075    Array<KnotVector *> kv;
00076 
00077    int sd, nd;
00078 
00079    void swap(NURBSPatch *np);
00080 
00081    // Special B-NET acces functions
00082    int SetLoopDirection(int dir);
00083    inline       double &operator()(int i, int j);
00084    inline const double &operator()(int i, int j) const;
00085 
00086    void init(int dim_);
00087 
00088    NURBSPatch(NURBSPatch *parent, int dir, int Order, int NCP);
00089 
00090 public:
00091    NURBSPatch(istream &input);
00092    NURBSPatch(KnotVector *kv0, KnotVector *kv1, int dim_);
00093    NURBSPatch(KnotVector *kv0, KnotVector *kv1, KnotVector *kv2, int dim_);
00094    NURBSPatch(Array<KnotVector *> &kv, int dim_);
00095 
00096    ~NURBSPatch();
00097 
00098    void Print(ostream &out);
00099 
00100    void DegreeElevate(int dir, int t);
00101    void KnotInsert   (int dir, const KnotVector &knot);
00102    void KnotInsert   (int dir, const Vector     &knot);
00103 
00104    void KnotInsert(Array<KnotVector *> &knot);
00105    void DegreeElevate(int t);
00106    void UniformRefinement();
00107 
00108    KnotVector *GetKV(int i) { return kv[i]; }
00109 
00110    // Standard B-NET acces functions
00111    inline       double &operator()(int i, int j, int l);
00112    inline const double &operator()(int i, int j, int l) const;
00113 
00114    inline       double &operator()(int i, int j, int k, int l);
00115    inline const double &operator()(int i, int j, int k, int l) const;
00116 
00117    static void Get3DRotationMatrix(double n[], double angle, double r,
00118                                    DenseMatrix &T);
00119    void FlipDirection(int dir);
00120    void SwapDirections(int dir1, int dir2);
00121    void Rotate3D(double normal[], double angle);
00122    int MakeUniformDegree();
00123    friend NURBSPatch *Interpolate(NURBSPatch &p1, NURBSPatch &p2);
00124    friend NURBSPatch *Revolve3D(NURBSPatch &patch, double n[], double ang,
00125                                 int times);
00126 };
00127 
00128 
00129 #ifdef MFEM_USE_MPI
00130 class ParNURBSExtension;
00131 #endif
00132 
00133 class NURBSPatchMap;
00134 
00135 
00136 class NURBSExtension
00137 {
00138 #ifdef MFEM_USE_MPI
00139    friend class ParNURBSExtension;
00140 #endif
00141    friend class NURBSPatchMap;
00142 
00143 protected:
00144    int Order;
00145    int NumOfKnotVectors;
00146    // global entity counts
00147    int NumOfVertices, NumOfElements, NumOfBdrElements, NumOfDofs;
00148    // local entity counts
00149    int NumOfActiveVertices, NumOfActiveElems, NumOfActiveBdrElems;
00150    int NumOfActiveDofs;
00151 
00152    Array<int>  activeVert; // activeVert[glob_vert] = loc_vert or -1
00153    Array<bool> activeElem;
00154    Array<bool> activeBdrElem;
00155    Array<int>  activeDof; // activeDof[glob_dof] = loc_dof + 1 or 0
00156 
00157    Mesh *patchTopo;
00158    int own_topo;
00159    Array<int> edge_to_knot;
00160    Array<KnotVector *> knotVectors;
00161    Vector weights;
00162 
00163    // global offsets, meshOffsets == meshVertexOffsets
00164    Array<int> v_meshOffsets;
00165    Array<int> e_meshOffsets;
00166    Array<int> f_meshOffsets;
00167    Array<int> p_meshOffsets;
00168 
00169    // global offsets, spaceOffsets == dofOffsets
00170    Array<int> v_spaceOffsets;
00171    Array<int> e_spaceOffsets;
00172    Array<int> f_spaceOffsets;
00173    Array<int> p_spaceOffsets;
00174 
00175    Table *el_dof, *bel_dof;
00176 
00177    Array<int> el_to_patch;
00178    Array<int> bel_to_patch;
00179    Array2D<int> el_to_IJK;  // IJK are "knot-span" indices!
00180    Array2D<int> bel_to_IJK; // they are NOT element indices!
00181 
00182    Array<NURBSPatch *> patches;
00183 
00184    inline int         KnotInd(int edge);
00185    inline KnotVector *KnotVec(int edge);
00186    inline KnotVector *KnotVec(int edge, int oedge, int *okv);
00187 
00188    void CheckPatches();
00189    void CheckBdrPatches();
00190 
00191    void GetPatchKnotVectors   (int p, Array<KnotVector *> &kv);
00192    void GetBdrPatchKnotVectors(int p, Array<KnotVector *> &kv);
00193 
00194    // also count the global NumOfVertices and the global NumOfDofs
00195    void GenerateOffsets();
00196    // count the global NumOfElements
00197    void CountElements();
00198    // count the global NumOfBdrElements
00199    void CountBdrElements();
00200 
00201    // generate the mesh elements
00202    void Get2DElementTopo(Array<Element *> &elements);
00203    void Get3DElementTopo(Array<Element *> &elements);
00204 
00205    // generate the boundary mesh elements
00206    void Get2DBdrElementTopo(Array<Element *> &boundary);
00207    void Get3DBdrElementTopo(Array<Element *> &boundary);
00208 
00209 
00210    // FE space generation functions
00211 
00212    // based on activeElem, count NumOfActiveDofs, generate el_dof,
00213    // el_to_patch, el_to_IJK, activeDof map (global-to-local)
00214    void GenerateElementDofTable();
00215 
00216    // generate elem_to_global-dof table for the active elements
00217    // define el_to_patch, el_to_IJK, activeDof (as bool)
00218    void Generate2DElementDofTable();
00219    void Generate3DElementDofTable();
00220 
00221    // call after GenerateElementDofTable
00222    void GenerateBdrElementDofTable();
00223 
00224    // generate the bdr-elem_to_global-dof table for the active bdr. elements
00225    // define bel_to_patch, bel_to_IJK
00226    void Generate2DBdrElementDofTable();
00227    void Generate3DBdrElementDofTable();
00228 
00229    // Patch <--> FE translation functions
00230    void GetPatchNets  (const Vector &Nodes);
00231    void Get2DPatchNets(const Vector &Nodes);
00232    void Get3DPatchNets(const Vector &Nodes);
00233 
00234    void SetSolutionVector  (Vector &Nodes);
00235    void Set2DSolutionVector(Vector &Nodes);
00236    void Set3DSolutionVector(Vector &Nodes);
00237 
00238    // determine activeVert, NumOfActiveVertices from the activeElem array
00239    void GenerateActiveVertices();
00240 
00241    // determine activeBdrElem, NumOfActiveBdrElems
00242    void GenerateActiveBdrElems();
00243 
00244    void MergeWeights(Mesh *mesh_array[], int num_pieces);
00245 
00246    // to be used by ParNURBSExtension constructor(s)
00247    NURBSExtension() { }
00248 
00249 public:
00251    NURBSExtension(istream &input);
00254    NURBSExtension(NURBSExtension *parent, int Order);
00256    NURBSExtension(Mesh *mesh_array[], int num_pieces);
00257 
00258    void MergeGridFunctions(GridFunction *gf_array[], int num_pieces,
00259                            GridFunction &merged);
00260 
00262    virtual ~NURBSExtension();
00263 
00264    // Print functions
00265    void Print(ostream &out) const;
00266    void PrintCharacteristics(ostream &out);
00267 
00268    // Meta data functions
00269    int Dimension() { return patchTopo->Dimension(); }
00270    int GetNP()     { return patchTopo->GetNE(); }
00271    int GetNBP()    { return patchTopo->GetNBE(); }
00272    int GetOrder()  { return Order; }
00273    int GetNKV()    { return NumOfKnotVectors; }
00274 
00275    int GetGNV()  { return NumOfVertices; }
00276    int GetNV()   { return NumOfActiveVertices; }
00277    int GetGNE()  { return NumOfElements; }
00278    int GetNE()   { return NumOfActiveElems; }
00279    int GetGNBE() { return NumOfBdrElements; }
00280    int GetNBE()  { return NumOfActiveBdrElems; }
00281 
00282    int GetNTotalDof() { return NumOfDofs; }
00283    int GetNDof()      { return NumOfActiveDofs; }
00284 
00285    // Knotvector acces function
00286    const KnotVector *GetKnotVector(int i) const { return knotVectors[i]; }
00287 
00288    // Mesh generation functions
00289    void GetElementTopo   (Array<Element *> &elements);
00290    void GetBdrElementTopo(Array<Element *> &boundary);
00291 
00292    bool HavePatches() { return (patches.Size() != 0); }
00293 
00294    Table *GetElementDofTable() { return el_dof; }
00295    Table *GetBdrElementDofTable() { return bel_dof; }
00296 
00297    void GetVertexLocalToGlobal(Array<int> &lvert_vert);
00298    void GetElementLocalToGlobal(Array<int> &lelem_elem);
00299 
00300    // Load functions
00301    void LoadFE(int i, const FiniteElement *FE);
00302    void LoadBE(int i, const FiniteElement *BE);
00303 
00304    const Vector &GetWeights() const { return  weights; }
00305    Vector       &GetWeights()       { return  weights; }
00306 
00307    // Translation functions: from FE coordinates into to IJK patch
00308    // format and vice versa
00309    void ConvertToPatches(const Vector &Nodes);
00310    void SetKnotsFromPatches();
00311    void SetCoordsFromPatches(Vector &Nodes);
00312 
00313    // Refinement methods
00314    void DegreeElevate(int t);
00315    void UniformRefinement();
00316    void KnotInsert(Array<KnotVector *> &kv);
00317 };
00318 
00319 
00320 #ifdef MFEM_USE_MPI
00321 class ParNURBSExtension : public NURBSExtension
00322 {
00323 private:
00324    int *partitioning;
00325 
00326    Table *GetGlobalElementDofTable();
00327    Table *Get2DGlobalElementDofTable();
00328    Table *Get3DGlobalElementDofTable();
00329 
00330    void SetActive(int *partitioning, const Array<bool> &active_bel);
00331    void BuildGroups(int *partitioning, const Table &elem_dof);
00332 
00333 public:
00334    GroupTopology gtopo;
00335 
00336    Array<int> ldof_group;
00337 
00338    ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent, int *partitioning,
00339                      const Array<bool> &active_bel);
00340 
00341    // create a parallel version of 'parent' with partitioning as in
00342    // 'par_parent'; the 'parent' object is destroyed
00343    ParNURBSExtension(NURBSExtension *parent, ParNURBSExtension *par_parent);
00344 
00345    virtual ~ParNURBSExtension() { delete [] partitioning; }
00346 };
00347 #endif
00348 
00349 
00350 class NURBSPatchMap
00351 {
00352 private:
00353    NURBSExtension *Ext;
00354 
00355    int I, J, K, pOffset, opatch;
00356    Array<int> verts, edges, faces, oedge, oface;
00357 
00358    inline static int F(const int n, const int N)
00359    { return (n < 0) ? 0 : ((n >= N) ? 2 : 1); }
00360 
00361    inline static int Or1D(const int n, const int N, const int Or)
00362    { return (Or > 0) ? n : (N - 1 - n); }
00363 
00364    inline static int Or2D(const int n1, const int n2,
00365                           const int N1, const int N2, const int Or);
00366 
00367    // also set verts, edges, faces, orientations etc
00368    void GetPatchKnotVectors   (int p, KnotVector *kv[]);
00369    void GetBdrPatchKnotVectors(int p, KnotVector *kv[], int *okv);
00370 
00371 public:
00372    NURBSPatchMap(NURBSExtension *ext) { Ext = ext; }
00373 
00374    int nx() { return I + 1; }
00375    int ny() { return J + 1; }
00376    int nz() { return K + 1; }
00377 
00378    void SetPatchVertexMap(int p, KnotVector *kv[]);
00379    void SetPatchDofMap   (int p, KnotVector *kv[]);
00380 
00381    void SetBdrPatchVertexMap(int p, KnotVector *kv[], int *okv);
00382    void SetBdrPatchDofMap   (int p, KnotVector *kv[], int *okv);
00383 
00384    inline int operator()(const int i) const;
00385    inline int operator[](const int i) const { return (*this)(i); }
00386 
00387    inline int operator()(const int i, const int j) const;
00388 
00389    inline int operator()(const int i, const int j, const int k) const;
00390 };
00391 
00392 
00393 // Inline function implementations
00394 
00395 inline double &NURBSPatch::operator()(int i, int j)
00396 {
00397    return data[j%sd + sd*(i + (j/sd)*nd)];
00398 }
00399 
00400 inline const double &NURBSPatch::operator()(int i, int j) const
00401 {
00402    return data[j%sd + sd*(i + (j/sd)*nd)];
00403 }
00404 
00405 inline double &NURBSPatch::operator()(int i, int j, int l)
00406 {
00407 #ifdef MFEM_DEBUG
00408    if (data == 0 || i < 0 || i >= ni || j < 0 || j >= nj || nk > 0 ||
00409        l < 0 || l >= Dim)
00410       mfem_error("NURBSPatch::operator() 2D");
00411 #endif
00412 
00413    return data[(i+j*ni)*Dim+l];
00414 }
00415 
00416 inline const double &NURBSPatch::operator()(int i, int j, int l) const
00417 {
00418 #ifdef MFEM_DEBUG
00419    if (data == 0 || i < 0 || i >= ni || j < 0 || j >= nj || nk > 0 ||
00420        l < 0 || l >= Dim)
00421       mfem_error("NURBSPatch::operator() const 2D");
00422 #endif
00423 
00424    return data[(i+j*ni)*Dim+l];
00425 }
00426 
00427 inline double &NURBSPatch::operator()(int i, int j, int k, int l)
00428 {
00429 #ifdef MFEM_DEBUG
00430    if (data == 0 || i < 0 || i >= ni || j < 0 || j >= nj || k < 0 ||
00431        k >= nk || l < 0 || l >= Dim)
00432       mfem_error("NURBSPatch::operator() 3D");
00433 #endif
00434 
00435    return data[(i+(j+k*nj)*ni)*Dim+l];
00436 }
00437 
00438 inline const double &NURBSPatch::operator()(int i, int j, int k, int l) const
00439 {
00440 #ifdef MFEM_DEBUG
00441    if (data == 0 || i < 0 || i >= ni || j < 0 || j >= nj || k < 0 ||
00442        k >= nk ||  l < 0 || l >= Dim)
00443       mfem_error("NURBSPatch::operator() const 3D");
00444 #endif
00445 
00446    return data[(i+(j+k*nj)*ni)*Dim+l];
00447 }
00448 
00449 
00450 inline int NURBSExtension::KnotInd(int edge)
00451 {
00452    int kv = edge_to_knot[edge];
00453    return (kv >= 0) ? kv : (-1-kv);
00454 }
00455 
00456 inline KnotVector *NURBSExtension::KnotVec(int edge)
00457 {
00458    return knotVectors[KnotInd(edge)];
00459 }
00460 
00461 inline KnotVector *NURBSExtension::KnotVec(int edge, int oedge, int *okv)
00462 {
00463    int kv = edge_to_knot[edge];
00464    if (kv >= 0)
00465    {
00466       *okv = oedge;
00467       return knotVectors[kv];
00468    }
00469    else
00470    {
00471       *okv = -oedge;
00472       return knotVectors[-1-kv];
00473    }
00474 }
00475 
00476 
00477 inline int NURBSPatchMap::Or2D(const int n1, const int n2,
00478                                const int N1, const int N2, const int Or)
00479 {
00480    // Needs testing
00481    switch (Or)
00482    {
00483    case 0: return n1 + n2*N1;
00484    case 1: return n2 + n1*N2;
00485    case 2: return n2 + (N1 - 1 - n1)*N2;
00486    case 3: return (N1 - 1 - n1) + n2*N1;
00487    case 4: return (N1 - 1 - n1) + (N2 - 1 - n2)*N1;
00488    case 5: return (N2 - 1 - n2) + (N1 - 1 - n1)*N2;
00489    case 6: return (N2 - 1 - n2) + n1*N2;
00490    case 7: return n1 + (N2 - 1 - n2)*N1;
00491    }
00492 #ifdef MFEM_DEBUG
00493    mfem_error("NURBSPatchMap::Or2D");
00494 #endif
00495    return -1;
00496 }
00497 
00498 inline int NURBSPatchMap::operator()(const int i) const
00499 {
00500    int i1 = i - 1;
00501    switch (F(i1, I))
00502    {
00503    case 0: return verts[0];
00504    case 1: return pOffset + Or1D(i1, I, opatch);
00505    case 2: return verts[1];
00506    }
00507 #ifdef MFEM_DEBUG
00508    mfem_error("NURBSPatchMap::operator() const 1D");
00509 #endif
00510    return -1;
00511 }
00512 
00513 inline int NURBSPatchMap::operator()(const int i, const int j) const
00514 {
00515    int i1 = i - 1, j1 = j - 1;
00516    switch (3*F(j1, J) + F(i1, I))
00517    {
00518    case 0: return verts[0];
00519    case 1: return edges[0] + Or1D(i1, I, oedge[0]);
00520    case 2: return verts[1];
00521    case 3: return edges[3] + Or1D(j1, J, -oedge[3]);
00522    case 4: return pOffset + Or2D(i1, j1, I, J, opatch);
00523    case 5: return edges[1] + Or1D(j1, J, oedge[1]);
00524    case 6: return verts[3];
00525    case 7: return edges[2] + Or1D(i1, I, -oedge[2]);
00526    case 8: return verts[2];
00527    }
00528 #ifdef MFEM_DEBUG
00529    mfem_error("NURBSPatchMap::operator() const 2D");
00530 #endif
00531    return -1;
00532 }
00533 
00534 inline int NURBSPatchMap::operator()(const int i, const int j, const int k)
00535    const
00536 {
00537    // Needs testing
00538    int i1 = i - 1, j1 = j - 1, k1 = k - 1;
00539    switch (3*(3*F(k1, K) + F(j1, J)) + F(i1, I))
00540    {
00541    case  0: return verts[0];
00542    case  1: return edges[0] + Or1D(i1, I, oedge[0]);
00543    case  2: return verts[1];
00544    case  3: return edges[3] + Or1D(j1, J, oedge[3]);
00545    case  4: return faces[0] + Or2D(i1, J - 1 - j1, I, J, oface[0]);
00546    case  5: return edges[1] + Or1D(j1, J, oedge[1]);
00547    case  6: return verts[3];
00548    case  7: return edges[2] + Or1D(i1, I, oedge[2]);
00549    case  8: return verts[2];
00550    case  9: return edges[8] + Or1D(k1, K, oedge[8]);
00551    case 10: return faces[1] + Or2D(i1, k1, I, K, oface[1]);
00552    case 11: return edges[9] + Or1D(k1, K, oedge[9]);
00553    case 12: return faces[4] + Or2D(J - 1 - j1, k1, J, K, oface[4]);
00554    case 13: return pOffset + I*(J*k1 + j1) + i1;
00555    case 14: return faces[2] + Or2D(j1, k1, J, K, oface[2]);
00556    case 15: return edges[11] + Or1D(k1, K, oedge[11]);
00557    case 16: return faces[3] + Or2D(I - 1 - i1, k1, I, K, oface[3]);
00558    case 17: return edges[10] + Or1D(k1, K, oedge[10]);
00559    case 18: return verts[4];
00560    case 19: return edges[4] + Or1D(i1, I, oedge[4]);
00561    case 20: return verts[5];
00562    case 21: return edges[7] + Or1D(j1, J, oedge[7]);
00563    case 22: return faces[5] + Or2D(i1, j1, I, J, oface[5]);
00564    case 23: return edges[5] + Or1D(j1, J, oedge[5]);
00565    case 24: return verts[7];
00566    case 25: return edges[6] + Or1D(i1, I, oedge[6]);
00567    case 26: return verts[6];
00568    }
00569 #ifdef MFEM_DEBUG
00570    mfem_error("NURBSPatchMap::operator() const 3D");
00571 #endif
00572    return -1;
00573 }
00574 
00575 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines