From a9629f47c9c920b8924e29d9a59c6de9f28b2ba4 Mon Sep 17 00:00:00 2001 From: Gauthier Becker <gauthierbecker@gmail.com> Date: Thu, 24 Mar 2011 15:58:02 +0000 Subject: [PATCH] NonLinearSolver beta dgshell v 1.0 lua --> python --- CMakeLists.txt | 11 + Common/gmshpy.i | 1 - Mesh/BoundaryLayers.cpp | 30 +- Mesh/meshGFaceOptimize.cpp | 352 ++-- .../BoundaryConditions/CMakeLists.txt | 10 + .../BoundaryConditions/nonLinearBC.cpp | 11 + .../BoundaryConditions/nonLinearBC.h | 134 ++ NonLinearSolver/CMakeLists.txt | 16 +- NonLinearSolver/Domain/CMakeLists.txt | 11 + NonLinearSolver/Domain/partDomain.cpp | 83 + NonLinearSolver/Domain/partDomain.h | 220 ++ NonLinearSolver/Interface/CMakeLists.txt | 15 + NonLinearSolver/Interface/IEdge.cpp | 12 + NonLinearSolver/Interface/IEdge.h | 32 + NonLinearSolver/Interface/IElement.cpp | 12 + NonLinearSolver/Interface/IElement.h | 38 + .../Interface/InterfaceBuilder.cpp | 66 + NonLinearSolver/Interface/InterfaceBuilder.h | 66 + .../Interface/MInterfaceElement.cpp | 49 + NonLinearSolver/Interface/MInterfaceElement.h | 31 + NonLinearSolver/Interface/MInterfaceLine.cpp | 111 + NonLinearSolver/Interface/MInterfaceLine.h | 58 + NonLinearSolver/contact/CMakeLists.txt | 16 + NonLinearSolver/contact/contactDomain.cpp | 115 + NonLinearSolver/contact/contactDomain.h | 108 + .../contact/contactFunctionSpace.h | 85 + NonLinearSolver/contact/contactTerms.cpp | 51 + NonLinearSolver/contact/contactTerms.h | 80 + .../contact/nodeStiffnessContact.h | 62 + .../contact/rigidCylinderContactTerms.cpp | 188 ++ .../contact/rigidCylinderContactTerms.h | 113 + NonLinearSolver/field/CMakeLists.txt | 12 + NonLinearSolver/field/elementField.cpp | 130 ++ NonLinearSolver/field/elementField.h | 51 + NonLinearSolver/field/energyField.cpp | 173 ++ NonLinearSolver/field/energyField.h | 89 + NonLinearSolver/internalPoints/CMakeLists.txt | 3 + NonLinearSolver/internalPoints/ipField.cpp | 293 +++ NonLinearSolver/internalPoints/ipField.h | 237 +++ NonLinearSolver/internalPoints/ipstate.cpp | 124 ++ NonLinearSolver/internalPoints/ipstate.h | 74 + NonLinearSolver/internalPoints/ipvariable.h | 93 + NonLinearSolver/materialLaw/CMakeLists.txt | 11 + NonLinearSolver/materialLaw/mlaw.cpp | 26 + NonLinearSolver/materialLaw/mlaw.h | 94 + NonLinearSolver/nlTerms/CMakeLists.txt | 11 + NonLinearSolver/nlTerms/nlTerms.cpp | 130 ++ NonLinearSolver/nlTerms/nlTerms.h | 109 + NonLinearSolver/nlsolver/CMakeLists.txt | 21 + NonLinearSolver/nlsolver/Dof3IntType.h | 32 + NonLinearSolver/nlsolver/explicitDofManager.h | 304 +++ .../nlsolver/explicitHulbertChung.h | 399 ++++ NonLinearSolver/nlsolver/nlsolAlgorithms.h | 228 ++ .../nlsolver/nonLinearMechSolver.cpp | 1852 +++++++++++++++++ .../nlsolver/nonLinearMechSolver.h | 254 +++ NonLinearSolver/nlsolver/staticDofManager.h | 157 ++ NonLinearSolver/nlsolver/timeFunction.h | 83 + .../nlsolver/unknownDynamicField.cpp | 179 ++ .../nlsolver/unknownDynamicField.h | 51 + NonLinearSolver/nlsolver/unknownField.cpp | 106 + NonLinearSolver/nlsolver/unknownField.h | 64 + .../nlsolver/unknownStaticField.cpp | 298 +++ NonLinearSolver/nlsolver/unknownStaticField.h | 53 + NonLinearSolver/space/CMakeLists.txt | 11 + NonLinearSolver/space/functionSpaceType.h | 22 + Numeric/simpleFunction.h | 1 + Solver/quadratureRules.h | 13 +- Solver/terms.h | 4 +- 68 files changed, 7782 insertions(+), 197 deletions(-) create mode 100644 NonLinearSolver/BoundaryConditions/CMakeLists.txt create mode 100644 NonLinearSolver/BoundaryConditions/nonLinearBC.cpp create mode 100644 NonLinearSolver/BoundaryConditions/nonLinearBC.h create mode 100644 NonLinearSolver/Domain/CMakeLists.txt create mode 100644 NonLinearSolver/Domain/partDomain.cpp create mode 100644 NonLinearSolver/Domain/partDomain.h create mode 100644 NonLinearSolver/Interface/CMakeLists.txt create mode 100644 NonLinearSolver/Interface/IEdge.cpp create mode 100644 NonLinearSolver/Interface/IEdge.h create mode 100644 NonLinearSolver/Interface/IElement.cpp create mode 100644 NonLinearSolver/Interface/IElement.h create mode 100644 NonLinearSolver/Interface/InterfaceBuilder.cpp create mode 100644 NonLinearSolver/Interface/InterfaceBuilder.h create mode 100644 NonLinearSolver/Interface/MInterfaceElement.cpp create mode 100644 NonLinearSolver/Interface/MInterfaceElement.h create mode 100644 NonLinearSolver/Interface/MInterfaceLine.cpp create mode 100644 NonLinearSolver/Interface/MInterfaceLine.h create mode 100644 NonLinearSolver/contact/CMakeLists.txt create mode 100644 NonLinearSolver/contact/contactDomain.cpp create mode 100644 NonLinearSolver/contact/contactDomain.h create mode 100644 NonLinearSolver/contact/contactFunctionSpace.h create mode 100644 NonLinearSolver/contact/contactTerms.cpp create mode 100644 NonLinearSolver/contact/contactTerms.h create mode 100644 NonLinearSolver/contact/nodeStiffnessContact.h create mode 100644 NonLinearSolver/contact/rigidCylinderContactTerms.cpp create mode 100644 NonLinearSolver/contact/rigidCylinderContactTerms.h create mode 100644 NonLinearSolver/field/CMakeLists.txt create mode 100644 NonLinearSolver/field/elementField.cpp create mode 100644 NonLinearSolver/field/elementField.h create mode 100644 NonLinearSolver/field/energyField.cpp create mode 100644 NonLinearSolver/field/energyField.h create mode 100644 NonLinearSolver/internalPoints/ipField.cpp create mode 100644 NonLinearSolver/internalPoints/ipField.h create mode 100644 NonLinearSolver/internalPoints/ipvariable.h create mode 100644 NonLinearSolver/materialLaw/CMakeLists.txt create mode 100644 NonLinearSolver/materialLaw/mlaw.cpp create mode 100644 NonLinearSolver/materialLaw/mlaw.h create mode 100644 NonLinearSolver/nlTerms/CMakeLists.txt create mode 100644 NonLinearSolver/nlTerms/nlTerms.cpp create mode 100644 NonLinearSolver/nlTerms/nlTerms.h create mode 100644 NonLinearSolver/nlsolver/CMakeLists.txt create mode 100644 NonLinearSolver/nlsolver/Dof3IntType.h create mode 100644 NonLinearSolver/nlsolver/explicitDofManager.h create mode 100644 NonLinearSolver/nlsolver/explicitHulbertChung.h create mode 100644 NonLinearSolver/nlsolver/nlsolAlgorithms.h create mode 100644 NonLinearSolver/nlsolver/nonLinearMechSolver.cpp create mode 100644 NonLinearSolver/nlsolver/nonLinearMechSolver.h create mode 100644 NonLinearSolver/nlsolver/staticDofManager.h create mode 100644 NonLinearSolver/nlsolver/timeFunction.h create mode 100644 NonLinearSolver/nlsolver/unknownDynamicField.cpp create mode 100644 NonLinearSolver/nlsolver/unknownDynamicField.h create mode 100644 NonLinearSolver/nlsolver/unknownField.cpp create mode 100644 NonLinearSolver/nlsolver/unknownField.h create mode 100644 NonLinearSolver/nlsolver/unknownStaticField.cpp create mode 100644 NonLinearSolver/nlsolver/unknownStaticField.h create mode 100644 NonLinearSolver/space/CMakeLists.txt create mode 100644 NonLinearSolver/space/functionSpaceType.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ef9cf8feb..7c8312dfab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -281,6 +281,17 @@ add_subdirectory(Geo) if(ENABLE_NON_LINEAR_SOLVER) add_subdirectory(NonLinearSolver) + include_directories(NonLinearSolver/nlsolver) + include_directories(NonLinearSolver/BoundaryConditions) + include_directories(NonLinearSolver/contact) + include_directories(NonLinearSolver/Domain) + include_directories(NonLinearSolver/field) + include_directories(NonLinearSolver/Interface) + include_directories(NonLinearSolver/internalPoints) + include_directories(NonLinearSolver/materialLaw) + include_directories(NonLinearSolver/nlTerms) + include_directories(NonLinearSolver/space) + set_config_option(HAVE_NLMECHSOL "NlMechSol") endif(ENABLE_NON_LINEAR_SOLVER) if(ENABLE_MESH) diff --git a/Common/gmshpy.i b/Common/gmshpy.i index c225e6672e..a2b6afdd6e 100644 --- a/Common/gmshpy.i +++ b/Common/gmshpy.i @@ -128,4 +128,3 @@ namespace std { %include "functionPython.h" %include "meshGFaceLloyd.h" %include "DefaultOptions.h" - diff --git a/Mesh/BoundaryLayers.cpp b/Mesh/BoundaryLayers.cpp index 2863ab8a7b..05b58eeb66 100644 --- a/Mesh/BoundaryLayers.cpp +++ b/Mesh/BoundaryLayers.cpp @@ -22,14 +22,14 @@ class OctreePost{ int dummy; }; #endif template<class T> -static void addExtrudeNormals(std::vector<T*> &elements, int invert, +static void addExtrudeNormals(std::vector<T*> &elements, int invert, OctreePost *octree, bool gouraud, int index) { if(index < 0 || index > 1){ Msg::Error("Boundary layer index should be 0 or 1"); return; } - + if(octree && !gouraud){ // get extrusion direction from post-processing view std::set<MVertex*> verts; for(unsigned int i = 0; i < elements.size(); i++) @@ -65,7 +65,7 @@ static void addExtrudeNormals(std::vector<T*> &elements, int invert, typedef std::set<std::pair<bool, std::pair<int, int> > > infoset; template<class T> -static void addExtrudeNormals(std::set<T*> &entities, +static void addExtrudeNormals(std::set<T*> &entities, std::map<int, infoset> &infos) { bool normalize = true, special3dbox = false; @@ -80,8 +80,8 @@ static void addExtrudeNormals(std::set<T*> &entities, int view = it2->second.second; bool gouraud = true; OctreePost *octree = 0; - if(view != -1){ #if defined(HAVE_POST) + if(view != -1){ if(view >= 0 && view < PView::list.size()){ octree = new OctreePost(PView::list[view]); if(PView::list[view]->getData()->getNumVectors()) @@ -124,7 +124,7 @@ static void addExtrudeNormals(std::set<T*> &entities, for(int i = 0; i < 2; i++){ ExtrudeParams::normals[i]->normalize(); if(special3dbox){ // force normals for 3d "box" along x,y,z - for(smooth_data::iter it = ExtrudeParams::normals[i]->begin(); + for(smooth_data::iter it = ExtrudeParams::normals[i]->begin(); it != ExtrudeParams::normals[i]->end(); it++){ for(int j = 0; j < 3; j++){ if(it->vals[j] < -0.1) it->vals[j] = -1.; @@ -135,7 +135,7 @@ static void addExtrudeNormals(std::set<T*> &entities, } #if defined(HAVE_POST) if(octrees.size()){ // scale normals by scalar views - for(smooth_data::iter it = ExtrudeParams::normals[i]->begin(); + for(smooth_data::iter it = ExtrudeParams::normals[i]->begin(); it != ExtrudeParams::normals[i]->end(); it++){ for(unsigned int j = 0; j < octrees.size(); j++){ double d; @@ -177,7 +177,7 @@ int Mesh2DWithBoundaryLayers(GModel *m) // 2D boundary layers for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); it++){ GEdge *ge = *it; - if(ge->getNativeType() == GEntity::GmshModel && + if(ge->getNativeType() == GEntity::GmshModel && ge->geomType() == GEntity::BoundaryLayerCurve){ ExtrudeParams *ep = ge->meshAttributes.extrude; if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == COPIED_ENTITY){ @@ -198,7 +198,7 @@ int Mesh2DWithBoundaryLayers(GModel *m) // 3D boundary layers for(GModel::fiter it = m->firstFace(); it != m->lastFace(); it++){ GFace *gf = *it; - if(gf->getNativeType() == GEntity::GmshModel && + if(gf->getNativeType() == GEntity::GmshModel && gf->geomType() == GEntity::BoundaryLayerSurface){ ExtrudeParams *ep = gf->meshAttributes.extrude; if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == COPIED_ENTITY){ @@ -238,14 +238,14 @@ int Mesh2DWithBoundaryLayers(GModel *m) if(sourceEdges.find(*it) == sourceEdges.end()) otherEdges.insert(*it); for(GModel::fiter it = m->firstFace(); it != m->lastFace(); it++) if(sourceFaces.find(*it) == sourceFaces.end() && - sourceFacesDependencies.find(*it) == sourceFacesDependencies.end()) + sourceFacesDependencies.find(*it) == sourceFacesDependencies.end()) otherFaces.insert(*it); // mesh source surfaces (and dependencies) for(int i = 0; i < 10; i++) // FIXME: should check PENDING status instead! - std::for_each(sourceFacesDependencies.begin(), sourceFacesDependencies.end(), - meshGFace()); - std::for_each(sourceFaces.begin(), sourceFaces.end(), meshGFace()); + std::for_each(sourceFacesDependencies.begin(), sourceFacesDependencies.end(), + meshGFace()); + std::for_each(sourceFaces.begin(), sourceFaces.end(), meshGFace()); // make sure the source surfaces for the boundary layers are // oriented correctly (normally we do this only after the 3D mesh is @@ -264,7 +264,7 @@ int Mesh2DWithBoundaryLayers(GModel *m) addExtrudeNormals(sourceFaces, sourceFaceInfo); // set the position of boundary layer points using the smooth normal - // field + // field for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); it++){ GEdge *ge = *it; if(ge->geomType() == GEntity::BoundaryLayerCurve){ @@ -286,7 +286,7 @@ int Mesh2DWithBoundaryLayers(GModel *m) } } } - + // remesh non-source edges (since they might have been modified by // the change in boundary layer points) std::for_each(otherFaces.begin(), otherFaces.end(), deMeshGFace()); @@ -312,7 +312,7 @@ int Mesh2DWithBoundaryLayers(GModel *m) } // mesh non-source surfaces - std::for_each(otherFaces.begin(), otherFaces.end(), meshGFace()); + std::for_each(otherFaces.begin(), otherFaces.end(), meshGFace()); // mesh the surfaces bounding the boundary layers by extrusion using // the smooth normal field diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index 1b5c8942fe..abf7b9439f 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -27,12 +27,12 @@ #ifdef HAVE_MATCH extern "C" int FAILED_NODE; extern "C" struct CCdatagroup; -extern "C" int perfect_match -(int ncount, CCdatagroup *dat, int ecount, - int **elist, int **elen, char *blo_filename, - char *mat_filename, int just_fractional, int no_fractional, - int use_all_trees, int partialprice, - double *totalzeit) ; +extern "C" int perfect_match +(int ncount, CCdatagroup *dat, int ecount, + int **elist, int **elen, char *blo_filename, + char *mat_filename, int just_fractional, int no_fractional, + int use_all_trees, int partialprice, + double *totalzeit) ; #endif edge_angle::edge_angle(MVertex *_v1, MVertex *_v2, MElement *t1, MElement *t2) @@ -94,15 +94,15 @@ static void setLcs(MTriangle *t, std::map<MVertex*, double> &vSizes) double dy = vi->y() - vj->y(); double dz = vi->z() - vj->z(); double l = sqrt(dx * dx + dy * dy + dz * dz); - std::map<MVertex*,double>::iterator iti = vSizes.find(vi); - std::map<MVertex*,double>::iterator itj = vSizes.find(vj); + std::map<MVertex*,double>::iterator iti = vSizes.find(vi); + std::map<MVertex*,double>::iterator itj = vSizes.find(vj); if(iti->second < 0 || iti->second > l) iti->second = l; if(itj->second < 0 || itj->second > l) itj->second = l; } } } -void buildMeshGenerationDataStructures(GFace *gf, +void buildMeshGenerationDataStructures(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris, std::vector<double> &vSizes, std::vector<double> &vSizesBGM, @@ -125,7 +125,7 @@ void buildMeshGenerationDataStructures(GFace *gf, std::list<GVertex*>::iterator itvx = emb_vertx.begin(); while(itvx != emb_vertx.end()){ MVertex *v = *((*itvx)->mesh_vertices.begin()); - vSizesMap[v] = std::min(vSizesMap[v], (*itvx)->prescribedMeshSizeAtVertex()); + vSizesMap[v] = std::min(vSizesMap[v], (*itvx)->prescribedMeshSizeAtVertex()); ++itvx; } } @@ -166,7 +166,7 @@ void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris, else gf->triangles.push_back(worst->tri()); delete worst; - AllTris.erase(AllTris.begin()); + AllTris.erase(AllTris.begin()); } // make sure all the triangles are oriented in the same way in @@ -236,12 +236,12 @@ void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected, e2t_cont::iterator it = adj.begin(); for(; it != adj.end(); ++it){ if(it->second.second) - edges_detected.push_back(edge_angle(it->first.getVertex(0), - it->first.getVertex(1), + edges_detected.push_back(edge_angle(it->first.getVertex(0), + it->first.getVertex(1), it->second.first, it->second.second)); - else + else edges_lonly.push_back(edge_angle(it->first.getVertex(0), - it->first.getVertex(1), + it->first.getVertex(1), it->second.first, it->second.second)); } std::sort(edges_detected.begin(), edges_detected.end()); @@ -269,7 +269,7 @@ double surfaceFaceUV(MElement *t,GFace *gf){ 0.5*fabs((u[3]-u[2])*(v[0]-v[2])-(u[0]-u[2])*(v[3]-v[2])) ; } -double surfaceTriangleUV(MVertex *v1, MVertex *v2, MVertex *v3, +double surfaceTriangleUV(MVertex *v1, MVertex *v2, MVertex *v3, const std::vector<double> &Us, const std::vector<double> &Vs) { @@ -327,7 +327,7 @@ int _removeFourTrianglesNodes(GFace *gf,bool replace_by_quads) } } } - if(edges[0][1] == edges[1][0] && edges[1][1] == edges[2][0] && + if(edges[0][1] == edges[1][0] && edges[1][1] == edges[2][0] && edges[2][1] == edges[3][0] && edges[3][1] == edges[0][0]) { if(replace_by_quads){ gf->quadrangles.push_back(new MQuadrangle(edges[0][0], edges[1][0], @@ -341,16 +341,16 @@ int _removeFourTrianglesNodes(GFace *gf,bool replace_by_quads) surf[i] = surfaceFaceUV(newt[i],gf); qual[i] = qmTriangle(newt[i],QMTRI_RHO); } - double q02=(fabs((surf[0]+surf[2]-surfaceRef)/surfaceRef)<1e-8) ? + double q02=(fabs((surf[0]+surf[2]-surfaceRef)/surfaceRef)<1e-8) ? std::min(qual[0],qual[2]) : -1; - double q13=(fabs((surf[1]+surf[3]-surfaceRef)/surfaceRef)<1e-8) ? + double q13=(fabs((surf[1]+surf[3]-surfaceRef)/surfaceRef)<1e-8) ? std::min(qual[1],qual[3]) : -1; if(q02>q13 && q02 >0) { delete newt[1]; delete newt[3]; gf->triangles.push_back(newt[0]); gf->triangles.push_back(newt[2]); - } + } else if (q13 >0) { delete newt[0]; delete newt[2]; @@ -377,8 +377,8 @@ int _removeFourTrianglesNodes(GFace *gf,bool replace_by_quads) } else { delete gf->triangles[i]; - } - } + } + } gf->triangles = triangles2; Msg::Debug("%i four-triangles vertices removed",n); return n; @@ -416,8 +416,8 @@ static int _removeTwoQuadsNodes(GFace *gf) const std::vector<MElement*> < = it->second; MElement *q1 = it->second[0]; MElement *q2 = it->second[1]; - if (q1->getNumVertices() == 4 && - q2->getNumVertices() == 4 && + if (q1->getNumVertices() == 4 && + q2->getNumVertices() == 4 && touched.find(q1) == touched.end() && touched.find(q2) == touched.end()){ touched.insert(q1); touched.insert(q2); @@ -433,7 +433,7 @@ static int _removeTwoQuadsNodes(GFace *gf) MVertex *v3 = q1->getVertex((comm+3)%4); MVertex *v4 = 0; for (int i=0;i<4;i++){ - if (q2->getVertex(i) != v1 && q2->getVertex(i) != v2 && + if (q2->getVertex(i) != v1 && q2->getVertex(i) != v2 && q2->getVertex(i) != v3 && q2->getVertex(i) != it->first){ v4 = q2->getVertex(i); break; @@ -452,8 +452,8 @@ static int _removeTwoQuadsNodes(GFace *gf) } else { delete gf->quadrangles[i]; - } - } + } + } gf->quadrangles = quadrangles2; std::vector<MVertex*> mesh_vertices2; @@ -463,8 +463,8 @@ static int _removeTwoQuadsNodes(GFace *gf) } else { delete gf->mesh_vertices[i]; - } - } + } + } gf->mesh_vertices = mesh_vertices2; return vtouched.size(); @@ -483,19 +483,19 @@ int removeTwoQuadsNodes(GFace *gf){ static bool _isItAGoodIdeaToCollapseThatVertex (GFace *gf, - std::vector<MElement*> &e1, - std::vector<MElement*> &e2, - MElement *q, - MVertex *v1, + std::vector<MElement*> &e1, + std::vector<MElement*> &e2, + MElement *q, + MVertex *v1, MVertex *v2, - MVertex *v, + MVertex *v, double FACT){ double surface_old = surfaceFaceUV(q,gf); double surface_new = 0; // double worst_quality_old = q->etaShapeMeasure(); // double worst_quality_new = 1.0; - + double x = v->x(); double y = v->y(); double z = v->z(); @@ -515,13 +515,13 @@ static bool _isItAGoodIdeaToCollapseThatVertex (GFace *gf, // worst_quality_old = std::min(worst_quality_old,e1[j]-> etaShapeMeasure()); for (int k=0;k<e1[j]->getNumVertices();k++){ if (e1[j]->getVertex(k) == v1 && e1[j] != q) - e1[j]->setVertex(k,v); + e1[j]->setVertex(k,v); } surface_new += surfaceFaceUV(e1[j],gf); // worst_quality_new = std::min(worst_quality_new,e1[j]-> etaShapeMeasure()); for (int k=0;k<e1[j]->getNumVertices();k++){ if (e1[j]->getVertex(k) == v && e1[j] != q) - e1[j]->setVertex(k,v1); + e1[j]->setVertex(k,v1); } } @@ -536,10 +536,10 @@ static bool _isItAGoodIdeaToCollapseThatVertex (GFace *gf, // worst_quality_new = std::min(worst_quality_new,e2[j]-> etaShapeMeasure()); for (int k=0;k<e2[j]->getNumVertices();k++){ if (e2[j]->getVertex(k) == v && e2[j] != q) - e2[j]->setVertex(k,v2); + e2[j]->setVertex(k,v2); } } - + if ( fabs (surface_old - surface_new ) > 1.e-10 * surface_old) { // || FACT*worst_quality_new < worst_quality_old ) { @@ -550,16 +550,16 @@ static bool _isItAGoodIdeaToCollapseThatVertex (GFace *gf, } return true; - + } static bool _isItAGoodIdeaToMoveThatVertex (GFace *gf, - const std::vector<MElement*> &e1, - MVertex *v1, - const SPoint2 &before, + const std::vector<MElement*> &e1, + MVertex *v1, + const SPoint2 &before, const SPoint2 &after){ - + double surface_old = 0; double surface_new = 0; @@ -598,7 +598,7 @@ static bool _isItAGoodIdeaToMoveThatVertex (GFace *gf, int nBetter=0,nWorse=0; int nReallyBadOld=0,nReallyBadNew=0; for (unsigned int j=0;j<e1.size();++j){ - if (qualityNew[j] >= qualityOld[j])nBetter++; + if (qualityNew[j] >= qualityOld[j])nBetter++; else { nWorse++; } @@ -610,19 +610,19 @@ static bool _isItAGoodIdeaToMoveThatVertex (GFace *gf, if (nReallyBadOld < nReallyBadNew)return false; return (nBetter >= nWorse); - + } static int _quadWithOneVertexOnBoundary (GFace *gf, std::set<MVertex*> &touched, std::set<MElement*> &diamonds, - std::set<MVertex*> &deleted, - std::vector<MElement*> &e2, - std::vector<MElement*> &e4, - std::vector<MElement*> &e1, + std::set<MVertex*> &deleted, + std::vector<MElement*> &e2, + std::vector<MElement*> &e4, + std::vector<MElement*> &e1, MQuadrangle *q, - MVertex *v1, + MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4){ @@ -631,9 +631,9 @@ static int _quadWithOneVertexOnBoundary (GFace *gf, v2->onWhat()->dim() == 2 && v3->onWhat()->dim() == 2 && v4->onWhat()->dim() == 2 && - e2.size() < 5 && - e4.size() < 5 && - _isItAGoodIdeaToCollapseThatVertex (gf, e2, e4, q, v2, v4, v4,12.0) + e2.size() < 5 && + e4.size() < 5 && + _isItAGoodIdeaToCollapseThatVertex (gf, e2, e4, q, v2, v4, v4,12.0) /* || _isItAGoodIdeaToCollapseThatVertex (gf, e2, e4, q, v2, v4, v2,12.0))*/){ touched.insert(v1); touched.insert(v2); @@ -655,7 +655,7 @@ static int _quadWithOneVertexOnBoundary (GFace *gf, // printf("coucou %g\n",angle3Vertices(line[0],v1,line[1])*180./M_PI); return 0; } - } + } */ // if (line.size() == 2)printf("caca\n"); // else printf("hohcozbucof\n"); @@ -664,13 +664,13 @@ static int _quadWithOneVertexOnBoundary (GFace *gf, if (e2[j]->getVertex(k) == v2 && e2[j] != q) e2[j]->setVertex(k,v4); } - } + } diamonds.insert(q); deleted.insert(v2); return 1; } return 0; -} +} static int _countCommon(std::vector<MElement*> &a, std::vector<MElement*> &b) { int count = 0; @@ -698,7 +698,7 @@ static int _removeDiamonds(GFace *gf) touched.insert(gf->triangles[i]->getVertex(1)); touched.insert(gf->triangles[i]->getVertex(2)); } - + for(unsigned int i = 0; i < gf->quadrangles.size(); i++){ MQuadrangle *q = gf->quadrangles[i]; @@ -710,19 +710,19 @@ static int _removeDiamonds(GFace *gf) v2t_cont::iterator it2 = adj.find(v2); v2t_cont::iterator it3 = adj.find(v3); v2t_cont::iterator it4 = adj.find(v4); - if (touched.find(v1) == touched.end() && + if (touched.find(v1) == touched.end() && touched.find(v2) == touched.end() && touched.find(v3) == touched.end() && touched.find(v4) == touched.end() ) { if (_quadWithOneVertexOnBoundary (gf,touched,diamonds,deleted,it2->second,it4->second,it1->second,q,v1,v2,v3,v4)){} else if (_quadWithOneVertexOnBoundary (gf,touched,diamonds,deleted,it3->second,it1->second,it2->second,q,v2,v3,v4,v1)){} else if (_quadWithOneVertexOnBoundary (gf,touched,diamonds,deleted,it4->second,it2->second,it3->second,q,v3,v4,v1,v2)){} - else if (_quadWithOneVertexOnBoundary (gf,touched,diamonds,deleted,it1->second,it3->second,it4->second,q,v4,v1,v2,v3)){} - else if (v2->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && - v1->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - it1->second.size() ==3 && it3->second.size() == 3 && + else if (_quadWithOneVertexOnBoundary (gf,touched,diamonds,deleted,it1->second,it3->second,it4->second,q,v4,v1,v2,v3)){} + else if (v2->onWhat()->dim() == 2 && + v4->onWhat()->dim() == 2 && + v1->onWhat()->dim() == 2 && + v3->onWhat()->dim() == 2 && + it1->second.size() ==3 && it3->second.size() == 3 && _isItAGoodIdeaToCollapseThatVertex (gf, it1->second, it3->second, q, v1, v3, v3,10.)){ touched.insert(v1); touched.insert(v2); @@ -733,15 +733,15 @@ static int _removeDiamonds(GFace *gf) if (it1->second[j]->getVertex(k) == v1 && it1->second[j] != q) it1->second[j]->setVertex(k,v3); } - } + } deleted.insert(v1); diamonds.insert(q); - } - else if (v2->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && - v1->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - it1->second.size() ==3 && it3->second.size() == 3 && + } + else if (v2->onWhat()->dim() == 2 && + v4->onWhat()->dim() == 2 && + v1->onWhat()->dim() == 2 && + v3->onWhat()->dim() == 2 && + it1->second.size() ==3 && it3->second.size() == 3 && _isItAGoodIdeaToCollapseThatVertex (gf, it1->second, it3->second, q, v1, v3, v1,10.)){ touched.insert(v1); touched.insert(v2); @@ -752,14 +752,14 @@ static int _removeDiamonds(GFace *gf) if (it3->second[j]->getVertex(k) == v3 && it3->second[j] != q) it3->second[j]->setVertex(k,v1); } - } + } deleted.insert(v3); diamonds.insert(q); - } - else if (v1->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - v2->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && + } + else if (v1->onWhat()->dim() == 2 && + v3->onWhat()->dim() == 2 && + v2->onWhat()->dim() == 2 && + v4->onWhat()->dim() == 2 && it2->second.size() == 3 && it4->second.size() == 3 && _isItAGoodIdeaToCollapseThatVertex (gf, it2->second, it4->second, q, v2, v4, v4,10.)){ touched.insert(v1); @@ -775,10 +775,10 @@ static int _removeDiamonds(GFace *gf) deleted.insert(v2); diamonds.insert(q); } - else if (v1->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - v2->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && + else if (v1->onWhat()->dim() == 2 && + v3->onWhat()->dim() == 2 && + v2->onWhat()->dim() == 2 && + v4->onWhat()->dim() == 2 && it2->second.size() == 3 && it4->second.size() == 3 && _isItAGoodIdeaToCollapseThatVertex (gf, it2->second, it4->second, q, v2, v4, v2,10.)){ touched.insert(v1); @@ -810,8 +810,8 @@ static int _removeDiamonds(GFace *gf) } else { delete gf->mesh_vertices[i]; - } - } + } + } gf->mesh_vertices = mesh_vertices2; return diamonds.size(); @@ -831,8 +831,8 @@ int removeDiamonds(GFace *gf){ struct p1p2p3 { MVertex *p1,*p2; }; -static void _relocateVertexConstrained (GFace *gf, - MVertex *ver, +static void _relocateVertexConstrained (GFace *gf, + MVertex *ver, const std::vector<MElement*> <){ if( ver->onWhat()->dim() == 2){ @@ -906,12 +906,12 @@ static void _relocateVertexConstrained (GFace *gf, ver->y() = pt.y(); ver->z() = pt.z(); } - } + } } } -static void _relocateVertex (GFace *gf, - MVertex *ver, +static void _relocateVertex (GFace *gf, + MVertex *ver, const std::vector<MElement*> <){ double R; SPoint3 c; bool isSphere = gf->isSphere(R,c); if( ver->onWhat()->dim() == 2){ @@ -935,7 +935,7 @@ static void _relocateVertex (GFace *gf, XX += lt[i]->getVertex(3)->x(); YY += lt[i]->getVertex(3)->y(); ZZ += lt[i]->getVertex(3)->z(); - } + } fact += lt[i]->getNumVertices(); } if(fact != 0.0){ @@ -967,7 +967,7 @@ static void _relocateVertex (GFace *gf, } } } - + void laplaceSmoothing(GFace *gf, int niter) { v2t_cont adj; @@ -978,7 +978,7 @@ void laplaceSmoothing(GFace *gf, int niter) while (it != adj.end()){ _relocateVertex(gf,it->first,it->second); ++it; - } + } } } @@ -992,7 +992,7 @@ void laplaceSmoothingConstrained(GFace *gf) while (it != adj.end()){ _relocateVertexConstrained(gf,it->first,it->second); ++it; - } + } } } @@ -1002,15 +1002,15 @@ int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { e2t_cont adj; // buildEdgeToElement(gf->triangles, adj); buildEdgeToElement(gf->quadrangles, adj); - + std::vector<MQuadrangle*>created; std::set<MElement*>deleted; int COUNT = 0; for(e2t_cont::iterator it = adj.begin(); it!= adj.end(); ++it){ - if(it->second.second && - it->second.first->getNumVertices() == 4 && + if(it->second.second && + it->second.first->getNumVertices() == 4 && it->second.second->getNumVertices() == 4){ MVertex *v1 = it->first.getVertex(0); MVertex *v2 = it->first.getVertex(1); @@ -1019,7 +1019,7 @@ int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { double worst_quality_old = std::min(e1->etaShapeMeasure(),e2->etaShapeMeasure()); - if (worst_quality_old < .1 && ( + if (worst_quality_old < .1 && ( deleted.find(e1) == deleted.end() || deleted.find(e2) == deleted.end())){ MVertex *v12,*v11,*v22,*v21; @@ -1034,7 +1034,7 @@ int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { if (ed.getVertex(1) == v1 && ed.getVertex(0) != v2)v21 = ed.getVertex(0); if (ed.getVertex(0) == v2 && ed.getVertex(1) != v1)v22 = ed.getVertex(1); if (ed.getVertex(1) == v2 && ed.getVertex(0) != v1)v22 = ed.getVertex(0); - } + } MQuadrangle *q1A = new MQuadrangle (v11,v22,v2,v12); MQuadrangle *q2A = new MQuadrangle (v22,v11,v1,v21); @@ -1081,8 +1081,8 @@ int _edgeSwapQuadsForBetterQuality ( GFace *gf ) { } else { delete gf->quadrangles[i]; - } - } + } + } gf->quadrangles = created; return COUNT; } @@ -1122,7 +1122,7 @@ int postProcessExtraEdges (GFace *gf, std::vector<std::pair<MElement*,MElement*> } } if (common){ - + deleted.insert(t1); deleted.insert(t2); v2t_cont :: iterator it = adj.find(common); @@ -1165,7 +1165,7 @@ int postProcessExtraEdges (GFace *gf, std::vector<std::pair<MElement*,MElement*> t2->getVertex((start2+1)%3), t2->getVertex(start2)); - + MQuadrangle *q2 = new MQuadrangle(); std::vector<MElement*> newAdj; newAdj.push_back(q1); @@ -1175,12 +1175,12 @@ int postProcessExtraEdges (GFace *gf, std::vector<std::pair<MElement*,MElement*> newAdj.push_back(it->second[k]); } gf->quadrangles.insert(q1); - gf->quadrangles.insert(q2); + gf->quadrangles.insert(q2); _relocateVertex(gf,newVertex,newAdj); } } } - + std::vector<MTriangle*>remained; for(unsigned int i = 0; i < gf->triangles.size(); i++){ if(deleted.find(gf->triangles[i]) == deleted.end()){ @@ -1188,15 +1188,15 @@ int postProcessExtraEdges (GFace *gf, std::vector<std::pair<MElement*,MElement*> } else { delete gf->triangles[i]; - } - } + } + } gf->triangles = remained; */ return 0; } bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, - std::vector<MTri3*> &newTris, const swapCriterion &cr, + std::vector<MTri3*> &newTris, const swapCriterion &cr, const std::vector<double> &Us, const std::vector<double> &Vs, const std::vector<double> &vSizes, const std::vector<double> &vSizesBGM) { @@ -1210,27 +1210,27 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, for(int i = 0; i < 3; i++) if(t2->tri()->getVertex(i) != v1 && t2->tri()->getVertex(i) != v2) v4 = t2->tri()->getVertex(i); - + swapquad sq (v1, v2, v3, v4); if(configs.find(sq) != configs.end()) return false; configs.insert(sq); - const double volumeRef = surfaceTriangleUV(v1, v2, v3, Us, Vs) + + const double volumeRef = surfaceTriangleUV(v1, v2, v3, Us, Vs) + surfaceTriangleUV(v1, v2, v4, Us, Vs); - MTriangle *t1b = new MTriangle(v2, v3, v4); - MTriangle *t2b = new MTriangle(v4, v3, v1); + MTriangle *t1b = new MTriangle(v2, v3, v4); + MTriangle *t2b = new MTriangle(v4, v3, v1); const double v1b = surfaceTriangleUV(v2, v3, v4, Us, Vs); const double v2b = surfaceTriangleUV(v4, v3, v1, Us, Vs); const double volume = v1b + v2b; - if(fabs(volume - volumeRef) > 1.e-10 * (volume + volumeRef) || + if(fabs(volume - volumeRef) > 1.e-10 * (volume + volumeRef) || v1b < 1.e-8 * (volume + volumeRef) || v2b < 1.e-8 * (volume + volumeRef)){ delete t1b; delete t2b; return false; } - + switch(cr){ case SWCR_QUAL: { @@ -1247,9 +1247,9 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, } case SWCR_DEL: { - double edgeCenter[2] ={(Us[v1->getIndex()] + Us[v2->getIndex()] + Us[v3->getIndex()] + + double edgeCenter[2] ={(Us[v1->getIndex()] + Us[v2->getIndex()] + Us[v3->getIndex()] + Us[v4->getIndex()]) * .25, - (Vs[v1->getIndex()] + Vs[v2->getIndex()] + Vs[v3->getIndex()] + + (Vs[v1->getIndex()] + Vs[v2->getIndex()] + Vs[v3->getIndex()] + Vs[v4->getIndex()]) * .25}; double uv4[2] ={Us[v4->getIndex()], Vs[v4->getIndex()]}; double metric[3]; @@ -1258,7 +1258,7 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, delete t1b; delete t2b; return false; - } + } } break; case SWCR_CLOSE: @@ -1267,12 +1267,12 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, (v1->z() + v2->z()) *.5}; double avg2[3] = {(v3->x() + v4->x()) *.5,(v3->y() + v4->y()) *.5, (v3->z() + v4->z()) *.5}; - + GPoint gp1 = gf->point(SPoint2((Us[v1->getIndex()] + Us[v2->getIndex()]) * .5, (Vs[v1->getIndex()] + Vs[v2->getIndex()]) * .5)); GPoint gp2 = gf->point(SPoint2((Us[v3->getIndex()] + Us[v4->getIndex()]) * .5, (Vs[v3->getIndex()] + Vs[v4->getIndex()]) * .5)); - double d1 = (avg1[0] - gp1.x()) * (avg1[0] - gp1.x()) + (avg1[1] - gp1.y()) * + double d1 = (avg1[0] - gp1.x()) * (avg1[0] - gp1.x()) + (avg1[1] - gp1.y()) * (avg1[1]-gp1.y()) + (avg1[2] - gp1.z()) * (avg1[2] - gp1.z()); double d2 = (avg2[0] - gp2.x()) * (avg2[0] - gp2.x()) + (avg2[1] - gp2.y()) * (avg2[1] - gp2.y()) + (avg2[2] - gp2.z()) * (avg2[2] - gp2.z()); @@ -1280,7 +1280,7 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, delete t1b; delete t2b; return false; - } + } } break; default : @@ -1289,8 +1289,8 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, } std::list<MTri3*> cavity; - for(int i = 0; i < 3; i++){ - if(t1->getNeigh(i) && t1->getNeigh(i) != t2){ + for(int i = 0; i < 3; i++){ + if(t1->getNeigh(i) && t1->getNeigh(i) != t2){ bool found = false; for(std::list<MTri3*>::iterator it = cavity.begin(); it != cavity.end(); it++){ if(*it == t1->getNeigh(i)) found = true; @@ -1298,8 +1298,8 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, if(!found)cavity.push_back(t1->getNeigh(i)); } } - for(int i = 0; i < 3; i++){ - if(t2->getNeigh(i) && t2->getNeigh(i) != t1){ + for(int i = 0; i < 3; i++){ + if(t2->getNeigh(i) && t2->getNeigh(i) != t1){ bool found = false; for(std::list<MTri3*>::iterator it = cavity.begin(); it != cavity.end(); it++){ if(*it == t2->getNeigh(i)) found = true; @@ -1319,7 +1319,7 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, double lcBGM2 = 0.3333333333 * (vSizesBGM[t2b->getVertex(0)->getIndex()] + vSizesBGM[t2b->getVertex(1)->getIndex()] + vSizesBGM[t2b->getVertex(2)->getIndex()]); - MTri3 *t1b3 = new MTri3(t1b, Extend1dMeshIn2dSurfaces() ? + MTri3 *t1b3 = new MTri3(t1b, Extend1dMeshIn2dSurfaces() ? std::min(lc1, lcBGM1) : lcBGM1); MTri3 *t2b3 = new MTri3(t2b, Extend1dMeshIn2dSurfaces() ? std::min(lc2, lcBGM2) : lcBGM2); @@ -1367,7 +1367,7 @@ int edgeSwapPass(GFace *gf, std::set<MTri3*, compareTri3Ptr> &allTris, allTris.insert(newTris.begin(), newTris.end()); nbSwapTot += nbSwap; if(nbSwap == 0) break; - } + } return nbSwapTot; } @@ -1378,11 +1378,11 @@ inline double computeEdgeAdimLength(MVertex *v1, MVertex *v2, GFace *f, const std::vector<double> &Vs, const std::vector<double> &vSizes , const std::vector<double> &vSizesBGM) -{ +{ const double edgeCenter[2] ={(Us[v1->getIndex()] + Us[v2->getIndex()]) * .5, (Vs[v1->getIndex()] + Vs[v2->getIndex()]) * .5}; GPoint GP = f->point (edgeCenter[0], edgeCenter[1]); - + const double dx1 = v1->x() - GP.x(); const double dy1 = v1->y() - GP.y(); const double dz1 = v1->z() - GP.z(); @@ -1425,7 +1425,7 @@ void computeNeighboringTrisOfACavity(const std::vector<MTri3*> &cavity, } } } - + bool buildVertexCavity(MTri3 *t, int iLocalVertex, MVertex **v1, std::vector<MTri3*> &cavity, std::vector<MTri3*> &outside, std::vector<MVertex*> &ring) @@ -1453,10 +1453,10 @@ bool buildVertexCavity(MTri3 *t, int iLocalVertex, MVertex **v1, return true; } if(!t) return false; - if(t->isDeleted()){ + if(t->isDeleted()){ Msg::Error("Impossible to build vertex cavity"); return false; - } + } cavity.push_back(t); for(int j = 0; j < 3; j++){ if(t->tri()->getVertex(j) !=lastinring && t->tri()->getVertex(j) != *v1){ @@ -1478,7 +1478,7 @@ bool buildVertexCavity(MTri3 *t, int iLocalVertex, MVertex **v1, // split one triangle into 3 triangles then apply edge swop (or not) -// will do better (faster) soon, just to test +// will do better (faster) soon, just to test void _triangleSplit (GFace *gf, MElement *t, bool swop = false) { MVertex *v1 = t->getVertex(0); MVertex *v2 = t->getVertex(1); @@ -1487,19 +1487,19 @@ void _triangleSplit (GFace *gf, MElement *t, bool swop = false) { reparamMeshEdgeOnFace(v1, v2, gf, p1,p2); reparamMeshEdgeOnFace(v1, v3, gf, p1,p3); - + SPoint2 np = (p1+p2+p3)*(1./3.0); GPoint gp = gf->point(np); MFaceVertex *fv = new MFaceVertex(gp.x(),gp.y(),gp.z(), - gf,np.x(),np.y()); + gf,np.x(),np.y()); std::vector<MTriangle*> triangles2; for(unsigned int i = 0; i < gf->triangles.size(); i++){ if(gf->triangles[i] != t){ triangles2.push_back(gf->triangles[i]); } - } + } delete t; MTriangle *t1 = new MTriangle(v1,v2,fv); MTriangle *t2 = new MTriangle(v2,v3,fv); @@ -1525,7 +1525,7 @@ struct RecombineTriangle { n1 = me.getVertex(0); n2 = me.getVertex(1); - + if(t1->getVertex(0) != n1 && t1->getVertex(0) != n2) n3 = t1->getVertex(0); else if(t1->getVertex(1) != n1 && t1->getVertex(1) != n2) n3 = t1->getVertex(1); else if(t1->getVertex(2) != n1 && t1->getVertex(2) != n2) n3 = t1->getVertex(2); @@ -1600,23 +1600,23 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) std::vector<RecombineTriangle> pairs; int nbValidPairs = 0; for(e2t_cont::iterator it = adj.begin(); it!= adj.end(); ++it){ - if(it->second.second && - it->second.first->getNumVertices() == 3 && + if(it->second.second && + it->second.first->getNumVertices() == 3 && it->second.second->getNumVertices() == 3 && (emb_edgeverts.find(it->first.getVertex(0)) == emb_edgeverts.end() || emb_edgeverts.find(it->first.getVertex(1)) == emb_edgeverts.end())){ - + pairs.push_back(RecombineTriangle(it->first, it->second.first, it->second.second)); } - else if (!it->second.second && + else if (!it->second.second && it->second.first->getNumVertices() == 3){ for (int i=0;i<2;i++){ MVertex *v = it->first.getVertex(i); std::map<MVertex*,std::pair<MElement*,MElement*> > :: iterator itv = makeGraphPeriodic.find(v); if (itv == makeGraphPeriodic.end()){ - makeGraphPeriodic[v] = std::make_pair(it->second.first,(MElement*)0); + makeGraphPeriodic[v] = std::make_pair(it->second.first,(MElement*)0); } else{ if ( itv->second.first != it->second.first) @@ -1631,7 +1631,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) std::sort(pairs.begin(),pairs.end()); std::set<MElement*> touched; - + if(CTX::instance()->mesh.algoRecombine == 1){ #ifdef HAVE_MATCH int ncount = gf->triangles.size(); @@ -1645,7 +1645,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) for (unsigned int i=0;i<gf->triangles.size();++i){ t2n[gf->triangles[i]] = i; n2t[i] = gf->triangles[i]; - } + } int *elist = new int [2*ecount]; int *elen = new int [ecount]; @@ -1666,7 +1666,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) if (angle > M_PI/2) angle -= M_PI/2; } //elen [i] = (int) 180. * fabs(angle-M_PI/4)/M_PI; - + int NB = 0; if (pairs[i].n1->onWhat()->dim() < 2)NB++; if (pairs[i].n2->onWhat()->dim() < 2)NB++; @@ -1674,7 +1674,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) if (pairs[i].n4->onWhat()->dim() < 2)NB++; if (elen[i] > 60 && NB > 2) {elen[i] = 1000;} } - + if (cubicGraph){ std::map<MVertex*,std::pair<MElement*,MElement*> > :: iterator itv = makeGraphPeriodic.begin(); int CC = pairs.size(); @@ -1706,11 +1706,11 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) std::vector<MTriangle*> triangles2; for (unsigned int i=0;i<pairs.size();++i){ RecombineTriangle &rt = pairs[i]; - if ((rt.n1->onWhat()->dim() < 2 && + if ((rt.n1->onWhat()->dim() < 2 && rt.n2->onWhat()->dim() < 2) || (recur_level > 10 && i < 10) ){ - if (removed.find(rt.t1) == removed.end() && + if (removed.find(rt.t1) == removed.end() && removed.find(rt.t2) == removed.end() ){ removed.insert(rt.t1); removed.insert(rt.t2); @@ -1719,7 +1719,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) SPoint2 np = (p1+p2)*(1./2.0); GPoint gp = gf->point(np); MFaceVertex *newv = new MFaceVertex(gp.x(),gp.y(),gp.z(), - gf,np.x(),np.y()); + gf,np.x(),np.y()); MTriangle *t1 = new MTriangle(rt.n1,rt.n4,newv); MTriangle *t2 = new MTriangle(rt.n4,rt.n2,newv); MTriangle *t3 = new MTriangle(rt.n2,rt.n3,newv); @@ -1743,7 +1743,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) // for (int i=0;i<tos.size();i++)_triangleSplit (gf,tos[i]); // gf->model()->writeMSH("chplit.msh"); free(elist); - return _recombineIntoQuads(gf, recur_level+1); + return _recombineIntoQuads(gf, recur_level+1); } else { Msg::Error("Perfect Match Finally Failed in Quadrangulation, Try Something Else"); @@ -1755,7 +1755,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) // TEST std::vector<std::pair<MElement*,MElement*> > toProcess; for (int k=0;k<elist[0];k++){ - int i1 = elist[1+3*k],i2 = elist[1+3*k+1],an=elist[1+3*k+2]; + int i1 = elist[1+3*k],i2 = elist[1+3*k+1],an=elist[1+3*k+2]; // FIXME !! if (an == 100000){// || an == 1000){ toProcess.push_back(std::make_pair(n2t[i1],n2t[i2])); @@ -1774,7 +1774,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) t1->getVertex(2) != t2->getVertex(i)){ other = t2->getVertex(i); break; - } + } } int start; for(int i = 0; i < 3; i++) { @@ -1783,7 +1783,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) t2->getVertex(2) != t1->getVertex(i)){ start=i; break; - } + } } MQuadrangle *q = new MQuadrangle(t1->getVertex(start), t1->getVertex((start+1)%3), @@ -1796,9 +1796,9 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) free(elist); pairs.clear(); if (recur_level == 0) - Msg::Debug("Perfect Match Succeeded in Quadrangulation (%g sec)",matzeit); + Msg::Debug("Perfect Match Succeeded in Quadrangulation (%g sec)",matzeit); else - Msg::Info(" :-) Perfect Match Succeeded in Quadrangulation after Splits (%g sec)",matzeit); + Msg::Info(" :-) Perfect Match Succeeded in Quadrangulation after Splits (%g sec)",matzeit); } } #else @@ -1846,13 +1846,13 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) } else { delete gf->triangles[i]; - } - } + } + } gf->triangles = triangles2; return success; } -void recombineIntoQuads(GFace *gf, +void recombineIntoQuads(GFace *gf, bool topologicalOpti, bool nodeRepositioning) { @@ -1871,11 +1871,11 @@ void recombineIntoQuads(GFace *gf, // gf->addLayersOfQuads(1, 0); gf->model()->writeMSH("raw.msh"); - if(haveParam && nodeRepositioning) + if(haveParam && nodeRepositioning) laplaceSmoothing(gf, CTX::instance()->mesh.nbSmoothing); // blossom-quad algo - if(success && CTX::instance()->mesh.algoRecombine == 1){ + if(success && CTX::instance()->mesh.algoRecombine == 1){ if(topologicalOpti){ if(haveParam){ gf->model()->writeMSH("smoothed.msh"); @@ -1913,7 +1913,7 @@ void recombineIntoQuads(GFace *gf, Msg::Info("Simple recombination algorithm completed (%g s)", t2 - t1); } -// give it a try : add one quad layer on the +// give it a try : add one quad layer on the /* void addOneLayerOnContour(GFace *gf, GVertex *gv){ , int nbLayers, double hplus, double factor){ @@ -1928,14 +1928,14 @@ void addOneLayerOnContour(GFace *gf, GVertex *gv){ std::list<GEdge*> ed; for (GEdgeLoop::iter it2 = it->begin(); it2 != it->end(); ++it2){ if (it2->ge->getBeginVertex() == gv || it2->ge->getEndVertex() == gv) { - found = true; + found = true; } ed.push_back(it2->ge); } // we found an edge loop with the GVertex that was specified if (found){ // compute model vertices that will produce fans - for (GEdgeLoop::iter it2 = it->begin(); it2 != it->end(); ++it2){ + for (GEdgeLoop::iter it2 = it->begin(); it2 != it->end(); ++it2){ GEdgeLoop::iter it3 = it2; ++it3; GVertex *gv = it2->getEndVertex(); GEdgeSigned *before,*after = *it2; @@ -1944,8 +1944,8 @@ void addOneLayerOnContour(GFace *gf, GVertex *gv){ } else{ before = *it2; - } - } + } + } for (std::list<GEdge*>::iterator it = ed.begin(); it != ed.end(); ++it){ GEdge *ge = *it; @@ -1961,7 +1961,7 @@ void addOneLayerOnContour(GFace *gf, GVertex *gv){ duplicates[v] = vd[j]; gf->mesh_vertices.push_back(vd[j]); } - else + else vd[j] = itv->second; } newQuads.push_back(new MQuadrangle(ge->lines[i]->getVertex(0), ge->lines[i]->getVertex(1),vd[1],vd[0])); @@ -1999,7 +1999,7 @@ void addOneLayerOnContour(GFace *gf, GVertex *gv){ newTris.push_back(new MTriangle(vs[0],vs[1],vs[2])); delete t; } - + gf->triangles = newTris; gf->quadrangles = newQuads; } @@ -2017,8 +2017,8 @@ void quadsToTriangles(GFace *gf, double minqual = -10000.) MTriangle *t12 = new MTriangle (q->getVertex(2),q->getVertex(3),q->getVertex(0)); MTriangle *t21 = new MTriangle (q->getVertex(1),q->getVertex(2),q->getVertex(3)); MTriangle *t22 = new MTriangle (q->getVertex(3),q->getVertex(0),q->getVertex(1)); - double qual1 = std::min(t11->gammaShapeMeasure(),t12->gammaShapeMeasure()); - double qual2 = std::min(t21->gammaShapeMeasure(),t22->gammaShapeMeasure()); + double qual1 = std::min(t11->gammaShapeMeasure(),t12->gammaShapeMeasure()); + double qual2 = std::min(t21->gammaShapeMeasure(),t22->gammaShapeMeasure()); double surf1 = surfaceFaceUV(t11,gf) + surfaceFaceUV(t12,gf); double surf2 = surfaceFaceUV(t21,gf) + surfaceFaceUV(t22,gf); @@ -2044,26 +2044,26 @@ void quadsToTriangles(GFace *gf, double minqual = -10000.) } } gf->quadrangles = qds; -} +} void recombineIntoQuadsIterative(GFace *gf) { recombineIntoQuads(gf); - quadsToTriangles(gf,0.03); + quadsToTriangles(gf,0.03); return; int COUNT = 0; while (1){ - quadsToTriangles(gf); + quadsToTriangles(gf); {char NAME[245];sprintf(NAME,"iterT%d.msh",COUNT); gf->model()->writeMSH(NAME);} std::set<MTri3*,compareTri3Ptr> AllTris; std::vector<double> vSizes, vSizesBGM, Us, Vs; std::vector<SMetric3> vMetricsBGM; // buildMeshGenerationDataStructures - // (gf, AllTris, vSizes, vSizesBGM, vMetricsBGM, Us, Vs); + // (gf, AllTris, vSizes, vSizesBGM, vMetricsBGM, Us, Vs); // int nbSwaps = edgeSwapPass(gf, AllTris, SWCR_DEL, Us, Vs, vSizes, vSizesBGM); - // transferDataStructure(gf, AllTris, Us, Vs); + // transferDataStructure(gf, AllTris, Us, Vs); {char NAME[245];sprintf(NAME,"iterTD%d.msh",COUNT); gf->model()->writeMSH(NAME);} - recombineIntoQuads(gf,false,true); + recombineIntoQuads(gf,false,true); {char NAME[245];sprintf(NAME,"iter%d.msh",COUNT++); gf->model()->writeMSH(NAME);} if (COUNT == 5)break; } @@ -2174,7 +2174,7 @@ double Temporary::compute_alignment(const MEdge&_edge, MElement*element1, MEleme scalar_productA = fabs(dot(gradient,edge)); scalar_productB = fabs(dot(other_vector,edge)); alignment = std::max(scalar_productA,scalar_productB) - sqrt(2.0)/2.0; - alignment = alignment/(1.0-sqrt(2.0)/2.0); + alignment = alignment/(1.0-sqrt(2.0)/2.0); return alignment; } @@ -2183,7 +2183,7 @@ void Temporary::read_data(std::string file_name){ double x,y,z; MElement*element; PView*view; - PViewData*data; + PViewData*data; PView::readMSH(file_name,-1); std::vector<PView*> list = PView::list; data = list[0]->getData(); @@ -2229,5 +2229,5 @@ void Temporary::registerBindings(binding *b){ cm->setDescription("This function creates the quad mesh."); cm->setArgNames("file_name","w1","w2","w3",NULL); } - + diff --git a/NonLinearSolver/BoundaryConditions/CMakeLists.txt b/NonLinearSolver/BoundaryConditions/CMakeLists.txt new file mode 100644 index 0000000000..65a1b09c13 --- /dev/null +++ b/NonLinearSolver/BoundaryConditions/CMakeLists.txt @@ -0,0 +1,10 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. +set(SRC + nonLinearBC.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/BoundaryConditions "${SRC};${HDR}") diff --git a/NonLinearSolver/BoundaryConditions/nonLinearBC.cpp b/NonLinearSolver/BoundaryConditions/nonLinearBC.cpp new file mode 100644 index 0000000000..3ad2307300 --- /dev/null +++ b/NonLinearSolver/BoundaryConditions/nonLinearBC.cpp @@ -0,0 +1,11 @@ +// +// +// Description: Class to set Boundary Conditions +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "nonLinearBC.h" diff --git a/NonLinearSolver/BoundaryConditions/nonLinearBC.h b/NonLinearSolver/BoundaryConditions/nonLinearBC.h new file mode 100644 index 0000000000..835cdd359f --- /dev/null +++ b/NonLinearSolver/BoundaryConditions/nonLinearBC.h @@ -0,0 +1,134 @@ +// +// +// Description: Class to set Boundary Conditions +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// Has to be regroup with BoundaryCondition defined in elasticitySolver.h These BC have to be defined in a separated file +// I add nonLinear above to avoid ambiguities +#ifndef NONLINEARBC_H_ +#define NONLINEARBC_H_ +#ifndef SWIG +#include "groupOfElements.h" +#include "simpleFunction.h" +#include "SVector3.h" +#include "quadratureRules.h" +#include "timeFunction.h" +#include "contactFunctionSpace.h" +#include "solverAlgorithms.h" // change this +class nonLinearBoundaryCondition +{ + public: + enum location{UNDEF,ON_VERTEX,ON_EDGE,ON_FACE,ON_VOLUME,PRESSURE,RIGIDCONTACT}; + location onWhat; // on vertices or elements + int _tag; // tag for the dofManager + groupOfElements *g; // support for this BC + nonLinearBoundaryCondition() : g(0),_tag(0),onWhat(UNDEF) {}; + nonLinearBoundaryCondition(const nonLinearBoundaryCondition &source){ + this->onWhat = source.onWhat; + this->_tag = source._tag; + this->g = source.g; + } +}; + +class nonLinearDirichletBC : public nonLinearBoundaryCondition +{ + public: + int _comp; // component + simpleFunctionTime<double> _f; + FilterDof *_filter; + FunctionSpaceBase *_space; + nonLinearDirichletBC() : nonLinearBoundaryCondition(),_comp(0),_f(0), _space(NULL), _filter(NULL){} + nonLinearDirichletBC(const nonLinearDirichletBC &source) : nonLinearBoundaryCondition(source){ + this->_comp = source._comp; + this->_f = source._f; + this->_space = source._space; + this->_filter = source._filter; + } +}; + +// group will be not used but allow to store in same vector +// tag == Master physical number +class rigidContactBC : public nonLinearBoundaryCondition +{ + public: + rigidContactSpace *space; + int _comp; // component + simpleFunctionTime<double> _f; + rigidContactBC(const int physMaster) : nonLinearBoundaryCondition(){ + _tag = physMaster; + onWhat = RIGIDCONTACT; + } + rigidContactBC(const rigidContactBC &source) : nonLinearBoundaryCondition(source) + { + _comp = source._comp; + space = source.space; + _f = source._f; + } + ~rigidContactBC(){} + void setSpace(rigidContactSpace *sp){space = sp;} +}; +#endif +class nonLinearNeumannBC : public nonLinearBoundaryCondition +{ + public: + simpleFunction<double> *_f; + QuadratureBase* integ; // given by partDomain + FunctionSpaceBase *_space; // given by partDomain + LinearTermBase<double> *_term; // given by partDomain + int _comp; // component x, y or z to create function space + nonLinearNeumannBC () : nonLinearBoundaryCondition(),_f(NULL), integ(NULL), _space(NULL), _term(NULL) {} + nonLinearNeumannBC (const int tag, const int ow, simpleFunction<double>* f): nonLinearBoundaryCondition(), _f(f), + integ(NULL), _space(NULL), _term(NULL), + _comp(0) + { + _tag = tag; + switch(ow){ + case 0: + this->onWhat = nonLinearBoundaryCondition::UNDEF; + break; + case 1: + this->onWhat = nonLinearBoundaryCondition::ON_VERTEX; + g = new groupOfElements(0,tag); + break; + case 2: + onWhat = nonLinearBoundaryCondition::ON_EDGE; + g = new groupOfElements(1,tag); + break; + case 3: + onWhat = nonLinearBoundaryCondition::ON_FACE; + g = new groupOfElements(2,tag); + break; + case 4: + onWhat = nonLinearBoundaryCondition::ON_VOLUME; + g = new groupOfElements(3,tag); + break; + case 5: + onWhat = nonLinearBoundaryCondition::PRESSURE; + g = new groupOfElements(2,tag); + break; + } + } + nonLinearNeumannBC(const nonLinearNeumannBC &source) : _f(source._f), nonLinearBoundaryCondition(source), + integ(source.integ), _space(source._space), _term(source._term), + _comp(source._comp){} +}; +#ifndef SWIG +class initialCondition : public nonLinearDirichletBC { + public: + enum whichCondition{position=0, velocity=1, acceleration=2}; + double _value; + whichCondition _wc; + initialCondition(double val, int comp, whichCondition wc) : nonLinearDirichletBC(), _value(val), _wc(wc){_comp=comp;} + ~initialCondition(){} + initialCondition(const initialCondition &source) : nonLinearDirichletBC(source){ + _value = source._value; + _wc = source._wc; + } +}; +#endif +#endif // non linear Boundary Conditions diff --git a/NonLinearSolver/CMakeLists.txt b/NonLinearSolver/CMakeLists.txt index 3e9576d382..98fcf560fa 100644 --- a/NonLinearSolver/CMakeLists.txt +++ b/NonLinearSolver/CMakeLists.txt @@ -3,11 +3,25 @@ # See the LICENSE.txt file for license information. Please report all # bugs and problems to <gmsh@geuz.org>. + +add_subdirectory(BoundaryConditions) +add_subdirectory(contact) +add_subdirectory(Domain) +add_subdirectory(field) +add_subdirectory(Interface) add_subdirectory(internalPoints) -include_directories(internalPoints) +add_subdirectory(materialLaw) +add_subdirectory(nlTerms) +add_subdirectory(nlsolver) +add_subdirectory(space) + append_gmsh_src(NonLinearSolver "${SRC};${HDR}") set(GMSH_DIRS ${GMSH_DIRS};NonLinearSolver PARENT_SCOPE) +# add pragma to compile nlmechsolpy.i in gmshpy.i +# no if because here it is sure to used NonLinearSolver +set(MAKE_C_FLAGS " ${CMAKE_C_FLAGS} -D_HAVE_NLMECHSOL") +set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -D_HAVE_NLMECHSOL") diff --git a/NonLinearSolver/Domain/CMakeLists.txt b/NonLinearSolver/Domain/CMakeLists.txt new file mode 100644 index 0000000000..cf481ee811 --- /dev/null +++ b/NonLinearSolver/Domain/CMakeLists.txt @@ -0,0 +1,11 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + partDomain.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/Domain "${SRC};${HDR}") diff --git a/NonLinearSolver/Domain/partDomain.cpp b/NonLinearSolver/Domain/partDomain.cpp new file mode 100644 index 0000000000..4db73cdf4c --- /dev/null +++ b/NonLinearSolver/Domain/partDomain.cpp @@ -0,0 +1,83 @@ +// +// C++ Interface: partDomain +// +// Description: Interface class to used solver. Your term ha to be store in a domain +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "partDomain.h" +partDomain::partDomain(const partDomain &source){ + _tag = source._tag; + _phys = source._phys; + _fullDg = source._fullDg; + btermBulk = source.btermBulk; + massterm = source.massterm; + ltermBulk = source.ltermBulk; + integBulk = source.integBulk; + g = source.g; + allDirichlet = source.allDirichlet; + allNeumann = source.allNeumann; + allInitial = source.allInitial; + _bmbp = source._bmbp; + _eps= source._eps; + _wsp = source._wsp; + setmaterial = source.setmaterial; +} + +partDomain& partDomain::operator=(const partDomain &source) +{ + _tag = source._tag; + _phys = source._phys; + _fullDg = source._fullDg; + btermBulk = source.btermBulk; + massterm = source.massterm; + ltermBulk = source.ltermBulk; + integBulk = source.integBulk; + g = source.g; + allDirichlet = source.allDirichlet; + allNeumann = source.allNeumann; + allInitial = source.allInitial; + _wsp = source._wsp; + _bmbp = source._bmbp; + _eps = source._eps; + setmaterial = source.setmaterial; + return *this; +} + +dgPartDomain::dgPartDomain(const dgPartDomain &source) : partDomain(source){ + btermBound = source.btermBound; + ltermBound = source.ltermBound; + btermVirtBound = source.btermVirtBound; + ltermVirtBound = source.ltermVirtBound; + integBound = source.integBound; + gi = source.gi; + gib = source.gib; + giv = source.giv; + _interByPert = source._interByPert; + _virtByPert = source._virtByPert; +} + +dgPartDomain& dgPartDomain::operator=(dgPartDomain &source) +{ + this->partDomain::operator=(source); + btermBound = source.btermBound; + ltermBound = source.ltermBound; + btermVirtBound = source.btermVirtBound; + ltermVirtBound = source.ltermVirtBound; + integBound = source.integBound; + gi = source.gi; + gib = source.gib; + giv = source.giv; + _interByPert = source._interByPert; + _virtByPert = source._virtByPert; + return *this; +} + +void partDomain::setBulkMatrixByPerturbation(const int i, const double eps) +{ + i == 0 ? _bmbp = false : _bmbp = true; + _eps = eps; +} diff --git a/NonLinearSolver/Domain/partDomain.h b/NonLinearSolver/Domain/partDomain.h new file mode 100644 index 0000000000..a703dd02de --- /dev/null +++ b/NonLinearSolver/Domain/partDomain.h @@ -0,0 +1,220 @@ +// +// C++ Interface: partDomain +// +// Description: Interface class to used solver. Your term ha to be store in a domain +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef PARTDOMAIN_H_ +#define PARTDOMAIN_H_ +#ifndef SWIG +#include "mlaw.h" +#include "SVector3.h" +#include "MInterfaceElement.h" +#include "groupOfElements.h" +#include "timeFunction.h" +#include "functionSpaceType.h" +#include "nonLinearBC.h" +#include "nlTerms.h" +#include "unknownField.h" +#include "InterfaceBuilder.h" +// class for a domain (pure virtual class) +#endif +class partDomain{ + public : + typedef std::set<nonLinearDirichletBC*> diriContainer; + typedef std::set<nonLinearNeumannBC*> neuContainer; + typedef std::set<initialCondition*> initContainer; + + protected : + int _tag; // tag for the dofManager + int _phys; // physical of interface group I don't know how to retrieve it from *g + bool _fullDg; // To know which formulation Cg/Dg or FullDg is used for this part + functionSpaceType::whichSpace _wsp; + BilinearTermBase* btermBulk; + BilinearTermBase* massterm; + LinearTermBase<double>* ltermBulk; + QuadratureBase* integBulk; + // for matrix by perturbation + bool _bmbp; + double _eps; + virtual void setBulkMatrixByPerturbation(const int i, const double eps=1e-8); + // To know if law is already set + bool setmaterial; + // BC are put in domain to be sure to use the good function space + // neumann BC + neuContainer allNeumann; + // dirichlet BC + diriContainer allDirichlet; + // initial Condition + initContainer allInitial; + + public : + // Todo protect this variable + groupOfElements *g; // support for this field + +#ifndef SWIG + // Constructors + partDomain(const int tag, const int phys, + const int ws = 0,const bool fdg=false) : g(0), _tag(tag), _phys(phys), + _bmbp(false), _eps(1e-8), _fullDg(fdg), setmaterial(false) + { + switch(ws){ + case 0: + _wsp = functionSpaceType::Lagrange; + break; + case 10000: // Allow to set space later (used for interface domain) + _wsp = functionSpaceType::Inter; + break; + default: + Msg::Error("Function space type is unknown for partDomain %d. So Lagrange by default"); + _wsp = functionSpaceType::Lagrange; + } + } + partDomain(const partDomain &source); + partDomain& operator=(const partDomain &source); +// ~partDomain(){delete btermBulk; delete ltermBulk; delete integBulk;} + BilinearTermBase* getBilinearBulkTerm() const{return btermBulk;} + BilinearTermBase* getBilinearMassTerm() const{return massterm;} + LinearTermBase<double>* getLinearBulkTerm() const{return ltermBulk;} + QuadratureBase* getBulkGaussIntegrationRule() const{return integBulk;} + // Dimension of domain + virtual int getDim() const=0; + int getTag()const{return _tag;} + int getPhysical() const{return _phys;} + virtual void initializeTerms(unknownField *uf,IPField *ip)=0; + // true is domain has interface terms + virtual bool IsInterfaceTerms() const=0; + functionSpaceType::whichSpace getFunctionSpaceType() const{return _wsp;} + // can be return const FunctionSpaceBase if the function of this class are declarated const + virtual FunctionSpaceBase* getFunctionSpace() const=0; +// some data of BC have to be set by domain + virtual void addDirichletBC(nonLinearDirichletBC *diri)=0; // space and filterDof + virtual void addNeumannBC(nonLinearNeumannBC *neu)=0; // space, integration rule and term + virtual void addInitialCondition(initialCondition *initC)=0; // idem as dirichlet + void setTimeBC(const double curtime){ + for(neuContainer::iterator it=neuBegin(); it!=neuEnd(); ++it){ + nonLinearNeumannBC *neu = *it; + simpleFunctionTime<double> *ft = dynamic_cast<simpleFunctionTime<double>*>(neu->_f); + ft->setTime(curtime); + } + + for(diriContainer::iterator it=diriBegin(); it!=diriEnd(); ++it){ + nonLinearDirichletBC *diri = *it; + diri->_f.setTime(curtime); + } + } + diriContainer::iterator diriBegin(){return allDirichlet.begin();} + diriContainer::iterator diriEnd(){return allDirichlet.end();} + neuContainer::iterator neuBegin(){return allNeumann.begin();} + neuContainer::iterator neuEnd(){return allNeumann.end();} + initContainer::iterator initCBegin(){return allInitial.begin();} + initContainer::iterator initCEnd(){return allInitial.end();} + +// static void registerBindings(binding *b); + virtual void computeIPVariable(AllIPState *aips,const unknownField *ufield,const IPStateBase::whichState ws)=0; + virtual void computeIpv(AllIPState *aips,MInterfaceElement *ie, IntPt *GP,const IPStateBase::whichState ws, + partDomain* efMinus, partDomain *efPlus,materialLaw *mlawminus, + materialLaw *mlawplus,fullVector<double> &dispm, + fullVector<double> &dispp,const bool virt,const bool checkfrac=true)=0; + virtual void computeIpv(AllIPState *aips,MElement *e, IPStateBase::whichState ws, + materialLaw *mlaw,fullVector<double> &disp)=0; + virtual void setGaussIntegrationRule()=0; + virtual void inverseLinearTermSign()=0; + virtual bool getFormulation() const{return _fullDg;} + virtual void setMaterialLaw(const std::map<int,materialLaw*> maplaw)=0; + // No materialLaw store here but the function to give the material law exist + // The law has to be store in the derivated class + virtual materialLaw* getMaterialLaw()=0; + virtual const materialLaw* getMaterialLaw() const=0; + virtual int getLawNum() const=0; + // For dg formulation the stability parameters decrease the critical time step size + // in explicit. So this function allows to scale the time step + virtual double scaleTimeStep() const {return 1.;} + // creation of interface. At least boundary to create interface domain + // can be empty be not interdomain creation in this case + virtual void createInterface(manageInterface &maninter)=0; + //Iedge has to be change in IElement + virtual MElement* createVirtualInterface(IElement *ie) const=0; + virtual MElement* createInterface(IElement* ie1,IElement* ie2) const=0; + // Add for BC + virtual FilterDof* createFilterDof(const int comp) const=0; +#endif +}; +// class for Dg part domain (pure virtual) +class dgPartDomain : public partDomain{ + protected : + BilinearTermBase* btermBound; + LinearTermBase<double>* ltermBound; + BilinearTermBase* btermVirtBound; + LinearTermBase<double>* ltermVirtBound; + QuadratureBase* integBound; + // For matrix by perturbation + bool _interByPert; + bool _virtByPert; + + public : + // TODO protect these variables + groupOfElements *gi; // support for the interfaceElement TODO cast to a groupOfElements + groupOfElements *gib; // support for the interfaceElement TODO cast to a groupOfElements + groupOfElements *giv; // support for the virtual interface element (used to set Neumann and Dirichlet BC) +#ifndef SWIG + dgPartDomain(const int tag, const int phys, const int ws = 0, + const bool fdg=false) : partDomain(tag,phys,ws,fdg), _interByPert(false), _virtByPert(false) + { + gi = new groupOfElements(); + gib = new groupOfElements(); + giv = new groupOfElements(); + } + dgPartDomain(const dgPartDomain &source); + dgPartDomain& operator=(dgPartDomain &source); +// ~dgPartDomain(){delete btermBound; delete ltermBound; delete btermVirtBound; delete ltermVirtBound; +// delete integBound; delete gib; delete giv} + BilinearTermBase* getBilinearInterfaceTerm(){return btermBound;} + LinearTermBase<double>* getLinearInterfaceTerm()const{return ltermBound;} + BilinearTermBase* getBilinearVirtualInterfaceTerm(){return btermVirtBound;} + LinearTermBase<double>* getLinearVirtualInterfaceTerm(){return ltermVirtBound;} + QuadratureBase* getInterfaceGaussIntegrationRule() const {return integBound;} + virtual void computeIPVariable(AllIPState *aips,const unknownField *ufield,const IPStateBase::whichState ws)=0; + virtual void computeIpv(AllIPState *aips,MInterfaceElement *ie, IntPt *GP,const IPStateBase::whichState ws, + partDomain* efMinus, partDomain *efPlus,materialLaw *mlawminus, + materialLaw *mlawplus,fullVector<double> &dispm, + fullVector<double> &dispp,const bool virt,const bool checkfrac=true)=0; + virtual void computeIpv(AllIPState *aips,MElement *e, IPStateBase::whichState ws, + materialLaw *mlaw,fullVector<double> &disp)=0; + virtual void addDirichletBC(nonLinearDirichletBC *diri)=0; + virtual void addNeumannBC(nonLinearNeumannBC *neu)=0; + virtual void addInitialCondition(initialCondition *initC)=0; + virtual void setGaussIntegrationRule()=0; + virtual int getDim() const=0; + virtual bool IsInterfaceTerms() const{return true;} + virtual FunctionSpaceBase* getFunctionSpace() const=0; + virtual FunctionSpaceBase* getFunctionSpaceMinus() const=0; + virtual FunctionSpaceBase* getFunctionSpacePlus() const=0; + virtual void matrixByPerturbation(const int ibulk, const int iinter, const int ivirt,const double eps=1e-8)=0; +// static void registerBindings(binding *b); + virtual void setMaterialLaw(const std::map<int,materialLaw*> maplaw)=0; + virtual materialLaw* getMaterialLaw(){Msg::Error("The law to retrieve is not given on a dgdom"); return NULL;} + virtual const materialLaw* getMaterialLaw() const{Msg::Error("The law to retrieve is not given on a dgdom"); return NULL;} + virtual materialLaw* getMaterialLawMinus()=0; + virtual const materialLaw* getMaterialLawMinus() const=0; + virtual materialLaw* getMaterialLawPlus()=0; + virtual const materialLaw* getMaterialLawPlus() const=0; + virtual int getLawNum() const=0; + virtual int getMinusLawNum() const=0; + virtual int getPlusLawNum() const=0; + virtual const partDomain* getMinusDomain() const=0; + virtual const partDomain* getPlusDomain() const=0; + virtual partDomain* getMinusDomain()=0; + virtual partDomain* getPlusDomain()=0; + virtual void createInterface(manageInterface &maninter)=0; + virtual MElement* createVirtualInterface(IElement *ie) const=0; + virtual MElement* createInterface(IElement *ie1, IElement *ie2) const=0; + // Add for BC + virtual FilterDof* createFilterDof(const int comp) const=0; +#endif +}; +#endif diff --git a/NonLinearSolver/Interface/CMakeLists.txt b/NonLinearSolver/Interface/CMakeLists.txt new file mode 100644 index 0000000000..295d70c457 --- /dev/null +++ b/NonLinearSolver/Interface/CMakeLists.txt @@ -0,0 +1,15 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + IEdge.cpp + IElement.cpp + InterfaceBuilder.cpp + MInterfaceElement.cpp + MInterfaceLine.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/Interface "${SRC};${HDR}") diff --git a/NonLinearSolver/Interface/IEdge.cpp b/NonLinearSolver/Interface/IEdge.cpp new file mode 100644 index 0000000000..34933710d6 --- /dev/null +++ b/NonLinearSolver/Interface/IEdge.cpp @@ -0,0 +1,12 @@ +// +// C++ Interface: terms +// +// Description: Class to bluid an interface line (used at initialization) +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "IEdge.h" diff --git a/NonLinearSolver/Interface/IEdge.h b/NonLinearSolver/Interface/IEdge.h new file mode 100644 index 0000000000..877d1cdb5b --- /dev/null +++ b/NonLinearSolver/Interface/IEdge.h @@ -0,0 +1,32 @@ +// +// C++ Interface: terms +// +// Description: Class to bluid an interface line (used at initialization) +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef _IEDEGE_H_ +#define _IEDEGE_H_ +#include "IElement.h" +#include "MVertex.h" +#include "MElement.h" +// Class used to build 2D interface element +class IEdge : public IElement{ + public : + IEdge(std::vector<MVertex*> &v,MElement *e, int i) : IElement(v,e,i){}; + ~IEdge(){}; + unsigned long int getkey() const{ + int i1,i2,i3; + i1 = vertex[0]->getNum(); + i2 = vertex[1]->getNum(); + i1>i2 ? i3=i1*100000+i2 : i3=i2*100000+i1; // change this + return i3; + } + virtual IElement::IEtype getType()const{return IElement::Edge;} +}; +#endif // _IEDEGE_H_ diff --git a/NonLinearSolver/Interface/IElement.cpp b/NonLinearSolver/Interface/IElement.cpp new file mode 100644 index 0000000000..03b145b569 --- /dev/null +++ b/NonLinearSolver/Interface/IElement.cpp @@ -0,0 +1,12 @@ +// +// C++ Interface: terms +// +// Description: Class to bluid the interface element (used at initialization) +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "IElement.h" diff --git a/NonLinearSolver/Interface/IElement.h b/NonLinearSolver/Interface/IElement.h new file mode 100644 index 0000000000..0b90fcec0b --- /dev/null +++ b/NonLinearSolver/Interface/IElement.h @@ -0,0 +1,38 @@ +// +// C++ Interface: terms +// +// Description: Class to bluid the interface element (used at initialization) +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef _IELEMENT_H_ +#define _IELEMENT_H_ +#include "MVertex.h" +#include "MElement.h" +class IElement{ + public: + enum IEtype{Edge}; + protected: + std::vector<MVertex*> vertex; + MElement *elem; + int phys; + public: + IElement(std::vector<MVertex*> &v,MElement *e, int i) : vertex(v), elem(e), phys(i){}; + ~IElement(){}; + virtual unsigned long int getkey() const=0; + virtual IEtype getType() const=0; + // As for now only IEdge exists I don't know if these method are virtual pure + // virtual or are only for IEdge + virtual std::vector<MVertex*> getVertices() const{return vertex;} + virtual MElement* getElement() const{return elem;} + virtual MVertex* getFirstInteriorVertex() const {return vertex[2];} + virtual MVertex* getLastInteriorVertex() const {return *vertex.end();} + virtual int getPhys() const {return phys;} + +}; +#endif // _IELEMENT_H_ diff --git a/NonLinearSolver/Interface/InterfaceBuilder.cpp b/NonLinearSolver/Interface/InterfaceBuilder.cpp new file mode 100644 index 0000000000..b58a71b499 --- /dev/null +++ b/NonLinearSolver/Interface/InterfaceBuilder.cpp @@ -0,0 +1,66 @@ +// +// C++ Interface: terms +// +// Description: Class to manage the creation of interface +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "InterfaceBuilder.h" +#include "partDomain.h" +unsigned long int manageInterface::getKey(partDomain* dom1, partDomain *dom2){ + int i1 = dom1->getPhysical(); + int i2 = dom2->getPhysical(); + return manageInterface::getKey(i1,i2); +} + +void manageInterface::insert(IElement *iele,partDomain *dom) +{ + unsigned long int key = iele->getkey(); + IelementContainer::iterator it_edge=mapinter.find(key); + if((it_edge == mapinter.end()) or (iele->getType() != it_edge->second->getType())) + mapinter.insert(IelementPart(key,iele)); + else{ // create the interface + MElement *interel = dom->createInterface(iele,it_edge->second); + this->createinter(interel,iele,it_edge->second->getPhys()); + } +} + +void manageInterface::createinter(MElement *iele, IElement *ie, const int phys2) +{ + unsigned int physkey = manageInterface::getKey(ie->getPhys(),phys2); + #ifdef _DEBUG + bool findi = false; + #endif + for(std::vector<partDomain*>::iterator it = _vdom->begin(); it!=_vdom->end(); ++it){ + partDomain *dom = *it; + if(dom->getPhysical() == physkey){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + dgdom->gi->insert(iele); + #ifdef _DEBUG + findi=true; + #endif + } + } + #ifdef _DEBUG + if(!findi) + Msg::Error("Error with the creation of interfaceelement. It seems that an Interface element is not include in any domain"); + #endif + if(physkey != phys2){ + // search domain + for(std::vector<partDomain*>::iterator it = _vdom->begin(); it!=_vdom->end(); ++it){ + partDomain *dom = *it; + if(dom->getPhysical() == ie->getPhys()){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + MElement* interel = dgdom->createVirtualInterface(ie); + dgdom->giv->insert(interel); + } + } + } + else{ + this->erase(ie); + } +} diff --git a/NonLinearSolver/Interface/InterfaceBuilder.h b/NonLinearSolver/Interface/InterfaceBuilder.h new file mode 100644 index 0000000000..c6471b0de6 --- /dev/null +++ b/NonLinearSolver/Interface/InterfaceBuilder.h @@ -0,0 +1,66 @@ +// +// C++ Interface: terms +// +// Description: Class to manage the creation of interface +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef _INTERFACEBUILDER_H_ +#define _INTERFACEBUILDER_H_ +#include "mlaw.h" +#include "IElement.h" +class partDomain; +class manageInterface{ + public: + typedef std::map<unsigned long int,IElement*> IelementContainer; // create IElement type and Iede derive from Iedge + typedef std::pair<unsigned long int,IElement*> IelementPart; + protected: + IelementContainer mapinter; + std::vector<partDomain*> *_vdom; + public: + static unsigned long int getKey(const int npdom1, const int npdom2){ + unsigned long int i; + if(npdom1 == npdom2){ + return npdom1; + } + else{ + npdom1<npdom2 ? i = npdom2*100000+npdom1 : i = npdom1*100000+npdom2; + return i; + } + } + + unsigned long int getKey(partDomain* dom1, partDomain *dom2); + void insert(IElement *iele,partDomain *dom); + + // not optimal for internal interface pass current dom for more efficiency ?? + void createinter(MElement *ele, IElement *ie, const int phys2); + + manageInterface(std::vector<partDomain*> *vdom) : _vdom(vdom){} + ~manageInterface() + { + for(IelementContainer::iterator it = mapinter.begin(); it!=mapinter.end(); ++it){ + delete it->second; + } + } + void erase(IElement *ie){ + unsigned long int key = ie->getkey(); + IelementContainer::iterator it = mapinter.find(key); + if(it != mapinter.end()){ + delete it->second; + mapinter.erase(it); + } + } + + + void create(partDomain *dom1, partDomain *dom2, const std::map<int,materialLaw*> &maplaw,const int lawnum=0); + void createInterShell(partDomain *dom1, partDomain *dom2, const int lawnum, + const std::map<int,materialLaw*> &maplaw,const int ipert, const double eps=1e-8); + IelementContainer::iterator begin(){return mapinter.begin();} + IelementContainer::iterator end(){return mapinter.end();} + +}; +#endif //_INTERFACEBUILDER_H_ diff --git a/NonLinearSolver/Interface/MInterfaceElement.cpp b/NonLinearSolver/Interface/MInterfaceElement.cpp new file mode 100644 index 0000000000..eaa687cd15 --- /dev/null +++ b/NonLinearSolver/Interface/MInterfaceElement.cpp @@ -0,0 +1,49 @@ +// +// C++ Interface: terms +// +// Description: Class of interface element used for DG +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// Has to be merge with interface element defined in dg project HOW ?? +#include "MInterfaceElement.h" +#include "quadratureRules.h" +#include "MLine.h" +double MInterfaceElement::characSize(MElement *e) +{ + // Compute the area of the element + GaussQuadrature Integ_Bulk(GaussQuadrature::Grad); // which rule used for now not the same as the call function ?? + IntPt *GP; + double perimeter = 0., Area = 0.; + double jac[3][3]; + int npts=Integ_Bulk.getIntPoints(e,&GP); + // Area + for( int i = 0; i < npts; i++){ + // Coordonate of Gauss' point i + const double u = GP[i].pt[0]; const double v = GP[i].pt[1]; const double w = GP[i].pt[2]; + const double weight = GP[i].weight; const double detJ = e->getJacobian(u, v, w, jac); // Or compute jacobian with crossprod(phi0[0],phi0[1]) ?? + Area += weight * detJ; + } + // perimeter + int nside = e->getNumEdges(); + GaussQuadrature Integ_Bound(GaussQuadrature::ValVal); + std::vector<MVertex*> vver; + for(int i=0;i<nside;i++){ + IntPt *GPb; + e->getEdgeVertices(i,vver); + MLineN mlin = MLineN(vver); + int npts = Integ_Bound.getIntPoints(&mlin,&GPb); + for(int j=0;j<npts; j++){ + const double u = GPb[j].pt[0]; const double v = GPb[j].pt[1]; const double w = GPb[j].pt[2]; + const double weight = GPb[j].weight; const double detJ = mlin.getJacobian(u, v, w, jac); + perimeter +=weight*detJ; + } + vver.clear(); + } + + return Area/perimeter; +} diff --git a/NonLinearSolver/Interface/MInterfaceElement.h b/NonLinearSolver/Interface/MInterfaceElement.h new file mode 100644 index 0000000000..dee64bd16a --- /dev/null +++ b/NonLinearSolver/Interface/MInterfaceElement.h @@ -0,0 +1,31 @@ +// +// C++ Interface: terms +// +// Description: Class of interface element used for DG +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// Has to be merge with interface element defined in dg project HOW ?? + +# ifndef _MINTERFACEELEMENT_H_ +# define _MINTERFACEELEMENT_H_ +#include "MElement.h" +// MinterfaceElement is a pure virtual class whose is interace has to be derived and derived from MElement too +// so MinterfaceElement can't not be derived from MElement +class MInterfaceElement{ + public: + MInterfaceElement(){} + ~MInterfaceElement(){} + virtual MElement* getElem(const int index) const=0; + virtual int getEdgeOrFaceNumber(const int index) const=0; + virtual bool isSameDirection(const int index) const=0; + // should return the element number !! + virtual int getNum() const=0; + // compute the characteritic size of one element (This function can be defined as a method of MElement) ?? + static double characSize(MElement *e); // Area/perimeter +}; +#endif // _MINTERFACEELEMENT diff --git a/NonLinearSolver/Interface/MInterfaceLine.cpp b/NonLinearSolver/Interface/MInterfaceLine.cpp new file mode 100644 index 0000000000..a9eeed4903 --- /dev/null +++ b/NonLinearSolver/Interface/MInterfaceLine.cpp @@ -0,0 +1,111 @@ +// +// C++ Interface: terms +// +// Description: Class of interface element of line used for DG +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// Has to be merge with interface element defined in dg project HOW ?? + +#include "MInterfaceLine.h" +MInterfaceLine::MInterfaceLine(std::vector<MVertex*> &v, int num, int part, + MElement *e_minus, MElement *e_plus) : MLineN(v, num, part), MInterfaceElement(), + _num(MElement::getGlobalNumber()) //avoid this ?? +{ + _numElem[0]=e_minus; + _numElem[1]=e_plus; + // Edge of element linked to interface element we identifie an interior point of the MLine (degree 2 min for shell) thus we used v[0] + for(int jj=0;jj<2;jj++){ + int nopv = _numElem[jj]->getNumPrimaryVertices(); + std::vector<MVertex*> vv; + for(int i = 0; i < nopv; i++){ + _numElem[jj]->getEdgeVertices(i,vv); + for(int j = 2; j < vv.size(); j++){ + if(vv[j] == v[2]){ // v[2] because it is the first interior node + _numEdge[jj] = i; + if(v[0] == vv[0]) _dir[jj] = true; // same orientation + else _dir[jj] = false; + } + } + } + } +} + +void MInterfaceLine::getLocalVertexNum(const int i,std::vector<int> &vn) +{ + switch(_numEdge[i]){ + case 0 : + vn[0] = 0; + vn[1] = 1; + break; + case 1 : + vn[0] = 1; + vn[1] = 2; + break; + case 2 : + if(_numElem[i]->getType()==TYPE_TRI){vn[0]=2;vn[1]=0;} + else{vn[0]=2;vn[1]=3;} + break; + case 3 : + vn[0] = 3; + vn[1] = 0; + break; + default : Msg::Error("Impossible to get local vertex number in this case"); + } + // interior edge node + for(int j=2;j<vn.size();j++) + vn[j]=_numElem[i]->getNumEdges()+_numEdge[i]*(_numElem[i]->getPolynomialOrder()-1)+(j-2); +} + + // Get the u v value on element for a abscissa u on the interface element // TODO optmize by store in the class interface element the corresponding value (if many step must be compute once)?? +void MInterfaceLine::getuvOnElem(const double u, double &uem, double &vem, double &uep, double &vep) +{ // w = 0 as no volume element are taken into account. The point is defined between u=-1 and u=1 on the interface element + double ue=0.,ve=0.; + for(int jj=0;jj<2;jj++){ + switch(_numElem[jj]->getType()){ + case TYPE_TRI : + switch(_numEdge[jj]){ + case 0 : + if(_dir[jj]) {ue = 0.5 * ( 1 + u ); ve = 0.;} + else {ue = 0.5 * ( 1 - u ); ve = 0.;} + break; + case 1 : + if(_dir[jj]) {ue = 0.5 * (1 - u) ; ve = 0.5 * ( 1 + u );} + else {ue = 0.5 * (1 + u) ; ve = 0.5 * ( 1 - u );} + break; + case 2 : + if(_dir[jj]) { ue = 0; ve = 0.5 * (1 - u);} + else { ue = 0; ve = 0.5 * (1 + u);} + break; + } + break; + case TYPE_QUA : + switch(_numEdge[jj]){ + case 0 : + if(_dir[jj]) {ue = u; ve = -1.;} + else {ue =-u; ve=-1;} + break; + case 1 : + if(_dir[jj]) {ue =1.; ve = u;} + else {ue = 1.; ve = -u;} + break; + case 2 : + if(_dir[jj]) {ue = -u; ve = 1;} + else {ue = u; ve = 1;} + break; + case 3 : + if(_dir[jj]) {ue = -1; ve = -u;} + else {ue = -1; ve = u;} + break; + } + break; + default : Msg::Error("The Method doesn't work for this type of element"); + } + if(jj==0){uem=ue;vem=ve;} + else {uep=ue;vep=ve;} + } +} diff --git a/NonLinearSolver/Interface/MInterfaceLine.h b/NonLinearSolver/Interface/MInterfaceLine.h new file mode 100644 index 0000000000..cd97f5b31d --- /dev/null +++ b/NonLinearSolver/Interface/MInterfaceLine.h @@ -0,0 +1,58 @@ +// +// C++ Interface: terms +// +// Description: Class of interface element of line used for DG +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// Has to be merge with interface element defined in dg project HOW ?? + +#ifndef _MINTERFACELINE_H_ +#define _MINTERFACELINE_H_ +#include "MLine.h" +#include "MVertex.h" +#include "MInterfaceElement.h" +class MInterfaceLine : public MLineN, public MInterfaceElement{ // or don't derivate but in this case a vector with the vertices of interface element has to be save ?? + protected : + // NUMBER DUPLICATION HOW TO AVOID THIS (MInterfaceElement : public MELelement but 2 MElement at this time and MELement has to be a virtual class ??) + int _num; + // table of pointer on the two elements linked to the interface element + MElement *_numElem[2]; + // edge's number linked to interface element of minus and plus element + int _numEdge[2]; + // dir = true if the edge and the interface element are defined in the same sens and dir = false otherwise + bool _dir[2]; + + public : + + MInterfaceLine(std::vector<MVertex*> &v, int num = 0, int part = 0, MElement *e_minus = 0, MElement *e_plus = 0); + + // Destructor + ~MInterfaceLine(){} + + // Try to avoid this HOW +// int getNum() const{MLineN::getNum();} + int getNum() const{return _num;} + // Give the number of minus 0 or plus 1 element + MElement* getElem(int index) const {return _numElem[index];} + + void getuvOnElem(const double u, double &uem, double &vem, double &uep, double &vep); + + // Return the edge number of element + int getEdgeOrFaceNumber(const int i) const {return _numEdge[i];} + + // Return the local vertex number of interface + void getLocalVertexNum(const int i,std::vector<int> &vn); + // Compute the characteristic size of the side h_s = max_e (area_e/perimeter_e) + double getCharacteristicSize(){ + double cm = this->characSize(_numElem[0]); + double cp = this->characSize(_numElem[1]); + return cm > cp ? cm : cp; + } + bool isSameDirection(const int i) const {return _dir[i];} +}; +#endif // _MINTERFACELINE_H_ diff --git a/NonLinearSolver/contact/CMakeLists.txt b/NonLinearSolver/contact/CMakeLists.txt new file mode 100644 index 0000000000..7d7eafeba3 --- /dev/null +++ b/NonLinearSolver/contact/CMakeLists.txt @@ -0,0 +1,16 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + contactDomain.cpp + contactTerms.cpp + rigidCylinderContactTerms.cpp + # inline + contactFunctionSpace.h + nodeStiffnessContact.h +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/contact "${SRC};${HDR}") diff --git a/NonLinearSolver/contact/contactDomain.cpp b/NonLinearSolver/contact/contactDomain.cpp new file mode 100644 index 0000000000..924d741534 --- /dev/null +++ b/NonLinearSolver/contact/contactDomain.cpp @@ -0,0 +1,115 @@ +// +// contact Domain +// +// Description: Domain to solve contact problem +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "contactDomain.h" +contactDomain::contactDomain(const contactDomain &source){ + _tag = source._tag; + _phys = source._phys; + _physSlave = source._physSlave; + _penalty = source._penalty; + gSlave = source.gSlave; + gMaster = source.gMaster; + _dom = source._dom; + _bterm = source._bterm; + _massterm = source._massterm; + _lterm = source._lterm; + _contype = source._contype; + _rigid = source._rigid; + _space = source._space; + _integ = source._integ; +} + +void contactDomain::setContactType(const int ct){ + switch(ct){ + case 0: + _contype = rigidCylinder; + _rigid = true; + break; + case 1: + _contype = rigidSphere; + _rigid = true; + break; + default: + Msg::Error("No contact know for int %d",ct); + } +} + +MElement* contactDomain::getFirstElement() const { + groupOfElements::elementContainer::const_iterator it = gSlave->begin(); + return (*it); +} + +rigidCylinderContact::rigidCylinderContact(const int tag, const int physMaster, const int physSlave, const int physPt1, + const int physPt2, const double penalty, + const double h) : contactDomain(tag,physMaster,physSlave, + penalty,rigidCylinder,true), + _thick(h){ + + // void gauss integration + _integ = new QuadratureVoid(); + + // creation of group of elements + gMaster = new groupOfElements(2,physMaster); + gSlave = new groupOfElements(2,physSlave); + // use for build --> no save + groupOfElements gpt1 = groupOfElements(0,physPt1); + groupOfElements gpt2 = groupOfElements(0,physPt2); + + // find GC and dimension of cylinder + // get vertex + groupOfElements::vertexContainer::iterator itpt1 = gpt1.vbegin(); + groupOfElements::vertexContainer::iterator itpt2 = gpt2.vbegin(); + MVertex *ver1 = *itpt1; + MVertex *ver2 = *itpt2; + // Vertices coordinates + double x1 = ver1->x(); double y1 = ver1->y(); double z1 = ver1->z(); + double x2 = ver2->x(); double y2 = ver2->y(); double z2 = ver2->z(); + //creation of GC vertex + double xgc = 0.5*(x1+x2); double ygc = 0.5*(y1+y2); double zgc = 0.5*(z1+z2); + _vergc = new MVertex(xgc,ygc,zgc); + // dimension of cylinder + _length = ver1->distance(ver2); + // Radius search for an extreme pnt (ie the point with the most distance of gc) + double dist=-1.; // initialization + MVertex *vermax; + for(groupOfElements::vertexContainer::iterator it=gMaster->vbegin(); it!=gMaster->vend();++it){ + MVertex *ver = *it; + double d = ver->distance(_vergc); + if(d > dist){ + vermax = ver; + dist = d; + } + } + // radius = smallest distance of extreme point and a center + double r1 = vermax->distance(ver1); + double r2 = vermax->distance(ver2); + (r1>r2) ? _radius=r2 : _radius=r1; + + // vector director of cylinder's axis + _axisDirector = new SVector3(ver1->point(),ver2->point()); + _axisDirector->normalize(); +} + +void rigidCylinderContact::initializeTerms(const unknownField *ufield){ + rigidContactSpace *sp = dynamic_cast<rigidContactSpace*>(_space); + _massterm = new massRigidCylinder(this,sp); + _lterm = new forceRigidCylinderContact(this,sp,_thickContact,ufield); + rigidContactLinearTermBase<double> *rlterm = dynamic_cast<rigidContactLinearTermBase<double>*>(_lterm); + _bterm = new stiffnessRigidCylinderContact(sp,rlterm,ufield); +} + +void rigidCylinderContact::setDomain(partDomain *dom){ + _dom = dom; + FunctionSpace<double> *spdom = dynamic_cast<FunctionSpace<double>*>(dom->getFunctionSpace()); + if(_space != NULL) delete _space; + _space = new rigidContactSpace(_phys,spdom,_vergc); +} + diff --git a/NonLinearSolver/contact/contactDomain.h b/NonLinearSolver/contact/contactDomain.h new file mode 100644 index 0000000000..885687a419 --- /dev/null +++ b/NonLinearSolver/contact/contactDomain.h @@ -0,0 +1,108 @@ +// +// contact Domain +// +// Description: Domain to solve contact problem +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef CONTACTDOMAIN_H_ +#define CONTACTDOMAIN_H_ +#ifndef SWIG +#include "groupOfElements.h" +#include "partDomain.h" +#include "contactTerms.h" +#include "rigidCylinderContactTerms.h" +#include "MVertex.h" +#include "MElement.h" +template<class T2> class contactBilinearTermBase; +template<class T2> class contactLinearTermBase; +#endif +class contactDomain{ + public: + enum contact{rigidCylinder, rigidSphere}; + protected: + int _phys; + int _physSlave; + int _tag; + double _penalty; + BilinearTermBase* _bterm; + BilinearTermBase* _massterm; + LinearTermBase<double>* _lterm; + partDomain *_dom; + contact _contype; + bool _rigid; + FunctionSpaceBase *_space; + QuadratureBase *_integ; + public: + groupOfElements *gMaster; + groupOfElements *gSlave; +#ifndef SWIG + contactDomain() : gMaster(0), gSlave(0), _phys(0), _physSlave(0), _tag(0), _contype(rigidCylinder), _dom(0), _penalty(0.), _rigid(true){} + contactDomain(const int tag, const int phys, const int physSlave, double pe, + contact conty,const bool rigid=false) : _tag(tag), _phys(phys), _physSlave(physSlave), + _penalty(pe), _contype(conty), + _rigid(rigid), _space(NULL){} + contactDomain(const contactDomain &source); + ~contactDomain(){} + + virtual void setTag(const int t){ _tag =t;} + virtual void setPhys(const int p){_phys =p;} + virtual void setPenalty(const double pe){_penalty=pe;} + virtual void setDomain(partDomain *dom)=0; + virtual void setContactType(const int ct); + virtual void setContactType(const contact ct){_contype =ct;} + virtual int getTag() const{return _tag;} + virtual int getPhys() const{return _phys;} + virtual int getPhysSlave() const{return _physSlave;} + virtual double getPenalty() const{return _penalty;} + virtual contact getContactType() const{return _contype;} + virtual partDomain* getDomain() const {return _dom;} + virtual MElement * getFirstElement() const; + virtual bool isRigid() const {return _rigid;} + virtual BilinearTermBase* getMassTerm(){return _massterm;} + virtual BilinearTermBase* getStiffnessTerm(){return _bterm;} + virtual LinearTermBase<double>* getForceTerm(){return _lterm;} + virtual FunctionSpaceBase* getSpace() {return _space;} + virtual const FunctionSpaceBase* getSpace() const {return _space;} + virtual QuadratureBase* getGaussIntegration() const{return _integ;} +// static void registerBindings(binding *b); +#endif +}; + +class rigidCylinderContact : public contactDomain{ + protected: + double _length; // length of cylinder; + double _radius; // outer radius of cylinder; + double _thick; // thickness of cylinder; + double _thickContact; // use for shell (contact with neutral axis of external fiber is !=0) + double _density; // density of cylinder Not a material law for now + MVertex *_vergc; // vertex of gravity center + SVector3 *_axisDirector; // normalized vector director of cylinder's axis + public: + rigidCylinderContact() : contactDomain(), _length(0.), _radius(0.), _thick(0.){ + _contype = rigidCylinder; + _rigid = true; + _integ = new QuadratureVoid(); + } + rigidCylinderContact(const int tag, const int physMaster, const int physSlave, const int physpt1, + const int physpt2,const double penalty,const double h); + ~rigidCylinderContact(){delete _axisDirector;} + void density(const double rho){ _density = rho;} +// void setThicknessContact(const double h){_thickContact = h;} +#ifndef SWIG + virtual MVertex* getGC() const{return _vergc;} + double getDensity() const{return _density;} + double getLength() const{return _length;} + double getRadius() const{return _radius;} + double getThickness() const{return _thick;} + void initializeTerms(const unknownField *ufield); + SVector3* getAxisDirector() const{return _axisDirector;} + virtual void setDomain(partDomain *dom); +#endif + +}; +#endif // CONTACTDOMAIN_H_ diff --git a/NonLinearSolver/contact/contactFunctionSpace.h b/NonLinearSolver/contact/contactFunctionSpace.h new file mode 100644 index 0000000000..e2b67f9df9 --- /dev/null +++ b/NonLinearSolver/contact/contactFunctionSpace.h @@ -0,0 +1,85 @@ +// +// functional space for contact +// +// Description: +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// + +#ifndef CONTACTSPACE_H_ +#define CONTACTSPACE_H_ +#include "functionSpace.h" +#include "Dof3IntType.h" +template <class T1> class ContactSpaceBase : public FunctionSpaceBase{ + protected: + FunctionSpace<T1> *_space; // functional space of domain where contact is computed + const int _id; + std::vector<int> _comp; + public: + ContactSpaceBase(const int id, FunctionSpace<double> *sp) : FunctionSpaceBase(), _id(id), _space(sp){ + _comp.push_back(0); + _comp.push_back(1); + _comp.push_back(2); + } + ContactSpaceBase(const int id, FunctionSpace<double> *sp, const int comp1, + const int comp2 = -1, const int comp3 =-1) : FunctionSpaceBase(), _id(id), _space(sp) + { + _comp.push_back(comp1); + if(comp2 !=-1) + _comp.push_back(comp2); + if(comp3 != -1) + _comp.push_back(comp3); + } + + virtual void getKeys(MElement *ele,std::vector<Dof> &keys){ + _space->getKeys(ele,keys); + } + virtual int getNumKeys(MElement *ele){ + return _space->getNumKeys(ele); + } +}; + +class rigidContactSpace : public ContactSpaceBase<double>{ + protected: + const MVertex *_gc; // Node of gravity center + public: + rigidContactSpace(const int id, FunctionSpace<double> *sp, MVertex *ver) : ContactSpaceBase<double>(id,sp), _gc(ver){} + rigidContactSpace(const int id, FunctionSpace<double> *sp, MVertex *ver, const int comp1, + const int comp2 = -1, const int comp3 =-1) : ContactSpaceBase<double>(id,sp,comp1,comp2,comp3){} + virtual void getKeys(MElement *ele,std::vector<Dof> &keys){ + _space->getKeys(ele,keys); + for(int i=0;i<_comp.size();i++){ + keys.push_back(Dof(_gc->getNum(),Dof3IntType::createTypeWithThreeInts(_comp[i],_id))); + } + } + virtual int getNumKeys(MElement *ele){ + int nkeysele = _space->getNumKeys(ele); + return nkeysele + _comp.size(); + } + virtual void getKeysOfGravityCenter(std::vector<Dof> &keys){ + for(int i=0;i<_comp.size(); i++) + keys.push_back(Dof(_gc->getNum(),Dof3IntType::createTypeWithThreeInts(_comp[i],_id))); + } + virtual int getNumKeysOfGravityCenter(){ + return _comp.size(); + } + virtual void getKeys(MElement *ele, const int ind, std::vector<Dof> &keys){ + // generate keys of element and select the good ones after LAGRANGE OK ?? CHANGE THIS HOW TODO + std::vector<Dof> tkeys; + this->getKeys(ele,tkeys); + int nkeys = this->getNumKeys(ele); + int ncomp = _comp.size(); + int nbver = nkeys/ncomp-1; // because GC is in the nkeys + for(int i=0;i<ncomp; i++) + keys.push_back(tkeys[ind+i*nbver]); + this->getKeysOfGravityCenter(keys); + } + virtual int getNumKeys(MElement *ele, int ind){ + return 2*_comp.size(); + } +}; +#endif // CONTACTSPACE_H_ + diff --git a/NonLinearSolver/contact/contactTerms.cpp b/NonLinearSolver/contact/contactTerms.cpp new file mode 100644 index 0000000000..60e02ffb57 --- /dev/null +++ b/NonLinearSolver/contact/contactTerms.cpp @@ -0,0 +1,51 @@ +// +// contact base term +// +// Description: contact term +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +#include "contactTerms.h" +#include "unknownField.h" +template<> void rigidContactLinearTermBase<double>::get(MElement *ele, int npts, IntPt *GP,fullVector<double> &m) const +{ + nbdofs = _spc->getNumKeys(ele); + nbdofsGC = _spc->getNumKeysOfGravityCenter(); + m.resize(nbdofs); + m.setAll(0.); + nbvertex = ele->getNumVertices(); + nbcomp = (nbdofs-nbdofsGC)/nbvertex; + nbcomptimenbvertex = nbvertex*nbcomp; + // get displacement of vertices (To know the current node positions) + disp.clear(); R.clear(); + _spc->getKeys(ele,R); + + _ufield->get(R,disp); + + verdisp[3] = disp[nbcomptimenbvertex]; verdisp[4] = disp[nbcomptimenbvertex+1]; verdisp[5] = disp[nbcomptimenbvertex+2]; + for(int i=0;i<nbvertex;i++){ + for(int j=0;j<6;j++) mvalue[j] =0.; + ver = ele->getVertex(i); + verdisp[0] = disp[i]; verdisp[1] = disp[i+nbvertex]; verdisp[2] = disp[i+2*nbvertex]; + this->get(ver,verdisp,mvalue); + // look if there is contact force + int jj=0; + while(jj<6){ + if(mvalue[jj] != 0.){ +// Msg::Info("Contact detected on elem %d vertex %d",ele->getNum(),ele->getVertex(i)->getNum()); + _allcontactNode->insert(ele,i,_lastNormalContact); + for(int j=0;j<nbcomp;j++){ + m(i+j*nbvertex) += mvalue[j]; + m(nbcomptimenbvertex+j) += mvalue[j+3]; // count two times + } + break; + } + jj++; + } + } + // if(m.norm() != 0.) +// m.print("contact"); +} diff --git a/NonLinearSolver/contact/contactTerms.h b/NonLinearSolver/contact/contactTerms.h new file mode 100644 index 0000000000..d0b652d20f --- /dev/null +++ b/NonLinearSolver/contact/contactTerms.h @@ -0,0 +1,80 @@ +// +// contact base term +// +// Description: define contact terms +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef CONTACTTERMS_H_ +#define CONTACTTERMS_H_ +#include "terms.h" +#include "nodeStiffnessContact.h" +#include "contactFunctionSpace.h" +class unknownField; +template<class T1=double> class contactLinearTermBase : public LinearTermBase<T1>{ + protected: + contactNodeStiffness *_allcontactNode; // need to compute BilinearTerm with more efficiency (compute only for nodes in contact) + public: + contactLinearTermBase(){ + _allcontactNode = new contactNodeStiffness(); + } + contactLinearTermBase(const contactLinearTermBase &source){ + _allcontactNode = source._allcontactNode; + } + virtual ~contactLinearTermBase(){delete _allcontactNode;} + contactNodeStiffness* getContactNode() const {return _allcontactNode;} + void clearContactNodes(){_allcontactNode->clear();} +// virtual void get(MElement *ele, int npts, IntPt *GP, fullVector<T1> &v)=0; +}; + +template <class T2=double>class contactBilinearTermBase : public BilinearTermBase +{ + protected: + contactLinearTermBase<T2> *_lterm; // because bilinear terms is compute only for nodes + // in contact. These nodes are in the linear terms associated to bilinearTerm + public: + contactBilinearTermBase(contactLinearTermBase<T2> *lterm) : _lterm(lterm){} + virtual ~contactBilinearTermBase(){} +// virtual void get(MElement *ele, int npts, IntPt *GP, fullMatrix<T2> &m) const=0; + // same for all contact + contactLinearTermBase<T2>* getLterm() const{return _lterm;} + contactNodeStiffness * getContactNodes() const{return _lterm->getContactNode();} + void clearContactNodes(){_lterm->clearContactNodes();} +}; + +template<class T2=double> class rigidContactLinearTermBase : public contactLinearTermBase<T2>{ + protected: + const unknownField *_ufield; + rigidContactSpace *_spc; + // data for get function (Allocated once) + mutable SVector3 _lastNormalContact; // allow to use the normal in the 2 get functions not very elegant + mutable int nbdofs,nbdofsGC, nbvertex,nbcomp,nbcomptimenbvertex; + mutable std::vector<double> disp; + mutable std::vector<Dof> R; + mutable double verdisp[6]; + mutable double mvalue[6]; + mutable MVertex *ver; + public: + rigidContactLinearTermBase(rigidContactSpace *sp, + const unknownField *ufield) : contactLinearTermBase<T2>(), + _ufield(ufield), _spc(sp), _lastNormalContact(0.,0.,0.), + nbdofs(0), nbdofsGC(0), nbvertex(0), nbcomp(0), nbcomptimenbvertex(0) + { + + } + rigidContactLinearTermBase(const rigidContactLinearTermBase<T2> &source) : contactLinearTermBase<T2>(source){ + _ufield = source._ufield; + _spc = source._spc; + } + ~rigidContactLinearTermBase(){} +// virtual void get(MElement *ele, fullVector<double> &m); + virtual void get(const MVertex *ver, const double disp[6],double mvalue[6]) const=0; + // same for ALL RIGID CONTACT + virtual void get(MElement *ele, int npts, IntPt *GP, fullVector<T2> &v) const; +}; +#endif // CONTACTTERMS_H_ diff --git a/NonLinearSolver/contact/nodeStiffnessContact.h b/NonLinearSolver/contact/nodeStiffnessContact.h new file mode 100644 index 0000000000..3f073ddec5 --- /dev/null +++ b/NonLinearSolver/contact/nodeStiffnessContact.h @@ -0,0 +1,62 @@ +// +// contact stiffness +// +// Description: Class to manage the Dof for which the stiffness must be computed +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef CONTACTNODESTIFFNESS_H_ +#define CONTACTNODESTIFFNESS_H_ +#include "MElement.h" +#include "SVector3.h" + +struct dataContactStiffnessNode{ + public: + MElement *_ele; + int _verIndex; + SVector3 _normal; + dataContactStiffnessNode() : _ele(NULL), _verIndex(0), _normal(0.,0.,0.){}; + dataContactStiffnessNode(MElement *ele, const int ind, const SVector3 &nor) : _ele(ele), _verIndex(ind), _normal(nor){} + dataContactStiffnessNode(const dataContactStiffnessNode &source){ + _ele = source._ele; + _verIndex = source._verIndex; + _normal = source._normal; + } +}; + +class contactNodeStiffness{ + public: + typedef std::vector<dataContactStiffnessNode> nodeContainer; + protected: + nodeContainer _nodeInContact; + groupOfElements *_g; // group with elements in contact + public: + contactNodeStiffness(){_g = new groupOfElements();} + contactNodeStiffness(const contactNodeStiffness &source){ + _nodeInContact = source._nodeInContact; + _g = source._g; + } + ~contactNodeStiffness() + { + if(_g !=NULL) delete _g; + }; + + void insert(MElement *ele,const int i, SVector3 &normal){ + _nodeInContact.push_back(dataContactStiffnessNode(ele,i,normal)); + _g->insert(ele); + } + void clear(){ + _nodeInContact.clear(); + if(_g != NULL) delete _g; + _g = new groupOfElements(); + } + nodeContainer::const_iterator nBegin() const{return _nodeInContact.begin();} + nodeContainer::const_iterator nEnd() const{return _nodeInContact.end();} + groupOfElements::elementContainer::const_iterator elemBegin() const{return _g->begin();} + groupOfElements::elementContainer::const_iterator elemEnd() const{return _g->end();} +}; +#endif // contactNodeStiffness diff --git a/NonLinearSolver/contact/rigidCylinderContactTerms.cpp b/NonLinearSolver/contact/rigidCylinderContactTerms.cpp new file mode 100644 index 0000000000..ab732190a1 --- /dev/null +++ b/NonLinearSolver/contact/rigidCylinderContactTerms.cpp @@ -0,0 +1,188 @@ +// +// contact base term +// +// Description: contact with a rigid cylinder +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +#include "rigidCylinderContactTerms.h" +#include "contactDomain.h" +#include "unknownField.h" +massRigidCylinder::massRigidCylinder(rigidCylinderContact *cdom, + rigidContactSpace *spc) : _length(cdom->getLength()),_radius(cdom->getRadius()), + _thick(cdom->getThickness()),_rho(cdom->getDensity()), + _spc(spc),nbdofs(0.), masse(0.),Rint(0.){} + +void massRigidCylinder::get(MElement *ele,int npts,IntPt *GP,fullMatrix<double> &m) const +{ + // get the number of cylinder component (same mass in all direction) + int nbdofs = _spc->getNumKeysOfGravityCenter(); + m.resize(nbdofs,nbdofs,true); // true --> setAll(0.) + if(_thick > _radius){ // full cylinder + masse = _rho*M_PI*_radius*_radius*_length; + } + else{ // hollow cylinder + Rint = _radius-_thick; + masse = _rho*M_PI*_thick*(_radius*_radius-Rint*Rint); + } + for(int i=0;i<nbdofs;i++) + m(i,i) = masse; +} + + forceRigidCylinderContact::forceRigidCylinderContact(const rigidCylinderContact *cdom, + rigidContactSpace *sp,const double thick, + const unknownField *ufield) : rigidContactLinearTermBase(sp,ufield), _cdom(cdom), + _vergc(cdom->getGC()), + _axisDirector(cdom->getAxisDirector()), + _radius(cdom->getRadius()), + _rcontact(cdom->getRadius() + 0.*thick), + _halflength(0.5*cdom->getLength()), + _GC(cdom->getGC()->point()), d(0.), + penetration(0.), penpen(0.) +{ + if(_cdom->getDomain()->IsInterfaceTerms()){ + partDomain *dom = dynamic_cast<partDomain*>(_cdom->getDomain()); + if(dom->getFormulation()){ + _fdgfactor = 1.; + _facGC =0.5; + } + else{ + _fdgfactor = 0.5; + _facGC =1.; + } + } + else{ + _fdgfactor = 0.5; + _facGC = 1.; + } + _penalty = _fdgfactor*_cdom->getPenalty(); +} + +void forceRigidCylinderContact::get(const MVertex *ver, const double disp[6],double mvalue[6]) const +{ + // B = axis' center + // A = vertex for which we look for contact + B = _GC; + Bdisp.setPosition(disp[3],disp[4],disp[5]); + B+=Bdisp; + // Distance between vertex and cylinder axis + // line BA + A = ver->point(); + Adisp.setPosition(disp[0],disp[1],disp[2]); + A+=Adisp; + SVector3 BA(A,B); + dirAC = crossprod(BA,*_axisDirector); + double d = dirAC.norm(); + // test to know if contact + if(d < _rcontact){ + // check if contact occur before end of cylinder + dirAC.normalize(); + _lastNormalContact = crossprod(dirAC,*_axisDirector); + _lastNormalContact.normalize(); + C.setPosition(A,_lastNormalContact.point(),-d); + // check normal direction if C is further of B than A the direction is wrong + if(C.distance(B) > A.distance(B)){ + _lastNormalContact.negate(); + _lastNormalContact.normalize(); + C.setPosition(A,_lastNormalContact.point(),-d); + } + if(C.distance(B) < _halflength){ + penetration = _rcontact-d; + penpen = penetration*_penalty; + for(int j=0;j<3;j++){ + mvalue[j]+= penpen*_lastNormalContact(j); + mvalue[j+3] -=_facGC*penpen*_lastNormalContact(j); // count two times + } + } + } +} + +void stiffnessRigidCylinderContact::get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) const +{ + int nbdofs = _spc->getNumKeys(ele); + m.resize(nbdofs,nbdofs,true); // true --> setAll(0.) + // search the vertices for which the matrix has to be computed + contactNodeStiffness * contactNodes = _lterm->getContactNode(); + for(contactNodeStiffness::nodeContainer::const_iterator itn = contactNodes->nBegin(); itn!= contactNodes->nEnd(); ++itn){ + if(itn->_ele == ele){ // contact + this->get(ele,itn->_verIndex,m); + } + } +} + +// Protected can only be called by stiffnessRigidCylinderContact::get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) +// NO RESIZE +void stiffnessRigidCylinderContact::get(MElement *ele, const int verIndex, fullMatrix<double> &m) const +{ + // perturbation numeric + rigidContactLinearTermBase<double>* rlterm = dynamic_cast<rigidContactLinearTermBase<double>*>(_lterm); + int nbdofselem = _spc->getNumKeys(ele) - _spc->getNumKeysOfGravityCenter(); + int nbFF = ele->getNumVertices(); + ver = ele->getVertex(verIndex); + disp.clear(); R.clear(); + _spc->getKeys(ele,verIndex,R); + _ufield->get(R,disp); + for(int j=0;j<6;j++) + pertdisp[j] = disp[j]; + + // perturbation on each Dofs 3 for vertex and 3 for GC of cylinder + for(int i=0;i<6;i++){ + // set force component to zero + for(int j=0;j<6;j++) + fp[j] = fm[j] = 0.; + + // Force - + pertdisp[i] = disp[i] - _perturbation; + rlterm->get(ver,pertdisp,fm); + + // Force + + pertdisp[i] = disp[i] + _perturbation; + rlterm->get(ver,pertdisp,fp); + + // Assembly in matrix + if(i<3){ // perturbation on vertex + for(int j=0; j<3; j++){ + m(verIndex+nbFF*j,verIndex+nbFF*i) -= (fp[j]-fm[j])*_doublepertexpm1; + m(nbdofselem+j,verIndex+nbFF*i) -= (fp[j+3]-fm[j+3])*_doublepertexpm1; + } + } + else{ // perturbation on gravity center + for(int j=0; j<3; j++){ + m(verIndex+nbFF*j,nbdofselem+i-3) -= (fp[j]-fm[j])*_doublepertexpm1; + m(nbdofselem+j,nbdofselem+i-3) -= (fp[j+3]-fm[j+3])*_doublepertexpm1; + } + } + // virgin pertdisp + pertdisp[i] = disp[i]; + } + + // ANALYTIC WAY MUST BE FIXED +/* int nbdofs = _spc->getNumKeys(ele); + int nbvertex = ele->getNumVertices(); + int nbdofGC = _spc->getNumKeysOfGravityCenter(); + int nbcomp = (nbdofs-nbdofGC)/nbvertex; + int nbcompTimesnbVertex = nbcomp*nbvertex; + m.resize(nbdofs,nbdofs); + m.setAll(0.); + double penalty = _fdgfactor*_cdom->getPenalty(); + for(int i=0;i<nbvertex;i++){ + SVector3 nor = _allcontactNode->getNormal(ele,i); + if(nor.norm() != 0.){ // otherwise no contact + double dianor[3][3]; + diaprod(nor,nor,dianor); + for(int j=0;j<3;j++) + for(int k=0;k<3;k++) + dianor[j][k]*=penalty; + for(int j=0;j<nbcomp;j++) + for(int k=0;k<nbcomp;k++){ + m(i+j*nbvertex,i+k*nbvertex) -= dianor[j][k]; + m(nbcompTimesnbVertex+j,nbcompTimesnbVertex+k) -=0.5*dianor[j][k]; + } + } + } + m.print("Contact Matrix");*/ +} + diff --git a/NonLinearSolver/contact/rigidCylinderContactTerms.h b/NonLinearSolver/contact/rigidCylinderContactTerms.h new file mode 100644 index 0000000000..de8a87eec7 --- /dev/null +++ b/NonLinearSolver/contact/rigidCylinderContactTerms.h @@ -0,0 +1,113 @@ +// +// contact base term +// +// Description: contact with a rigid cylinder +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// + +#ifndef RIGIDCONTACTCYLINDER_H_ +#define RIGIDCONTACTCYLINDER_H_ +#include "contactTerms.h" +#include "contactFunctionSpace.h" +class rigidCylinderContact; +class massRigidCylinder : public BilinearTermBase{ + protected: + double _length, _radius, _thick, _rho; + rigidContactSpace *_spc; + // Data for get function (Allocated once) + mutable int nbdofs; + mutable double masse; + mutable double Rint; + public: + massRigidCylinder(rigidCylinderContact *cdom,rigidContactSpace *spc); + massRigidCylinder(rigidContactSpace *spc,double leng, double radius, + double thick,double rho) : _spc(spc), _length(leng), _radius(radius),_thick(thick), _rho(rho){} + // Arguments are useless but it's allow to use classical assemble function + void get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) const; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullMatrix<double> > &mv) const + { + Msg::Error("Define me get by integration point massRigidCylinder"); + } + virtual BilinearTermBase* clone () const + { + return new massRigidCylinder(_spc,_length,_radius,_thick,_rho); + } +}; + +class forceRigidCylinderContact : public rigidContactLinearTermBase<double>{ + protected: + const rigidCylinderContact *_cdom; + double _fdgfactor, _facGC; + const MVertex *_vergc; + const SVector3* _axisDirector; + const double _radius; + const double _rcontact; + const double _halflength; + double _penalty; + const SPoint3 _GC; + // Data of get function (Allocated once) + mutable SPoint3 B,Bdisp,A,Adisp,C; + mutable double d,penetration,penpen; + mutable SVector3 dirAC; + public: + forceRigidCylinderContact(const rigidCylinderContact *cdom, + rigidContactSpace *sp,const double thick, + const unknownField *ufield); + ~forceRigidCylinderContact(){} +// void get(MElement *ele,int npts, IntPt *GP,fullVector<double> &m); + // specific function to this contact type ( put in rigidContactSpaceBase ??) + // This one cannot be called by Assemble function + void get(const MVertex *ver, const double disp[6],double mvalue[6]) const; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullVector<double> > &vv) const + { + Msg::Error("define me get by gauss point forceRigidCylinderContact"); + } + virtual LinearTermBase<double>* clone () const + { + return new forceRigidCylinderContact(_cdom,this->_spc,_rcontact-_radius,_ufield); + } +}; + + +class stiffnessRigidCylinderContact : public contactBilinearTermBase<double>{ + private: + // can be applied only be applied by classical get function perturbation for 1 vertex + void get(MElement *ele, const int verIndex, fullMatrix<double> &m) const; + protected: + const unknownField *_ufield; + rigidContactSpace *_spc; + const double _perturbation; // numerical perturbation + const double _doublepertexpm1; + // Data for get function (Allocated Once) + mutable double fp[6]; + mutable double fm[6]; + mutable int nbdofs; + mutable MVertex *ver; + mutable std::vector<Dof> R; + mutable std::vector<double> disp; + mutable double pertdisp[6]; + public: + stiffnessRigidCylinderContact(rigidContactSpace *space, contactLinearTermBase<double> *lterm, const unknownField *ufield) : contactBilinearTermBase(lterm), + _ufield(ufield), + _perturbation(1.e-10), + _doublepertexpm1(1./(2.e-10)), + _spc(space), nbdofs(0){} + ~stiffnessRigidCylinderContact(){} + void get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) const; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullMatrix<double> > &mv) const + { + Msg::Error("Define me get by integration point stiffnessRigidCylinderContact"); + } + virtual BilinearTermBase* clone () const + { + return new stiffnessRigidCylinderContact(_spc,_lterm,_ufield); + } +}; + + +#endif // RIGIDCONTACTCYLINDER_H_ + diff --git a/NonLinearSolver/field/CMakeLists.txt b/NonLinearSolver/field/CMakeLists.txt new file mode 100644 index 0000000000..56a906eb6f --- /dev/null +++ b/NonLinearSolver/field/CMakeLists.txt @@ -0,0 +1,12 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + elementField.cpp + energyField.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/field "${SRC};${HDR}") diff --git a/NonLinearSolver/field/elementField.cpp b/NonLinearSolver/field/elementField.cpp new file mode 100644 index 0000000000..1f685758e5 --- /dev/null +++ b/NonLinearSolver/field/elementField.cpp @@ -0,0 +1,130 @@ +// +// C++ Interface: terms +// +// Description: Base class to manage a field on element (All field are managed by element in full Dg so displacement is also +// considered like a field on element +// +// The base class contains archiving data (which is not dependent of the field) +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "elementField.h" +#include <sstream> +#include "partDomain.h" +void elementField::updateFileName(){ + // add a numero to file name + std::ostringstream oss; + oss << ++numfile; + std::string s = oss.str(); + std::string snum; + // cut filename and its extension + size_t ext_pos; + if(numfile==1){ + ext_pos = fileName.find_last_of('.'); + snum = "0"; + } + else{ + oss.str(""); + oss << numfile-1; + snum = oss.str(); + ext_pos = fileName.find_last_of(snum); + } + std::string newname(fileName,0,ext_pos-(snum.size()-1)); + ext_pos = fileName.find_last_of('.'); + std::string ext(fileName,ext_pos+1,fileName.size()); + fileName = newname+s+"."+ext; + // create initialization of file + FILE *fp = fopen(fileName.c_str(), "w"); + fprintf(fp, "$MeshFormat\n2.1 0 8\n$EndMeshFormat\n"); + fclose(fp); +} + +void elementField::createFile(){ + if(view){ + // creation of file to store displacement (delete the previous one if exist) + size_t ext_pos = fileName.find_last_of('.'); + std::string newname = fileName; + newname.resize(ext_pos); + std::string rfn = "rm "+newname+"*"; + system(rfn.c_str()); + FILE *fp = fopen(fileName.c_str(), "w"); + fprintf(fp, "$MeshFormat\n2.1 0 8\n$EndMeshFormat\n"); + fclose(fp); + } +} + +elementField::elementField(const std::string &fnn, const uint32_t fms, const int ncomp, const dataType dt, + const bool view_=true) : numfile(0), fileName(fnn), fmaxsize(fms), view(view_), + totelem(0), numcomp(ncomp), type(dt){ + this->createFile(); + switch(type){ + case ElementData : + dataname = "ElementData"; + break; + case ElementNodeData : + dataname = "ElementNodeData"; + break; + } +} + +void elementField::buildView(std::vector<partDomain*> &vdom,const double time, + const int nstep, const std::string &valuename, const int cc=-1, const bool binary=false){ + if(view){ + // test file size (and create a new one if needed) + uint32_t fileSize; + FILE *fp = fopen(fileName.c_str(), "r"); + if(!fp){ + Msg::Error("Unable to open file '%s'", fileName.c_str()); + return; + } + fseek (fp, 0, SEEK_END); + fileSize = (uint32_t) (ftell(fp)); + if(fileSize > fmaxsize) this->updateFileName(); + fclose(fp); + fp = fopen(fileName.c_str(), "a"); + + // compute the number of element + if(binary) Msg::Warning("Binary write not implemented yet"); + fprintf(fp, "$%s\n",dataname.c_str()); + fprintf(fp, "1\n\"%s\"\n",valuename.c_str()); + fprintf(fp, "1\n%.16g\n", time); + fprintf(fp, "3\n%d\n%d\n%d\n", nstep, numcomp, totelem); + std::vector<double> fieldData; + if(type == ElementNodeData){ +// for (unsigned int i = 0; i < elasticFields.size(); ++i) + for(std::vector<partDomain*>::iterator itdom=vdom.begin(); itdom!=vdom.end(); ++itdom){ + partDomain *dom = *itdom; + for (groupOfElements::elementContainer::const_iterator it = dom->g->begin(); it != dom->g->end(); ++it){ + MElement *ele = *it; + int numv = ele->getNumVertices(); + this->get(dom,ele,fieldData,cc); + fprintf(fp, "%d %d",ele->getNum(),numv); + for(int i=0;i<numv;i++) + for(int j=0;j<numcomp;j++) + fprintf(fp, " %.16g",fieldData[i+j*numv]); + fprintf(fp,"\n"); + fieldData.clear(); + } + } + } + else if(type == ElementData){ + for (unsigned int i = 0; i < vdom.size(); ++i) + for (groupOfElements::elementContainer::const_iterator it = vdom[i]->g->begin(); it != vdom[i]->g->end(); ++it){ + MElement *ele = *it; + fieldData.resize(numcomp); + this->get(vdom[i],ele,fieldData,cc); + fprintf(fp, "%d",ele->getNum()); + for(int j=0;j<numcomp;j++) + fprintf(fp, " %.16g",fieldData[j]); + fprintf(fp,"\n"); + } + } + fprintf(fp, "$End%s\n",dataname.c_str()); + fclose(fp); + } + else Msg::Warning("No displacement view created because the variable view is set to false for this field\n"); +} + diff --git a/NonLinearSolver/field/elementField.h b/NonLinearSolver/field/elementField.h new file mode 100644 index 0000000000..fdfa53888f --- /dev/null +++ b/NonLinearSolver/field/elementField.h @@ -0,0 +1,51 @@ +// +// C++ Interface: terms +// +// Description: Base class to manage a field on element (All field are managed by element in full Dg so displacement is also +// considered like a field on element +// +// The base class contains archiving data (which is not dependent of the field) +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef ELEMENTFIELD_H_ +#define ELEMENTFIELD_H_ +#include <string> +#include <stdint.h> +#include "MElement.h" +#include <vector> +#include <iostream> +#include <fstream> +class partDomain; +#include "groupOfElements.h" +class elementField{ + protected : + // data needed to archive displacement + // enum for chosen is ElementData or ElementNodeData more ?? + enum dataType{ElementData, ElementNodeData}; + dataType type; + bool view; + std::string fileName; // name of file where the displacement are store + long int totelem; // total number of element present in all elasticFields + uint32_t fmaxsize; // Size max of file in bytes (if size of file is greater a new one is created) TODO Argument for this parameter ? + int numfile; // numero of file + int numcomp; + std::string dataname; + // function to update file name + void updateFileName(); + void createFile(); + + public : + elementField(const std::string &fnn, const uint32_t fms, const int ncomp, const dataType dt, + const bool view_); + ~elementField(){}; + void setTotElem(const int ne){totelem=ne;} + virtual void get(partDomain* dom, MElement *ele,std::vector<double> &fieldData,const int comp=-1)=0; // comp allow to use an enum + // in derivate class to choose which component to save + virtual void buildView(std::vector<partDomain*> &vdom,const double time, + const int nstep, const std::string &valuename, const int cc,const bool binary); +}; +#endif // + diff --git a/NonLinearSolver/field/energyField.cpp b/NonLinearSolver/field/energyField.cpp new file mode 100644 index 0000000000..701150e554 --- /dev/null +++ b/NonLinearSolver/field/energyField.cpp @@ -0,0 +1,173 @@ +// +// C++ Interface: energetic field +// +// Description: Class derived from element field to manage energetic balance +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "energyField.h" +#include "explicitHulbertChung.h" +#include "explicitDofManager.h" +#include "ipField.h" +#include "SVector3.h" +#include "unknownField.h" +#include "unknownDynamicField.h" +double dot(const std::vector<double> &a, const fullVector<typename dofManager<double>::dataMat> &b){ + double c = 0.; + for(int i =0; i<a.size(); i++){ + c += a[i]*b(i); + } + return c; +} + +double dot(const std::vector<double> &a, const std::vector<double> &b){ + double c=0.; + for(int i =0; i<a.size(); i++){ + c += a[i]*b[i]; + } + return c; +} + +double energeticField::kineticEnergy() const { + explicitHCDofManager<double> *ddm = dynamic_cast<explicitHCDofManager<double>*>(_pAssembler); + if(ddm == NULL) return 0.; // system is not dynamic --> kinetic energy = 0 + else return ddm->getKineticEnergy(); +} + +double energeticField::kineticEnergy(MElement *ele, const partDomain *dom) const{ + explicitHulbertChung<double> * esys = dynamic_cast<explicitHulbertChung<double>*>(_lsys); + explicitHCDofManager<double> *ddm = dynamic_cast<explicitHCDofManager<double>*>(_pAssembler); + double ener=0.; + if(ddm != NULL){ + // get Dof + std::vector<Dof> R; + std::vector<double> velocities; + std::vector<double> vmass; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + sp->getKeys(ele,R); + int nkeys = sp->getNumKeys(ele); + ddm->getDofValue(R,velocities,initialCondition::velocity); + ddm->getVertexMass(R,vmass); + for(int i=0; i!=nkeys; i++) + ener+=vmass[i]*velocities[i]*velocities[i]; + R.clear(); velocities.clear(); vmass.clear(); + } + return ener; +} + +double energeticField::deformationEnergy(MElement *ele, const partDomain *dom) const{ + return _ipf->computeDeformationEnergy(ele,dom); +} + +double energeticField::deformationEnergy() const{ + return _ipf->computeDeformationEnergy(); +} + +double energeticField::externalWork(){ + double Deltawext=0.; + for(std::vector<partDomain*>::iterator itdom=_domvec.begin(); itdom!=_domvec.end();++itdom){ + partDomain *dom = *itdom; + for(partDomain::neuContainer::iterator itn=dom->neuBegin(); itn!=dom->neuEnd();++itn){ + nonLinearNeumannBC *neu = *itn; + FunctionSpaceBase *neuspace = neu->_space; + fullVector<typename dofManager<double>::dataMat> localVector; + std::vector<Dof> R; + std::vector<double> disp; + std::vector<double> deltau; + for(groupOfElements::elementContainer::const_iterator it = neu->g->begin(); it!=neu->g->end(); ++it){ + MElement *e = *it; + R.clear(); disp.clear(); deltau.clear(); + IntPt *GP; + //int npts=dom->getBulkGaussIntegrationRule()->getIntPoints(e,&GP); ?????????, + int npts = neu->integ->getIntPoints(e,&GP); + neu->_term->get(e,npts,GP,localVector); + fullVector<typename dofManager<double>::dataMat> fextnp1(localVector); + neuspace->getKeys(e,R); + _ufield->get(R,disp); + int ndofs = neuspace->getNumKeys(e); + // DeltaWext = 0.5*(Fn+1+Fn)*(un+1-un) + for(int i=0;i<ndofs;i++){ + _fextnp1[R[i]] = localVector(i); + localVector(i) += _fextn[R[i]]; + deltau.push_back(disp[i] - _dispn[R[i]]); + _dispnp1[R[i]] = disp[i]; + } + Deltawext += dot(deltau,localVector); + } + } + } + + // Now compute the work of external forces due to prescribed displacement (-Wint - Winertia) + // ATTENTION _allaef containts -fint so no minus + // Do the scalar product on vector (more efficient) TO DO THE SCALAR PRODUCT WITH BLAS HOW ?? + std::vector<double> disp; + std::vector<double> acc; + std::vector<double> _mass; + std::vector<double> forceval; +// std::vector<double> finertval; + std::vector<Dof> R; + for(int i=0; i<_allaef.size(); i++){ + R.push_back(_allaef[i].D); + forceval.push_back(_allaef[i].val); + } + _ufield->get(R,disp); + // Compute inertial forces if needed + explicitHCDofManager<double> *ddm = dynamic_cast<explicitHCDofManager<double>*>(_pAssembler); + if(ddm != NULL){ // otherwise static cases and no inertial forces + unknownDynamicField *duf = dynamic_cast<unknownDynamicField*>(_ufield); + duf->get(R,acc,initialCondition::acceleration); + ddm->getVertexMass(R,_mass); + for(int i=0; i<forceval.size(); i++) + forceval[i] -= _mass[i]*acc[i]; + } + for(int i=0;i<R.size(); i++){ + _fextnp1[R[i]] = forceval[i]; + forceval[i] += _fextn[R[i]]; + _dispnp1[R[i]] = disp[i]; + disp[i] -= _dispn[R[i]]; + } + + Deltawext += dot(forceval,disp); + + // swap value (next step) + _fextn.swap(_fextnp1); + _dispn.swap(_dispnp1); + + // New value of Wext W = 0.5*F*u + _wext += 0.5*Deltawext; + return _wext; +} + +void energeticField::get(partDomain *dom,MElement *ele,std::vector<double> &ener, const int cc){ + switch(cc){ + //case 0: + // ener[0] = this->kineticEnergy(ele,dom) + this->deformationEnergy(ele,dom); + // break; + case 1: + ener[0] = this->kineticEnergy(ele,dom); + break; + case 2: + ener[0] = this->deformationEnergy(ele,dom); + break; + case 3: + ener[0] = this->externalWork(); + default: + ener[0] = this->kineticEnergy(ele,dom) + this->deformationEnergy(ele,dom); + } +} + +void energeticField::archive(const double time){ + FILE *fp = fopen(_fname.c_str(),"a"); + double ekin,edefo,etot,wext; + ekin = this->kineticEnergy(); + edefo= this->deformationEnergy(); + wext = this->externalWork(); + etot = ekin + edefo; + fprintf(fp,"%e;%e;%e;%e;%e;\n",time,ekin,edefo,wext,etot); + fclose(fp); +} + diff --git a/NonLinearSolver/field/energyField.h b/NonLinearSolver/field/energyField.h new file mode 100644 index 0000000000..06333e0f6b --- /dev/null +++ b/NonLinearSolver/field/energyField.h @@ -0,0 +1,89 @@ +// +// C++ Interface: energetic field +// +// Description: Class derived from element field to manage energetic balance +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef ENERGETICFIELD_H_ +#define ENERGETICFIELD_H_ + +#include "elementField.h" +#include "nonLinearMechSolver.h" +class energeticField : public elementField{ + protected: + linearSystem<double> *_lsys; + IPField *_ipf; + unknownField *_ufield; + dofManager<double> *_pAssembler; + const std::string _fname; // file to store total energy in function of time + std::vector<partDomain*> &_domvec; + std::vector<fextPrescribedDisp> &_allaef; + std::map<Dof,double> _fextn; + std::map<Dof,double> _dispn; + std::map<Dof,double> _fextnp1; + std::map<Dof,double> _dispnp1; + + double _wext; + + public: + energeticField(linearSystem<double> *lsys, IPField *ipf, + unknownField *ufield, dofManager<double> *pAssembler, + std::vector<partDomain*> &domvec, + std::vector<fextPrescribedDisp> &allaef) : elementField("energy.msh",100000000,1,elementField::ElementData,true), + _lsys(lsys), _ipf(ipf), _ufield(ufield), _pAssembler(pAssembler), + _fname("energy.csv"), _domvec(domvec), _allaef(allaef), _wext(0.){ + // initialize file to store energy + FILE *fp = fopen(_fname.c_str(),"w"); + fprintf(fp,"Time;Kinetic;Deformation;Wext;Total\n"); + fprintf(fp,"0.;0.;0.;0;0.\n"); // false if initial deformation FIX IT HOW ?? + fclose(fp); + long int nelem=0; + for(std::vector<partDomain*>::iterator itdom=_domvec.begin(); itdom!=_domvec.end();++itdom){ + partDomain *dom = *itdom; + nelem+=dom->g->size(); + for(partDomain::neuContainer::iterator itn=dom->neuBegin(); itn!=dom->neuEnd();++itn){ + nonLinearNeumannBC *neu = *itn; + FunctionSpaceBase *neuspace = neu->_space; + std::vector<Dof> R; + for(groupOfElements::elementContainer::const_iterator it = neu->g->begin(); it!=neu->g->end(); ++it){ + MElement *e = *it; + R.clear(); + neuspace->getKeys(e,R); + int ndofs = neuspace->getNumKeys(e); + for(int i=0;i<ndofs;i++){ + _fextn.insert(std::pair<Dof,double>(R[i],0.)); + _dispn.insert(std::pair<Dof,double>(R[i],0.)); + _fextnp1.insert(std::pair<Dof,double>(R[i],0.)); + _dispnp1.insert(std::pair<Dof,double>(R[i],0.)); + } + } + } + } + this->setTotElem(nelem); + // Wext for prescribed displacement + for(int i=0; i<_allaef.size(); i++){ + _fextn.insert(std::pair<Dof,double>(_allaef[i].D,0.)); + _dispn.insert(std::pair<Dof,double>(_allaef[i].D,0.)); + _fextnp1.insert(std::pair<Dof,double>(_allaef[i].D,0.)); + _dispnp1.insert(std::pair<Dof,double>(_allaef[i].D,0.)); + } + } + ~energeticField(){} + + // functions to compute the different parts of energy + double kineticEnergy() const; // More efficient than a loop on element thanks to vector operation via PETSC + double kineticEnergy(MElement *ele, const partDomain *dom) const; + double deformationEnergy(MElement *ele, const partDomain *dom) const; + double deformationEnergy() const; + double externalWork(); + + void get(partDomain *dom,MElement *ele,std::vector<double> &ener, const int cc = -1); + void archive(const double time); +}; +#endif // ENERGETICFIELD_H_ + diff --git a/NonLinearSolver/internalPoints/CMakeLists.txt b/NonLinearSolver/internalPoints/CMakeLists.txt index 5b693a1305..2990968ad2 100644 --- a/NonLinearSolver/internalPoints/CMakeLists.txt +++ b/NonLinearSolver/internalPoints/CMakeLists.txt @@ -4,7 +4,10 @@ # bugs and problems to <gmsh@geuz.org>. set(SRC + ipField.cpp ipstate.cpp + # inline + ipvariable.h ) file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) diff --git a/NonLinearSolver/internalPoints/ipField.cpp b/NonLinearSolver/internalPoints/ipField.cpp new file mode 100644 index 0000000000..077254f577 --- /dev/null +++ b/NonLinearSolver/internalPoints/ipField.cpp @@ -0,0 +1,293 @@ +// +// C++ Interface: terms +// +// Description: Class to compute Internal point +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "ipField.h" +#include "mlaw.h" +#include "ipstate.h" +#include "nonLinearMechSolver.h" +void IPField::compute1state(IPStateBase::whichState ws){ + for(std::vector<partDomain*>::iterator itdom=_efield->begin(); itdom!=_efield->end(); ++itdom){ + partDomain *dom = *itdom; + dom->computeIPVariable(_AIPS,_ufield,ws); + } +} + +void IPField::initialBroken(MElement *iele, materialLaw* mlaw ){ + Msg::Info("Interface element %d is broken at initialization",iele->getNum()); + materialLaw2LawsInitializer * mflaw = dynamic_cast<materialLaw2LawsInitializer*>(mlaw); + // get ipstate + AllIPState::ipstateElementContainer *vips; + IPStateBase *ips; + vips = _AIPS->getIPstate(iele->getNum()); + for(int i=0;i<vips->size();i++){ + ips = (*vips)[i]; + mflaw->initialBroken(ips); + } +} + +void IPField::initialBroken(GModel* pModel, std::vector<int> &vnumphys){ + std::vector<MVertex*> vv; + for(int i=0;i<vnumphys.size();i++){ + // get the vertex associated to the physical entities + pModel->getMeshVerticesForPhysicalGroup(1,vnumphys[i],vv); + // find the InterfaceElement associated to these vertex (identify interior node as degree 2 min) + for(std::vector<partDomain*>::iterator itfield = _efield->begin(); itfield != _efield->end(); ++itfield){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(*itfield); + for(groupOfElements::elementContainer::const_iterator it = dgdom->gi->begin(); it!=dgdom->gi->end(); ++it) + for(int k=0;k<vv.size();k++) + if(vv[k] == (*it)->getVertex(2) ) this->initialBroken(*it, dgdom->getMaterialLaw()); + } + vv.clear(); + } +} + +void IPField::archive(const double time){ + for(std::vector<ip2archive>::iterator it=viparch.begin(); it!=viparch.end(); ++it){ + ip2archive &ipa = *it; + // get ip value + double val; + switch(ipa.comp){ + case -1 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,-1); + break; + case 0 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,component::xx); + break; + case 1 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,component::yy); + break; + case 2 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,component::zz); + break; + case 3 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,component::xy); + break; + case 4 : + val = this->getStress(ipa.domain,ipa.ele,IPStateBase::current,ipa.numgauss,-1); + } + FILE *fp = fopen(ipa.fname.c_str(),"a"); + fprintf(fp,"%e;%e\n",time,val); + fclose(fp); + } +} + +double IPField::computeDeformationEnergy(MElement *ele, const partDomain *dom) const +{ + IntPt *GP; + double jac[3][3]; + int npts = dom->getBulkGaussIntegrationRule()->getIntPoints(ele,&GP); + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(ele->getNum()); + double ener =0.; + for(int i=0;i<npts;i++){ + IPStateBase* ips = (*vips)[i]; + IPVariableMechanics *ipv = dynamic_cast<IPVariableMechanics*>(ips->getState(IPStateBase::current)); + #ifdef DEBUG_ + if(ipv == NULL){ + Msg::Error("Compute defo energy on an non mechanics gauss' point"); + return 0.; + } + #endif + double enerpt = ipv->defoEnergy(); + // gauss point weight + double weight = GP[i].weight; + // Shell Only compute detJ OK +// IPVariableShell *ipvs = dynamic_cast<IPVariableShell*>(ipv); +// double detJ2 = ipvs->getLocalBasis()->getJacobian(); + const double u = GP[i].pt[0]; const double v = GP[i].pt[1]; const double w = GP[i].pt[2]; + const double detJ = ele->getJacobian(u, v, w, jac); + ener += weight*detJ*enerpt; + } + return ener; +} + +IPField::IPField(std::vector<partDomain*> *ef,dofManager<double>* pa, + GModel *pmo, unknownField* uf, std::vector<archiveIPVariable> &vaip): _efield(ef), _dm(pa), + _ufield(uf), + elementField("stress.msh",100000000,1, + elementField::ElementData,true){ + // Creation of storage for IP data + _AIPS = new AllIPState(pmo, *_efield); + // compute the number of element + long int nelem=0; + for(std::vector<partDomain*>::iterator itdom=_efield->begin(); itdom!=_efield->end(); ++itdom){ + partDomain *dom = *itdom; + nelem+= dom->g->size(); + } + this->setTotElem(nelem); + this->buildView(*_efield,0.,0,"VonMises",-1,false); + this->buildView(*_efield,0.,0,"sigmaxx",0,false); + this->buildView(*_efield,0.,0,"sigmayy",1,false); + this->buildView(*_efield,0.,0,"tauxy",3,false); + + // Initiate file + FILE *fp = fopen("cohesiveLaw.csv","w"); + fprintf(fp,"time;inter num;gauss num;sc;deltac;delta;d_n;d_t;n22;m22;n21;m21\n"); + fclose(fp); + fp = fopen("crackPath.csv","w"); + fprintf(fp,"time;inter num;x0;y0;z0;x1;y1;z1\n"); + fclose(fp); + + // Build the viparch vector (find the nearest ipvariable to each given vertex) + for(std::vector<archiveIPVariable>::iterator ita=vaip.begin(); ita!=vaip.end(); ++ita){ + archiveIPVariable &aip = *ita; + // get the vertex of the node + groupOfElements g(0,aip.numphys); + groupOfElements::vertexContainer::iterator itv = g.vbegin(); + MVertex *ver = *itv; + bool flagfind=false; + MElement *elefind = NULL; + partDomain *domfind; + dgPartDomain *dgdom; + bool samedim = false; + for(std::vector<partDomain*>::iterator itdom=_efield->begin(); itdom!=_efield->end(); ++itdom){ + partDomain *dom = *itdom; + dgdom = dynamic_cast<dgPartDomain*>(dom); + if(dgdom != NULL){ // otherwise the domain doesn't contain interface element + for(groupOfElements::elementContainer::iterator it2 = dgdom->gi->begin(); it2 != dgdom->gi->end(); ++it2 ){ + MElement *iele = *it2; // two elements on interface + int numv = iele->getNumVertices(); + for(int j=0;j<numv;j++){ + if(ver == iele->getVertex(j)){ + elefind = iele; + domfind = dom; + flagfind = true; + break; + } + } + if(flagfind) break; + } + if(!flagfind){ // the interface element are on boundary + for(groupOfElements::elementContainer::iterator iti = dgdom->gib->begin(); iti!=dgdom->gib->end(); ++iti){ + MElement *ie = *iti; + int numv = ie->getNumVertices(); + for(int j=0;j<numv;j++){ + if(ver == ie->getVertex(j)){ + elefind = ie; + domfind = dom; + flagfind = true; + break; + } + } + if(flagfind) break; + } + } + } + if(!flagfind){ // no interface element found (Can happend on boundary) + for(groupOfElements::elementContainer::iterator it2 = dom->g->begin(); it2 != dom->g->end(); ++it2 ){ + MElement *ele = *it2; + int numv = ele->getNumVertices(); + for(int j=0;j<numv;j++){ + if(ver == ele->getVertex(j)){ + elefind = ele; + samedim = true; + flagfind = true; + domfind = dom; + break; + } + } + if(flagfind) break; + } + } + } + // Now the element where is situated the node is know find the nearest Gauss Point + IntPt *GP; + QuadratureBase *gq; + if(samedim){ //bulk point + gq = domfind->getBulkGaussIntegrationRule(); + } + else{ + dgPartDomain *dgfind = dynamic_cast<dgPartDomain*>(domfind); + gq = dgfind->getInterfaceGaussIntegrationRule(); + } + int npts = gq->getIntPoints(elefind,&GP); + // coordonate in uvw of vertex + double uvw[3]; + double xyz[3]; + xyz[0] = ver->x(); xyz[1] = ver->y(); xyz[2] = ver->z(); + elefind->xyz2uvw(xyz,uvw); + double distmin = 1.e100; // inf value at itnitialization + double dist, u,v,w; + int nummin; + for(int i=0;i<npts;i++){ + u = GP[i].pt[0]; v = GP[i].pt[1]; w = GP[i].pt[2]; + dist = sqrt((u-uvw[0])*(u-uvw[0]) + (v-uvw[1])*(v-uvw[1]) + (w-uvw[2])*(w-uvw[2])); + if(dist<distmin){ + distmin = dist; + nummin = i; + } + } + // Store information + viparch.push_back(ip2archive(elefind,domfind,aip.numphys,nummin,aip.ipval)); + // remove file LINUX ONLY ?? + std::ostringstream oss; + oss << aip.numphys; + std::string s = oss.str(); + oss.str(""); + oss << aip.ipval; + std::string s2 = oss.str(); + std::string rfname = "rm IP"+s+"val"+s2+".csv"; + system(rfname.c_str()); + } +} + +double IPField::getStress(const partDomain *ef,MElement *ele, const IPStateBase::whichState ws, + const int num, const int cmp) const{ + double svm =0.; + if(num<10000){ // value in a particular gauss point + IPStateBase* ips = (*_AIPS->getIPstate(ele->getNum()))[num]; + IPVariableMechanics *ipv = dynamic_cast<IPVariableMechanics*>(ips->getState(ws)); + #ifdef DEBUG_ + if(ipv != NULL) + #endif + return ipv->stressComp(cmp); + #ifdef DEBUG_ + else{ + Msg::Error("Compute Von Mises stress on a non mechanical element"); + return 0.; + } + #endif + } + else{ // loop on all IPVariable of an element and return a particular value (max, min, mean) + double svmp; + IntPt *GP; + int npts = ef->getBulkGaussIntegrationRule()->getIntPoints(ele,&GP); + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(ele->getNum()); + for(int i=0;i<npts;i++){ + IPStateBase* ips = (*vips)[i]; + IPVariableMechanics *ipv = dynamic_cast<IPVariableMechanics*>(ips->getState(ws)); + #ifdef DEBUG_ + if(ipv == NULL){ + Msg::Error("Compute Von Mises stress on a non mechanical element"); + return 0.; + } + #endif + svmp = ipv->stressComp(cmp); + if(i==0) + svm = svmp; + else{ + switch(num){ + case IPField::max : + if(svmp>svm) svm=svmp; + break; + case IPField::min : + if(svmp<svm) svm=svmp; + break; + case IPField::mean : + svm+=svmp; + break; + } + } + } + if(num==IPField::mean) svm/=(double)npts; + } + return svm; +} + diff --git a/NonLinearSolver/internalPoints/ipField.h b/NonLinearSolver/internalPoints/ipField.h new file mode 100644 index 0000000000..a5a427f36a --- /dev/null +++ b/NonLinearSolver/internalPoints/ipField.h @@ -0,0 +1,237 @@ +// +// C++ Interface: terms +// +// Description: Class to compute Internal point +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +# ifndef _IPFIELD_H_ +# define _IPFIELD_H_ +#include<vector> +#include"Dof3IntType.h" +#include"quadratureRules.h" +#include "unknownField.h" +#include "elementField.h" +#include "GModel.h" +#include "ipstate.h" +#include "partDomain.h" +struct archiveIPVariable; +class IPField : public elementField { + protected : + // Struct for archiving + struct ip2archive{ + MElement *ele; // element where the point is situated (if node is common to several element the first one met is chosen. Normally OK continuity) + int numgauss; // local gauss num + std::string fname; // file name where archive IP + int comp; // component to archive + const partDomain *domain; // address of domain needed to access IP + // constructor + ip2archive(MElement *e, const partDomain *dom, const int nump, const int num, const int ipval) : ele(e), + domain(dom),numgauss(num), comp(ipval){ + // build file name + std::ostringstream oss; + oss << nump; + std::string s = oss.str(); + oss.str(""); + oss << ipval; + std::string s2 = oss.str(); + fname = "IP"+s+"val"+s2+".csv"; + } + ip2archive(const ip2archive &source) : ele(source.ele), domain(source.domain){ + numgauss = source.numgauss; + fname = source.fname; + comp =source.comp; + } + ~ip2archive(){} + }; + std::vector<partDomain*>* _efield; + dofManager<double> *_dm; + AllIPState *_AIPS; + unknownField *_ufield; + std::vector<ip2archive> viparch; +// normalVariation _nvaripfield; // To avoid multiple allocation + public : + enum ElemValue{mean=10001, max=10002, min=10003}; // enum to select a particular value on element + IPField(std::vector<partDomain*> *ef,dofManager<double>* pa, + GModel *pmo, unknownField* uf, std::vector<archiveIPVariable> &vaip); + void archive(const double time); + + AllIPState* getAips() const {return _AIPS;} + ~IPField(){delete _AIPS;} + void compute1state(IPStateBase::whichState ws); + + // On element only ?? Higher level to pass the associated element (pass edge num) + // get value with a operation + double getStress(const partDomain *ef,MElement *ele, const IPStateBase::whichState ws, const int num, + const int cmp) const; + // function to archive + virtual void get(partDomain *dom, MElement *ele, std::vector<double> &stress, const int cc=-1){ + switch(cc){ + case -1 : + stress[0]= this->getStress(dom,ele,IPStateBase::current,mean,-1); + break; + case 0 : + stress[0] = this->getStress(dom,ele,IPStateBase::current,mean,component::xx); + break; + case 1 : + stress[0] = this->getStress(dom,ele,IPStateBase::current,mean,component::yy); + break; + case 2 : + stress[0] = this->getStress(dom,ele,IPStateBase::current,mean,component::zz); + break; + case 3 : + stress[0] = this->getStress(dom,ele,IPStateBase::current,mean,component::xy); + break; + case 4 : + stress[0]= this->getStress(dom,ele,IPStateBase::current,max,-1); + } + } + + // Interaction with Aips + void copy(IPStateBase::whichState source, IPStateBase::whichState dest){_AIPS->copy(source,dest);} + void nextStep(const double time=0.){ + _AIPS->nextStep(); + } + + // initial broken + void initialBroken(GModel* pModel, std::vector<int> &vnumphys); + void initialBroken(MElement *iele, materialLaw *mlaw); + + template<class T> void getIPv(const MElement *ele,const T** vipv, const IPStateBase::whichState ws= IPStateBase::current) const + { + AllIPState::ipstateElementContainer* vips = _AIPS->getIPstate(ele->getNum()); + for(int i=0; i<vips->size(); i++){ + IPStateBase* ips = (*vips)[i]; + vipv[i] = dynamic_cast<const T*>(ips->getState(ws)); + } + } + template<class T> void getIPv(const MElement *ele,const T** vipv, const T** vipvprev) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(ele->getNum()); + for(int i=0; i<vips->size(); i++){ + IPStateBase* ips = (*vips)[i]; + vipv[i] = dynamic_cast<const T*>(ips->getState(IPStateBase::current)); + vipvprev[i] = dynamic_cast<const T*>(ips->getState(IPStateBase::previous)); + } + } + template<class T1,class T2> void getIPv(const MInterfaceElement *iele, const T1** vipv_m, const T2** vipv_p, + const IPStateBase::whichState ws=IPStateBase::current) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size()/2; + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + IPStateBase *ipsp = (*vips)[i+npts]; + vipv_m[i] = dynamic_cast<const T1*>(ipsm->getState(ws)); + vipv_p[i] = dynamic_cast<const T2*>(ipsp->getState(ws)); + } + } + template<class T1,class T2> void getIPv(const MInterfaceElement *iele, const T1** vipv_m, const T1** vipvprev_m, + const T2** vipv_p, const T2** vipvprev_p) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size()/2; + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + IPStateBase *ipsp = (*vips)[i+npts]; + vipv_m[i] = dynamic_cast<const T1*>(ipsm->getState(IPStateBase::current)); + vipv_p[i] = dynamic_cast<const T2*>(ipsp->getState(IPStateBase::current)); + vipvprev_m[i] = dynamic_cast<const T1*>(ipsm->getState(IPStateBase::previous)); + vipvprev_p[i] = dynamic_cast<const T2*>(ipsp->getState(IPStateBase::previous)); + } + } + template<class T1,class T2> void getIPv(const MInterfaceElement *iele, T1** vipv_m, T2** vipv_p, + const IPStateBase::whichState ws=IPStateBase::current) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size()/2; + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + IPStateBase *ipsp = (*vips)[i+npts]; + vipv_m[i] = dynamic_cast<T1*>(ipsm->getState(ws)); + vipv_p[i] = dynamic_cast<T2*>(ipsp->getState(ws)); + } + } + template<class T1,class T2> void getIPv(const MInterfaceElement *iele, T1** vipv_m, T2** vipvprev_m, + T2** vipv_p, T2** vipvprev_p) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size()/2; + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + IPStateBase *ipsp = (*vips)[i+npts]; + vipv_m[i] = dynamic_cast<T1*>(ipsm->getState(IPStateBase::current)); + vipv_p[i] = dynamic_cast<T2*>(ipsp->getState(IPStateBase::current)); + vipvprev_m[i] = dynamic_cast<T1*>(ipsm->getState(IPStateBase::previous)); + vipvprev_p[i] = dynamic_cast<T2*>(ipsp->getState(IPStateBase::previous)); + } + } + + + template<class T1> void getIPv(const MInterfaceElement *iele, const T1** vipv_m, + const IPStateBase::whichState ws=IPStateBase::current) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size(); + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + vipv_m[i] = dynamic_cast<const T1*>(ipsm->getState(ws)); + } + } + template<class T1> void getIPv(const MInterfaceElement *iele, const T1** vipv_m, const T1** vipvprev_m) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + // SAME NUMBER OF GAUSS POINTS ON BOTH SIDES + int npts = vips->size(); + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + vipv_m[i] = dynamic_cast<const T1*>(ipsm->getState(IPStateBase::current)); + vipvprev_m[i] = dynamic_cast<const T1*>(ipsm->getState(IPStateBase::previous)); + } + } + + template<class T1> void getIPv(const MInterfaceElement *iele, T1** vipv_m, + const IPStateBase::whichState ws=IPStateBase::current) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + int npts = vips->size(); + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + vipv_m[i] = dynamic_cast<T1*>(ipsm->getState(ws)); + } + } + template<class T1> void getIPv(const MInterfaceElement *iele, T1** vipv_m, T1** vipvprev_m) const + { + AllIPState::ipstateElementContainer *vips = _AIPS->getIPstate(iele->getNum()); + int npts = vips->size(); + for(int i=0;i<npts;i++){ + IPStateBase *ipsm = (*vips)[i]; + vipv_m[i] = dynamic_cast<T1*>(ipsm->getState(IPStateBase::current)); + vipvprev_m[i] = dynamic_cast<T1*>(ipsm->getState(IPStateBase::previous)); + } + } + double computeDeformationEnergy(MElement *ele, const partDomain *dom) const; + double computeDeformationEnergy() const{ +// Msg::Error("Defo energy only for shell"); + double ener=0.; + for(std::vector<partDomain*>::const_iterator itdom=_efield->begin(); itdom!=_efield->end(); ++itdom){ + partDomain *dom = *itdom; + for(groupOfElements::elementContainer::const_iterator it=dom->g->begin(); it!=dom->g->end(); ++it){ + MElement *ele = *it; + ener += this->computeDeformationEnergy(ele,dom); + } + } + return ener; + } +}; +#endif // IPField + diff --git a/NonLinearSolver/internalPoints/ipstate.cpp b/NonLinearSolver/internalPoints/ipstate.cpp index d3333c5644..0d7ab3c965 100644 --- a/NonLinearSolver/internalPoints/ipstate.cpp +++ b/NonLinearSolver/internalPoints/ipstate.cpp @@ -1 +1,125 @@ +// +// C++ Interface: terms +// +// Description: Class to store internal variables at gauss point +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + #include "ipstate.h" +#include "partDomain.h" +#include "MInterfaceElement.h" +#include "MElement.h" +IP3State::~IP3State(){ + if(_initial) delete _initial; + if(_step2) delete _step2; + if(_step1) delete _step1; +} + +IP3State::IP3State(const IP3State &source) : IPStateBase() +{ + _initial = source._initial; + _step1 = source._step1; + _step2 = source._step2; + _st = source._st; +} + +IP3State & IP3State::operator = (const IPStateBase &source){ + IPStateBase::operator=(source); + const IP3State *src = dynamic_cast<const IP3State*>(&source); + *_initial = *src->_initial; + *_step1 = *src->_step1; + *_step2 = *src->_step2; + _st = src->_st; + return *this; +} + +IPVariable* IP3State::getState(const whichState wst) const +{ + switch(wst){ + case initial : + return _initial; + break; + case previous : + if(*_st) return _step1; else return _step2; + break; + case current : + if(*_st) return _step2; else return _step1; + break; + default : Msg::Error("Impossible to select the desired state for internal variable \n"); + } +} + +AllIPState::AllIPState(GModel *pModel, std::vector<partDomain*> &vdom) +{ + state = true; // at creation of object state is true + IntPt *GP; // needed to know the number of gauss point + for(std::vector<partDomain*>::iterator itdom=vdom.begin(); itdom!=vdom.end(); ++itdom){ + partDomain *dom = *itdom; + if(dom->IsInterfaceTerms()){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + materialLaw *mlawMinus = dgdom->getMaterialLawMinus(); + materialLaw *mlawPlus = dgdom->getMaterialLawPlus(); + // loop + for(groupOfElements::elementContainer::const_iterator it=dgdom->gi->begin(); it!=dgdom->gi->end();++it){ + MElement *ele = *it; + MInterfaceElement* iele = dynamic_cast<MInterfaceElement*>(ele); + // 2* because IP is duplicated for fullDg formulation + int npts_inter=2*dgdom->getInterfaceGaussIntegrationRule()->getIntPoints(ele,&GP); + ipstateElementContainer tp(npts_inter); + for(int i=0;i<npts_inter/2;i++){ + mlawMinus->createIPState(tp[i],&state,ele,iele->getElem(0)->getNumVertices()); + } + for(int i=npts_inter/2;i<npts_inter;i++){ + mlawPlus->createIPState(tp[i],&state,ele,iele->getElem(1)->getNumVertices()); + } + _mapall.insert(ipstatePairType(iele->getNum(),tp)); + } + // Virtual interface element (no duplication) + materialLaw *mlaw = dgdom->getMaterialLaw(); + for(groupOfElements::elementContainer::const_iterator it=dgdom->gib->begin(); it!=dgdom->gib->end();++it){ + MElement *ele = *it; + MInterfaceElement *iele = dynamic_cast<MInterfaceElement*>(ele); + int npts_inter=dgdom->getInterfaceGaussIntegrationRule()->getIntPoints(ele,&GP); + ipstateElementContainer tp(npts_inter); + for(int i=0;i<npts_inter;i++){ + mlaw->createIPState(tp[i],&state,ele,iele->getElem(0)->getNumVertices()); + } + _mapall.insert(ipstatePairType(iele->getNum(),tp)); + } + } + // bulk element + materialLaw *mlaw = dom->getMaterialLaw(); + for (groupOfElements::elementContainer::const_iterator it = dom->g->begin(); it != dom->g->end(); ++it){ + MElement *ele = *it; + int npts_bulk=dom->getBulkGaussIntegrationRule()->getIntPoints(ele,&GP); + ipstateElementContainer tp(npts_bulk); + for(int i=0;i<npts_bulk;i++){ + mlaw->createIPState(tp[i],&state,ele,ele->getNumVertices()); + } + _mapall.insert(ipstatePairType(ele->getNum(),tp)); + } + } +} +AllIPState::~AllIPState() +{ + for(ipstateContainer::iterator it=_mapall.begin();it!=_mapall.end();++it){ + ipstateElementContainer vips = (*it).second; + for(int i=0;i<vips.size();i++) + delete vips[i]; + } +}; + +AllIPState::ipstateElementContainer* AllIPState::getIPstate(const long int num) +{ + return &(_mapall.find(num)->second); +} + +AllIPState::ipstateElementContainer* AllIPState::operator[](const long int num) +{ + return &(_mapall.find(num)->second); +} diff --git a/NonLinearSolver/internalPoints/ipstate.h b/NonLinearSolver/internalPoints/ipstate.h index e69de29bb2..e6489ca1e1 100644 --- a/NonLinearSolver/internalPoints/ipstate.h +++ b/NonLinearSolver/internalPoints/ipstate.h @@ -0,0 +1,74 @@ +// +// C++ Interface: terms +// +// Description: Class to store internal variables at gauss point +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef IPSTATE_H_ +#define IPSTATE_H_ +#include "GModel.h" +#include "ipvariable.h" +// enum to access to component of stress and deformation GLOBAL ?? +struct component{ + enum enumcomp{xx,yy,zz,xy,xz,yz}; +}; +class partDomain; +class dgPartDomain; +class materialLaw; +class IPStateBase{ + public: + IPStateBase(){} + IPStateBase(const IPStateBase &source){} + virtual IPStateBase& operator=(const IPStateBase &source){return *this;} + enum whichState{initial, previous, current}; // keep previous OVERLOAD enum in daughter class ??? + virtual IPVariable* getState(const whichState wst=IPStateBase::current) const=0; +}; + +class IP3State : public IPStateBase{ + protected : + IPVariable *_initial; // initial state t=0 + IPVariable *_step1; // previous step if _st = true and current step otherwise + IPVariable *_step2; // current step if _st = true and previous step otherwise + const bool *_st; // pointer on a bool value to choice what vector is current and what vector is previous + public : + IP3State(bool *st) : IPStateBase(),_st(st), _initial(NULL), _step1(NULL), _step2(NULL){} + IP3State(const bool *st,IPVariable *init, + IPVariable *st1, IPVariable *st2): _st(st), _initial(init), _step1(st1), _step2(st2){} + ~IP3State(); + IP3State(const IP3State &source); + virtual IP3State & operator = (const IPStateBase &source); + IPVariable* getState(const whichState wst=IPStateBase::current) const; +}; + +// Class to access to the IPState of all gauss point +class AllIPState{ + public: + typedef std::map<long int, std::vector<IPStateBase*> > ipstateContainer; + typedef std::pair<long int, std::vector<IPStateBase*> > ipstatePairType; + typedef std::vector<IPStateBase*> ipstateElementContainer; + protected: + ipstateContainer _mapall; + bool state; // flag to switch previous and current (change the pointer in place of copy all variables) + public : + AllIPState(GModel *pModel, std::vector<partDomain*> &vdom); + ~AllIPState(); + ipstateElementContainer* getIPstate(const long int num); + ipstateElementContainer* operator[](const long int num); + void nextStep() {state ? state=false : state=true;} // change boolvalue + void copy(const IPStateBase::whichState ws1, const IPStateBase::whichState ws2){ + for(ipstateContainer::iterator it=_mapall.begin(); it!=_mapall.end();++it){ + std::vector<IPStateBase*> *vips = &((*it).second); + for(int i=0;i<vips->size();i++){ + IPVariable *ipv1= (*vips)[i]->getState(ws1); + IPVariable *ipv2= (*vips)[i]->getState(ws2); + *ipv2 =*ipv1; + } + } + } +}; +#endif // IPSTATE_H_ diff --git a/NonLinearSolver/internalPoints/ipvariable.h b/NonLinearSolver/internalPoints/ipvariable.h new file mode 100644 index 0000000000..ef4a9a1636 --- /dev/null +++ b/NonLinearSolver/internalPoints/ipvariable.h @@ -0,0 +1,93 @@ +// +// C++ Interface: ipvariable +// +// Description: Base class for ipvariable +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// class with the variables of IP (stress, deformation and localBasis) + +#ifndef IPVARIABLE_H_ +#define IPVARIABLE_H_ +#include <stdlib.h> +#include <stdio.h> + +class IPVariable +{ + public : + IPVariable(){} + virtual ~IPVariable(){} + // copie constructor + IPVariable(const IPVariable &source){}; + virtual IPVariable &operator=(const IPVariable &source){return *this;}; +}; + +class IPVariableMechanics : public IPVariable{ + public: + IPVariableMechanics(): IPVariable(){} + IPVariableMechanics(const IPVariableMechanics &source) : IPVariable(source){}; + virtual IPVariableMechanics &operator=(const IPVariable &source){ + IPVariable::operator=(source); + return *this; + } + virtual double defoEnergy() const{return 0;} + virtual double stressComp(const int i) const{return 0;} +}; + +template<class Tbulk,class Tfrac> class IPVariable2ForFracture : virtual public IPVariableMechanics{ + protected: + Tbulk *_ipvbulk; + Tfrac *_ipvfrac; + bool _broken; // To know which law to use + public: + IPVariable2ForFracture() : IPVariableMechanics(), _ipvbulk(NULL), _ipvfrac(NULL), _broken(false){} + IPVariable2ForFracture(const IPVariable2ForFracture &source) : IPVariableMechanics(source), _broken(source._broken) + { + (*_ipvbulk) = (*(dynamic_cast<const IPVariable*>(source._ipvbulk))); + if(source._ipvfrac != NULL) + if(_ipvfrac == NULL) _ipvfrac = new Tfrac(*(source._ipvfrac)); + else (*_ipvfrac) = (*(dynamic_cast<const IPVariable*>(source._ipvfrac))); + } + IPVariable2ForFracture& operator=(const IPVariable &source) + { + IPVariableMechanics::operator=(source); + const IPVariable2ForFracture *ipvf =dynamic_cast<const IPVariable2ForFracture *> (&source); + _broken = ipvf->_broken; + (*_ipvbulk) = (*(dynamic_cast<const IPVariableMechanics*>(ipvf->_ipvbulk))); + if(ipvf->_ipvfrac != NULL){ + if(_ipvfrac == NULL) _ipvfrac = new Tfrac(*(ipvf->_ipvfrac)); + else (*_ipvfrac) = (*(dynamic_cast<IPVariableMechanics*>(ipvf->_ipvfrac))); + } + else{ + if(_ipvfrac != NULL) delete _ipvfrac; + _ipvfrac =NULL; + } + return *this; + } + ~IPVariable2ForFracture() + { + if(_ipvbulk != NULL){ + delete _ipvbulk; + } + if(_ipvfrac != NULL){ + delete _ipvfrac; + } + } + const bool broken() const{return _broken;} + bool isbroken(){return _broken;} + void broken(){_broken=true;} + void nobroken(){_broken=false;} + Tbulk* getIPvBulk(){return _ipvbulk;} + const Tbulk* getIPvBulk() const{return _ipvbulk;} + Tfrac* getIPvFrac(){return _ipvfrac;} + const Tfrac* getIPvFrac() const {return _ipvfrac;} + void setIPvBulk(IPVariable *ipv){ _ipvbulk = dynamic_cast<Tbulk*>(ipv);} + void setIPvFrac(IPVariable *ipv){ _ipvfrac = dynamic_cast<Tfrac*>(ipv);} +}; + +#endif //IPVARIABLE_H_ + diff --git a/NonLinearSolver/materialLaw/CMakeLists.txt b/NonLinearSolver/materialLaw/CMakeLists.txt new file mode 100644 index 0000000000..39d2c54aa8 --- /dev/null +++ b/NonLinearSolver/materialLaw/CMakeLists.txt @@ -0,0 +1,11 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + mlaw.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/materialLaw "${SRC};${HDR}") diff --git a/NonLinearSolver/materialLaw/mlaw.cpp b/NonLinearSolver/materialLaw/mlaw.cpp new file mode 100644 index 0000000000..10add0ba1e --- /dev/null +++ b/NonLinearSolver/materialLaw/mlaw.cpp @@ -0,0 +1,26 @@ +// +// +// +// Description: Define material law +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "mlaw.h" +materialLaw::materialLaw(const int num, const bool init): _num(num), _initialized(init){} + +materialLaw::materialLaw(const materialLaw &source) +{ + _num = source._num; + _initialized = source._initialized; +} + +materialLaw& materialLaw::operator=(const materialLaw &source) +{ + _num = source._num; + _initialized = source._initialized; + return *this; +} diff --git a/NonLinearSolver/materialLaw/mlaw.h b/NonLinearSolver/materialLaw/mlaw.h new file mode 100644 index 0000000000..053eb71e84 --- /dev/null +++ b/NonLinearSolver/materialLaw/mlaw.h @@ -0,0 +1,94 @@ +// +// C++ Interface: terms +// +// Description: Define material law +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef _MLAW_H_ +#define _MLAW_H_ +#ifndef SWIG +#include "ipstate.h" +#include "MElement.h" +#endif +class materialLaw{ + public : + enum matname{linearElasticPlaneStress, linearElasticPlaneStressWithDamage, linearElasticOrthotropicPlaneStress, cohesiveLaw, fracture}; + protected : + int _num; // number of law (must be unique !) + bool _initialized; // to initialize law +#ifndef SWIG + public: + // constructor + materialLaw(const int num, const bool init=true); + ~materialLaw(){} + materialLaw(const materialLaw &source); + materialLaw& operator=(const materialLaw &source); + virtual int getNum() const{return _num;} + virtual matname getType() const=0; + virtual void createIPState(IPStateBase* &ips,const bool* state_=NULL,const MElement *ele=NULL, const int nbFF_=0) const=0; + virtual void initLaws(const std::map<int,materialLaw*> &maplaw)=0; + virtual const bool isInitialized() {return _initialized;} + // for explicit scheme it must return sqrt(E/rho) adapted to your case + virtual double soundSpeed() const=0; +#endif +}; +#ifndef SWIG +class materialLaw2LawsInitializer{ + public: + materialLaw2LawsInitializer(){} + ~materialLaw2LawsInitializer(){} + materialLaw2LawsInitializer(const materialLaw2LawsInitializer &source){} +// virtual materialLaw::matname getType() const{return materialLaw::fracture;} + virtual void initialBroken(IPStateBase *ips) const=0; +}; + +// If you used two laws your class has to be derived from this one +template<class Tbulk, class Tfrac>class fractureBy2Laws : public materialLaw2LawsInitializer{ + protected: + const int _nbulk; + const int _nfrac; + Tbulk *_mbulk; + Tfrac *_mfrac; + public: + fractureBy2Laws(const int num, const int nbulk, const int nfrac) : materialLaw2LawsInitializer(), + _nbulk(nbulk), _nfrac(nfrac), + _mbulk(NULL), _mfrac(NULL){} + fractureBy2Laws(const fractureBy2Laws &source) : materialLaw2LawsInitializer(source), _nbulk(source._nbulk), + _nfrac(source._nfrac), + _mbulk(source._mbulk), _mfrac(source._mfrac){} + ~fractureBy2Laws(){}; + virtual const int bulkLawNumber() const{return _nbulk;} + virtual const int fractureLawNumber() const{return _nfrac;} + virtual const Tbulk* getBulkLaw() const{return _mbulk;} + virtual Tbulk* getBulkLaw(){return _mbulk;} + virtual const Tfrac* getFractureLaw() const{return _mfrac;} + virtual void initLaws(const std::map<int,materialLaw*> &maplaw) + { + bool findb=false; + bool findc=false; + for(std::map<int,materialLaw*>::const_iterator it = maplaw.begin(); it != maplaw.end(); ++it) + { + int num = it->first; + if(num == _nbulk){ + findb=true; + it->second->initLaws(maplaw); + _mbulk = dynamic_cast<Tbulk*>(it->second); + } + if(num == _nfrac){ + findc=true; + it->second->initLaws(maplaw); + _mfrac = dynamic_cast<Tfrac*>(it->second); + } + } + if(!findb) Msg::Error("The bulk law is not initialize for shellFractureByCohesiveLaw number %d",_nbulk); + if(!findc) Msg::Error("The cohesive law is not initialize for shellFractureByCohesiveLaw number %d",_nfrac); + } + virtual void initialBroken(IPStateBase *ips) const=0; +}; +#endif // SWIG +#endif //MLAW_H_ diff --git a/NonLinearSolver/nlTerms/CMakeLists.txt b/NonLinearSolver/nlTerms/CMakeLists.txt new file mode 100644 index 0000000000..a325c8c2dc --- /dev/null +++ b/NonLinearSolver/nlTerms/CMakeLists.txt @@ -0,0 +1,11 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + nlTerms.cpp +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/nlTerms "${SRC};${HDR}") diff --git a/NonLinearSolver/nlTerms/nlTerms.cpp b/NonLinearSolver/nlTerms/nlTerms.cpp new file mode 100644 index 0000000000..4969d3fd9e --- /dev/null +++ b/NonLinearSolver/nlTerms/nlTerms.cpp @@ -0,0 +1,130 @@ +// +// C++ Interface: terms +// +// Description: Basic term for non linear solver +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "nlTerms.h" +#include "MInterfaceElement.h" +#include "unknownField.h" +#include "ipField.h" +template<> void BilinearTermPerturbation<double>::get(MElement *ele,int npts,IntPt *GP,fullMatrix<double> &m) const +{ + MInterfaceElement *iele = dynamic_cast<MInterfaceElement*>(ele); + std::vector<Dof> R; + if(_nlterm->isData()) + _nlterm->set(&disp); + if(iele == NULL){ // compute on element + int nbdof = space1.getNumKeys(ele); + m.resize(nbdof,nbdof,false); // set operation after + disp.resize(nbdof); + space1.getKeys(ele,R); + _ufield->get(R,disp); + + // Size of force vector + fp.resize(nbdof); + fm.resize(nbdof); + + for(int i=0;i<nbdof;i++){ + // pertubation + + disp(i) += _eps; + _dom->computeIpv(_ipf->getAips(),ele,IPStateBase::current,_dom->getMaterialLaw(),disp); + + _nlterm->get(ele,npts,GP,fp); + // perturbation - + disp(i) -=_twoeps; + _dom->computeIpv(_ipf->getAips(),ele,IPStateBase::current,_dom->getMaterialLaw(),disp); + _nlterm->get(ele,npts,GP,fm); + // restore dof value + disp(i) += _eps; + fp.axpy(fm,-1); + m.copyOneColumn(fp,i); // divide by 1/(2eps) at the end + } + _dom->computeIpv(_ipf->getAips(),ele,IPStateBase::current,_dom->getMaterialLaw(),disp); + } + else{ + // get displacement of element + space1.getKeys(iele->getElem(0),R); + if(iele->getElem(0) != iele->getElem(1)) + space2.getKeys(iele->getElem(1),R); + disp.resize(R.size()); + _ufield->get(R,disp); + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(_dom); + bool virt=false; + if(iele->getElem(0) == iele->getElem(1)) virt = true; + // store in dispm and dispp + int nbdof_m = space1.getNumKeys(iele->getElem(0)); + int nbdof_p = 0; + dispm.resize(nbdof_m); + for(int i=0;i<nbdof_m;i++) + dispm(i) = disp(i); + if(!virt){ + nbdof_p = space2.getNumKeys(iele->getElem(1)); + dispp.resize(nbdof_p); + for(int i=0;i<nbdof_p;i++) + dispp(i) = disp(i+nbdof_m); + m.resize(nbdof_m+nbdof_p,nbdof_m+nbdof_p); + } + else + m.resize(nbdof_m,nbdof_m,false); + fp.resize(disp.size()); // use disp size to know the number of dof (here unknow if interafce or virtual interface) + fm.resize(disp.size()); + + // Perturbation on minus element + for(int i=0;i<nbdof_m;i++){ + // dof perturbation + + disp(i)+=_eps; + dispm(i)+=_eps; + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(),dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(),dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); // 0 for - elem and npts for + elem + _nlterm->get(ele,npts,GP,fp); + // dof perturbation - + disp(i)-=_twoeps; + dispm(i)-=_twoeps; + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(),dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(),dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); // 0 for - elem and npts for + elem + _nlterm->get(ele,npts,GP,fm); + disp(i)+=_eps; + dispm(i)+=_eps; + fp.axpy(fm,-1); + m.copyOneColumn(fp,i); // divide by 1/(2eps) at the end + } + // restore ipv value + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(), dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(),dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); // 0 for - elem and npts for + elem + if(!virt){ // Otherwise virtual interface element + // Perturbation on plus element + for(int i=0;i<nbdof_p;i++){ + // dof perturbation + + disp(i+nbdof_m)+=_eps; + dispp(i)+=_eps; + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(),dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(),dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); // 0 for - elem and npts for + elem + _nlterm->get(ele,npts,GP,fp); + // dof perturbation + + disp(i+nbdof_m)-=_twoeps; + dispp(i)-=_twoeps; + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(),dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(), dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); // 0 for - elem and npts for + elem + _nlterm->get(ele,npts,GP,fm); + disp(i+nbdof_m)+=_eps; + dispp(i)+=_eps; + fp.axpy(fm,-1); + m.copyOneColumn(fp,i+nbdof_m); // divide by 1/(2eps) at the end + } + // restore ipv values + dgdom->computeIpv(_ipf->getAips(),iele,GP,IPStateBase::current,dgdom->getMinusDomain(),dgdom->getPlusDomain(), + dgdom->getMaterialLawMinus(),dgdom->getMaterialLawPlus(),dispm,dispp,virt,false); + } + } + // divide all components by 1/2eps + m.scale(_onedivtwoeps); +// m.print("matrix by perturbation"); + +} + diff --git a/NonLinearSolver/nlTerms/nlTerms.h b/NonLinearSolver/nlTerms/nlTerms.h new file mode 100644 index 0000000000..37ff76384b --- /dev/null +++ b/NonLinearSolver/nlTerms/nlTerms.h @@ -0,0 +1,109 @@ +// +// C++ Interface: terms +// +// Description: Basic term for non linear solver +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef NONLINEARTERMS_H_ +#define NONLINEARTERMS_H_ +// lineartermBase and Bilinear term base are not be able +// to take easily into account a perturbation of the unknown field +// It leads to a very poorly efficient computation of matrix by perturbation +// I change the basis class for this reason ALL assemble functions have to be "duplicated" +#include "terms.h" +class unknownField; +class IPField; +class partDomain; +class BiNonLinearTermBase : public BilinearTermBase +{ + public : + virtual ~BiNonLinearTermBase() {} + virtual void get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) = 0; + virtual void set(const fullVector<double> *datafield) = 0 ; + virtual const bool isData() const=0; // if true use this get function otherwise uses classical get +}; + +// Void term to avoid segmentation fault on domain for pure interface domain (Assemble on element) +class BilinearTermVoid : public BilinearTermBase +{ + public: + virtual ~BilinearTermVoid(){} + virtual void get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m){}; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullMatrix<double> > &mv) const{} + virtual BilinearTermBase* clone () const + { + return new BilinearTermVoid(); + } +}; + +template<class T2=double> class nonLinearTermBase : public LinearTermBase<T2> +{ + protected: + bool inverseSign; // has to be disappeared when solver is written with fext and fint + public: + nonLinearTermBase() : inverseSign(false){} + virtual ~nonLinearTermBase(){} +// virtual void get(MElement *ele, int npts, IntPt *GP, fullVector<T2> &v); + virtual void set(const fullVector<double> *datafield) = 0; + virtual const bool isData() const=0; // if true use this get function otherwise uses classical get + void invSign(){inverseSign ? inverseSign = false : inverseSign = true;} // has to dissappear +}; + +// Void term to avoid segmentation fault on domain for pure interface domain (Assemble on element) +class LinearTermVoid : public LinearTermBase<double> +{ +public: + virtual ~LinearTermVoid(){} + virtual void get(MElement *ele, int npts, IntPt *GP, fullVector<double> &v) const{}; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullVector<double> > &vv) const{} + virtual LinearTermBase<double>* clone () const + { + return new LinearTermVoid(); + } +}; + +// BiNonLinear term by perturbation via nonLinearterm +template <class T2=double> class BilinearTermPerturbation : public BilinearTermBase{ + protected: + nonLinearTermBase<T2> *_nlterm; + FunctionSpaceBase &space1; + FunctionSpaceBase &space2; + unknownField *_ufield; + partDomain *_dom; + IPField *_ipf; + const double _eps; + const double _twoeps; + const double _onedivtwoeps; + private: + mutable fullVector<double> dispm; + mutable fullVector<double> dispp; + mutable fullVector<double> disp; + mutable fullVector<double> fm; + mutable fullVector<double> fp; + public: + BilinearTermPerturbation(LinearTermBase<T2> *lterm, FunctionSpaceBase &sp1, FunctionSpaceBase &sp2, + unknownField *ufield, IPField *ipf, partDomain *dom, + const double pert=1e-8) : space1(sp1), space2(sp2), _nlterm(dynamic_cast<nonLinearTermBase<T2>*>(lterm)), + _ufield(ufield), _dom(dom), + _ipf(ipf), _eps(pert), _twoeps(pert+pert), + _onedivtwoeps(1./(pert+pert)){} + ~BilinearTermPerturbation(){} + virtual void get(MElement *ele,int npts,IntPt *GP,fullMatrix<T2> &m) const; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<fullMatrix<double> > &mv) const + { + Msg::Error("Define me ?? get without integration BilinearTermPerturbation"); + } + virtual BilinearTermBase* clone () const + { + return new BilinearTermPerturbation<T2>(_nlterm,space1,space2,_ufield,_ipf,_dom,_eps); + } +}; + +#endif // NONLINEARTERMS_H_ + diff --git a/NonLinearSolver/nlsolver/CMakeLists.txt b/NonLinearSolver/nlsolver/CMakeLists.txt new file mode 100644 index 0000000000..ef986dbe12 --- /dev/null +++ b/NonLinearSolver/nlsolver/CMakeLists.txt @@ -0,0 +1,21 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + nonLinearMechSolver.cpp + unknownDynamicField.cpp + unknownField.cpp + unknownStaticField.cpp + # inline + Dof3IntType.h + explicitDofManager.h + explicitHulbertChung.h + nlsolAlgorithms.h + staticDofManager.h + timeFunction.h +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/nlsolver "${SRC};${HDR}") diff --git a/NonLinearSolver/nlsolver/Dof3IntType.h b/NonLinearSolver/nlsolver/Dof3IntType.h new file mode 100644 index 0000000000..0c7aba525e --- /dev/null +++ b/NonLinearSolver/nlsolver/Dof3IntType.h @@ -0,0 +1,32 @@ +// +// Description: Derivate class of Dof used for FullDg formulation where the type includes 3 informations (field,local vertex number, dof) +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef DGC0DOF_H_ +#define DGC0DOF_H_ +#include "dofManager.h" +// Two functions are added to dof to define type with three int +// Use by high level so impossible to let this in the projects ? +class Dof3IntType : public Dof{ + public : + Dof3IntType(long int ent, int type) : Dof(ent,type){} + ~Dof3IntType(){} + inline static int createTypeWithThreeInts(int comp,int field, int num=0){return 100000*field+100*num+comp;} + inline static void getThreeIntsFromType(int t, int &comp, int &field, int &num){ + field = t/100000; + int i1=t%100000; + num = i1/100; + comp= i1%100; + } + // This function is used for Cg/Dg case (Allow to call the same function for the Two formulations) + inline static void getThreeIntsFromType(int t, int &comp, int &field){ + field = t/100000; + comp =t%100000; + } +}; +#endif // Dof3IntType diff --git a/NonLinearSolver/nlsolver/explicitDofManager.h b/NonLinearSolver/nlsolver/explicitDofManager.h new file mode 100644 index 0000000000..047cbb6e4f --- /dev/null +++ b/NonLinearSolver/nlsolver/explicitDofManager.h @@ -0,0 +1,304 @@ +// +// C++ Interface: dof manager for dynamic problems +// +// Description: derive the dofManager for a dynamic problem (access to velocities and acceleration) +// and contains a mass matrix +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef EXPLICITDOFMANAGER_H_ +#define EXPLICITDOFMANAGER_H_ + +#include "staticDofManager.h" +#include "explicitHulbertChung.h" +template<class T> +class explicitHCDofManager : public staticDofManager<T>{ + protected: + // map to have the initial conditions BC for positions, velocities and acceleration + //std::map<Dof, std::vector<dataVec> > initial; position in dofManager.h not used ?? + std::map<Dof, typename dofManager<T>::dataVec> _initpositions; + std::map<Dof, typename dofManager<T>::dataVec> _initvelocities; + std::map<Dof, typename dofManager<T>::dataVec> _initaccelerations; + + // for prescribed velocities and accelerations + std::map<Dof, typename dofManager<T>::dataVec> _fixedpositions; // needed to compute velocities (position of last time step) + std::map<Dof, typename dofManager<T>::dataVec> _fixedvelocities; + std::map<Dof, typename dofManager<T>::dataVec> _fixedaccelerations; + std::map<Dof, typename dofManager<T>::dataVec> _fixedmass; // needed to compute kinetic energy + + // pointer to an explicit system (allow to avoid multi dynamic_cast) + explicitHulbertChung<T> *_currentExpl; + + public: + explicitHCDofManager(linearSystem< typename dofManager<T>::dataMat> *l) : staticDofManager<T>(l){ + _currentExpl = dynamic_cast<explicitHulbertChung<T>*>(l); + } + explicitHCDofManager(linearSystem< typename dofManager<T>::dataMat > *l1, linearSystem< typename dofManager<T>::dataMat > *l2){ + _currentExpl = dynamic_cast<explicitHulbertChung<T> >(l1); + } + + // Function assemble matrix is rewritten to allow to have 2 matrix stiffness and mass + virtual inline void assemble(std::vector<Dof> &R, const fullMatrix<typename dofManager<T>::dataMat> &m, + const typename explicitHulbertChung<T>::whichMatrix wm=explicitHulbertChung<T>::stiff){ + if (!this->_current->isAllocated()) this->_current->allocate(this->unknown.size()); + std::vector<int> NR(R.size()); + for (unsigned int i = 0; i < R.size(); i++) + { + std::map<Dof, int>::iterator itR = this->unknown.find(R[i]); + if (itR != this->unknown.end()) NR[i] = itR->second; + else NR[i] = -1; + } + if(wm == explicitHulbertChung<T>::stiff) + { + for (unsigned int i = 0; i < R.size(); i++) + { + if (NR[i] != -1) + { + for (unsigned int j = 0; j < R.size(); j++) + { + if (NR[j] != -1) + { + this->_current->addToMatrix(NR[i], NR[j], m(i, j)); + } + else + { + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator itFixed = this->fixed.find(R[j]); + if (itFixed == this->fixed.end()) + assembleLinConst(R[i],R[j],m(i,j)); + } + } + } + else + { + for (unsigned int j = 0; j < R.size(); j++){ + assembleLinConst(R[i],R[j],m(i,j)); + } + } + } + } + else{ // mass matrix + for (unsigned int i = 0; i < R.size(); i++) + if (NR[i] != -1) + for (unsigned int j = 0; j < R.size(); j++) + //if (NR[j] != -1) + this->_currentExpl->addToMatrix(NR[i], NR[j], m(i, j),explicitHulbertChung<T>::mass); + else{ // store mass in _fixedmass + double linemass=0.; + // if already exist in _fixed mass retrieve value to add sum because diagonal matrix + typename std::map<Dof,typename dofManager<T>::dataVec>::iterator itm = this->_fixedmass.find(R[i]); + if(itm != this->_fixedmass.end()) + linemass+=itm->second; + for(unsigned int j=0; j<R.size(); j++) + linemass+=m(i,j); + this->_fixedmass[R[i]] = linemass; + } + } + } + + // Function to fix dof (fix velocities and acceleration Too. Must be modified to prescribed a velocities or an acceleration) + inline void fixDof(Dof key, const typename dofManager<T>::dataVec &value){ + if(this->unknown.find(key) != this->unknown.end()) + return; + this->fixed[key] = value; + this->_fixedvelocities[key]=0.; + this->_fixedaccelerations[key]=0.; + this->RHSfixed[key]=0.; + } + + // function with get operation (WARNING All getDofValue are not redifined) + virtual inline void getDofValue(std::vector<Dof> &keys,std::vector<typename dofManager<T>::dataVec> &Vals, + const typename initialCondition::whichCondition wv= initialCondition::position) + { + int ndofs=keys.size(); + size_t originalSize = Vals.size(); + Vals.resize(originalSize+ndofs); + for (int i=0;i<ndofs;++i) getDofValue(keys[i], Vals[originalSize+i],wv); + } + + virtual inline void getDofValue(Dof key, typename dofManager<T>::dataVec &val, + initialCondition::whichCondition wv= initialCondition::position) const + { + switch(wv){ + case initialCondition::position: + { + typename std::map<Dof, typename dofManager<T>::dataVec>::const_iterator it = this->fixed.find(key); + if (it != this->fixed.end()) { + val = it->second; + return ; + } + } + { + std::map<Dof, int>::const_iterator it = this->unknown.find(key); + if (it != this->unknown.end()) { + _currentExpl->getFromSolution(it->second, val,wv); + return; + } + } + { + typename std::map<Dof, DofAffineConstraint< typename dofManager<T>::dataVec > >::const_iterator it = this->constraints.find(key); + if (it != this->constraints.end()) + { + typename dofManager<T>::dataVec tmp(val); + val = it->second.shift; + for (unsigned i=0;i<(it->second).linear.size();i++) + { + std::map<Dof, int>::const_iterator itu = this->unknown.find(((it->second).linear[i]).first); + getDofValue(((it->second).linear[i]).first, tmp); + dofTraits<T>::gemm(val,((it->second).linear[i]).second, tmp, 1, 1); + } + return ; + } + } + break; + case initialCondition::velocity: + { + typename std::map<Dof, typename dofManager<T>::dataVec>::const_iterator it = this->_fixedvelocities.find(key); + if (it != this->_fixedvelocities.end()) { + val = it->second; + return ; + } + } + { + std::map<Dof, int>::const_iterator it = this->unknown.find(key); + if (it != this->unknown.end()) { + _currentExpl->getFromSolution(it->second, val,wv); + return; + } + } + break; + case initialCondition::acceleration: + { + typename std::map<Dof, typename dofManager<T>::dataVec>::const_iterator it = this->_fixedaccelerations.find(key); + if (it != this->_fixedaccelerations.end()) { + val = it->second; + return ; + } + } + { + std::map<Dof, int>::const_iterator it = this->unknown.find(key); + if (it != this->unknown.end()) { + _currentExpl->getFromSolution(it->second, val,wv); + return; + } + } + break; + } + } + + // specific functions tfor initial conditions + // I don't use the initial vector because initial conditions are given directly + // to the solver + virtual inline void setInitialCondition(const Dof &R, const typename dofManager<T>::dataVec &value, + const typename initialCondition::whichCondition wc){ + + if (!this->_current->isAllocated()) this->_current->allocate(this->unknown.size()); + // find the dof in map if not find -1 + int NR=-1; + std::map<Dof, int>::iterator itR = this->unknown.find(R); + if (itR != this->unknown.end()){ + NR = itR->second; + _currentExpl->setInitialCondition(NR, value,wc); + } + else{ // insert the initial conditions + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator it; + if(wc == initialCondition::position){ + this->_initpositions[R] = value; + // Find if the two others exist. If not set to zero + it = this->_initvelocities.find(R); + if (it == this->_initvelocities.end()) _initvelocities[R] = 0.; + it = this->_initaccelerations.find(R); + if (it == this->_initaccelerations.end()) _initaccelerations[R] = 0.; + // set initial position in fixedpos or 0 + _fixedpositions[R] = value; + } + else if(wc == initialCondition::velocity){ + _initvelocities[R] = value; + // Find if the two others exist. If not set to zero + it = this->_initpositions.find(R); + if (it == this->_initpositions.end()) this->_initpositions[R] = 0.; + it = this->_initaccelerations.find(R); + if (it == this->_initaccelerations.end()) _initaccelerations[R] = 0.; + _fixedpositions[R] = 0.; + } + else if(wc == initialCondition::acceleration){ + _initaccelerations[R] = value; + // Find if the two others exist. If not set to zero + it = this->_initpositions.find(R); + if (it == this->_initpositions.end()) this->_initpositions[R] = 0.; + it = this->_initvelocities.find(R); + if (it == this->_initvelocities.end()) _initvelocities[R] = 0.; + _fixedpositions[R] = 0.; + } + } + } + + // Function to update the fixed dof value + // must be rewritten to take into account a fixed velocity + virtual void updateFixedDof(const double timeStep){ + // loop + for(typename std::map<Dof, typename dofManager<T>::dataVec>::iterator it=this->fixed.begin(); it!=this->fixed.end(); ++it){ + // watch for an initial position + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator itpos = _initpositions.find(it->first); + double initpos=0.; + typename dofManager<T>::dataVec lastpos=_fixedpositions[it->first]; + typename dofManager<T>::dataVec lastvelo = _fixedvelocities[it->first]; + if(itpos != _initpositions.end() ) initpos = itpos->second; + it->second = it->second + initpos; + _fixedpositions[it->first] = it->second; + _fixedvelocities.find(it->first)->second = (it->second - lastpos)/timeStep; + // update acceleration with plexus manual theory + //_fixedaccelerations.find(it->first)->second = (it->second/timeStep - _fixedvelocities.find(it->first)->second)/timeStep; + _fixedaccelerations.find(it->first)->second = 0.; //(_fixedvelocities.find(it->first)->second -lastvelo)/timeStep; + } + } + virtual void getVertexMass(std::vector<Dof> &R, std::vector<typename dofManager<T>::dataVec> &vmass){ + if(this->_current->isAllocated()){ + std::map<Dof, int>::const_iterator it; + double mass; + for(int i=0;i<R.size(); i++){ + it = this->unknown.find(R[i]); + if(it != this->unknown.end()){ + _currentExpl->getFromMatrix(it->second,it->second,mass); + vmass.push_back(mass); + } + else{ // find mass in _fixedmass + typename std::map<Dof,typename dofManager<T>::dataVec>::iterator itm = this->_fixedmass.find(R[i]); + if(itm != _fixedmass.end()) vmass.push_back(itm->second); + else vmass.push_back(0.); + } + } + } + else{ + for(int i=0;i<R.size(); i++) vmass.push_back(0.); + } + } + + // Function to get global kinetic energy. Used vector PETSC function so it's more quick + double getKineticEnergy() const{ + double ener = _currentExpl->getKineticEnergy(); // energy of free dofs + // add energy of fixed dof + for(typename std::map<Dof,typename dofManager<T>::dataVec>::const_iterator it = _fixedmass.begin(); it!=_fixedmass.end(); ++it){ + double mv = it->second; + double v = 0.; + typename std::map<Dof,typename dofManager<T>::dataVec>::const_iterator itv = _fixedvelocities.find(it->first); + if(itv != _fixedvelocities.end()) v = itv->second; + ener += 0.5*mv*v*v; + } + return ener; + } + + // Print Right Hand Side (Use for debug) + void printRightHandSide() const{ + Msg::Info("Right Hand Side"); + for(std::map<Dof,int>::const_iterator it=this->unknown.begin(); it!=this->unknown.end(); ++it){ + double force; + _currentExpl->getFromRightHandSide(it->second,force); + Msg::Info("Dof Ent: %d Dof Type %d value %e",it->first.getEntity(),it->first.getType(),force); + } + } +}; +#endif // EXPLICITDOFMANAGER_H_ + diff --git a/NonLinearSolver/nlsolver/explicitHulbertChung.h b/NonLinearSolver/nlsolver/explicitHulbertChung.h new file mode 100644 index 0000000000..6028640131 --- /dev/null +++ b/NonLinearSolver/nlsolver/explicitHulbertChung.h @@ -0,0 +1,399 @@ +// +// C++ explicit Newmark scheme +// +// Description: implementation of the explicit algorithms of alpha-generalized method +// This system is derived from linearSystem from compatibility reason (use of Assemble function and DofManager +// even if the system is not a no linear system FIX THIS ?? +// for now works only this PETsc +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef EXPLICITHULBERTCHUNGSYSTEM_H_ +#define EXPLICITHULBERTCHUNGSYSTEM_H_ + +#include "GmshConfig.h" +#include "GmshMessage.h" +#include "linearSystem.h" +#include "partDomain.h" + +#if defined(HAVE_PETSC) +#include <petsc.h> +#include <petscksp.h> + +// 4 vectors are necessary per step and two step are kept +// current and next. Creation of a class regrouping the four vector +template<class scalar> +class explicitStep{ + private: + void _try(int ierr) const { CHKERRABORT(PETSC_COMM_WORLD, ierr); } + public : // Direct access by the system + Vec _b, _x, _xdot, _xddot; + explicitStep(){} + ~explicitStep(){} + void clear(){ + _try(VecDestroy(_b)); + _try(VecDestroy(_x)); + _try(VecDestroy(_xdot)); + _try(VecDestroy(_xddot)); + } + + void allocate(int nbRows){ + _try(VecCreate(PETSC_COMM_WORLD, &_x)); + _try(VecSetSizes(_x, nbRows, PETSC_DETERMINE)); + _try(VecSetFromOptions(_x)); // Usefull ?? + _try(VecDuplicate(_x, &_b)); + _try(VecDuplicate(_x, &_xdot)); + _try(VecDuplicate(_x, &_xddot)); + } +}; + +template<class scalar> +class explicitHulbertChung : public linearSystem<scalar>{ + public : + enum state{current, next}; +// enum whatValue{position, velocity, acceleration}; + enum whichMatrix{stiff, mass}; + protected: + int _blockSize; // for block Matrix (not used for now) + bool _isAllocated, _whichStep, _imassAllocated; + double _alpham, _beta,_gamma; // parameters of scheme + double _timeStep; // value of time step + int _nbRows; // To know the system size. + // values used by solve function + double _oneDivbyOneMinusAlpham,_minusAlphamDivbyOneMinusAlpham; + double _oneMinusgammaDeltat,_gammaDeltat,_Deltat2halfMinusbeta,_Deltat2beta; + explicitStep<scalar> *_currentStep, *_previousStep, *_step1, *_step2; + Vec _M; // mass matrix + Vec _invM; // inverse of mass matrix + Vec _v2; // square of velocitie (kinetic energy) + + // function to invert mass matrix + void invertMassMatrix(){ + _try(VecCopy(_M,_invM)); + _try(VecReciprocal(_invM)); + _imassAllocated=true; + } + + private: + void _try(int ierr) const { CHKERRABORT(PETSC_COMM_WORLD, ierr); } + + public: + explicitHulbertChung(double alpham=0., double beta=0., + double gamma=0.5) : _isAllocated(false), _whichStep(true), _blockSize(0), + _alpham(alpham), _beta(beta), _gamma(gamma), + _timeStep(0.), _nbRows(0), _imassAllocated(false){ + _oneDivbyOneMinusAlpham = 1./(1.-_alpham); + _minusAlphamDivbyOneMinusAlpham = - _alpham * _oneDivbyOneMinusAlpham; + _oneMinusgammaDeltat = (1.-_gamma)*_timeStep; + _gammaDeltat = _gamma*_timeStep; + _Deltat2halfMinusbeta = _timeStep*_timeStep *(0.5-_beta); + _Deltat2beta = _timeStep * _timeStep * _beta; + _step1 = new explicitStep<scalar>(); + _step2 = new explicitStep<scalar>(); + _currentStep = _step1; + _previousStep = _step2; + } + ~explicitHulbertChung(){delete _step1; delete _step2;} + + void nextStep(){ + if(_whichStep){ + _currentStep = _step2; + _previousStep = _step1; + _whichStep =false; + } + else{ + _currentStep = _step1; + _previousStep = _step2; + _whichStep = true; + } + } + + virtual void clear(){ + if(_isAllocated){ + _try(VecDestroy(_M)); + _try(VecDestroy(_invM)); + _try(VecDestroy(_v2)); + _step1->clear(); + _step2->clear(); + _nbRows=0; + } + _isAllocated=false; + _imassAllocated=false; + } + // Or compute directly the time step here ?? + virtual void setTimeStep(const double dt){ + _timeStep = dt; + // update variables which depends on _timeStep + _oneMinusgammaDeltat = (1.-_gamma)*_timeStep; + _gammaDeltat = _gamma*_timeStep; + _Deltat2halfMinusbeta = _timeStep*_timeStep *(0.5-_beta); + _Deltat2beta = _timeStep * _timeStep * _beta; + + } + virtual bool isAllocated() const { return _isAllocated; } + virtual void allocate(int nbRows){ + clear(); + _try(VecCreate(PETSC_COMM_WORLD, &_M)); + _try(VecSetSizes(_M, nbRows, PETSC_DETERMINE)); + _try(VecSetFromOptions(_M)); // Usefull ?? + _try(VecDuplicate(_M, &_invM)); + _try(VecDuplicate(_M, &_v2)); + _step1->allocate(nbRows); + _step2->allocate(nbRows); + _isAllocated = true; + _nbRows=nbRows; + } + // get the value of diagonalized mass matrix col is not used + virtual void getFromMatrix(int row, int col, scalar &val) const{ +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_M, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_M, &tmp)); + // FIXME specialize this routine + val = s.real(); +#else + VecGetValues(_M, 1, &row, &val); +#endif + } + virtual void addToRightHandSide(int row, const scalar &val) + { + PetscInt i = row; + PetscScalar s = val; + _try(VecSetValues(_currentStep->_b, 1, &i, &s, ADD_VALUES)); + } + + virtual void getFromRightHandSide(int row, scalar &val) const + { +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_currentStep->_b, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_currentStep->_b, &tmp)); + // FIXME specialize this routine + val = s.real(); +#else + VecGetValues(_currentStep->_b, 1, &row, &val); +#endif + } + + virtual double normInfRightHandSide() const + { + PetscReal nor; + _try(VecNorm(_currentStep->_b, NORM_INFINITY, &nor)); + return nor; + } + + // Add to mass matrix (which is diagonalized) + virtual void addToMatrix(int row, int col, const scalar &val){ + Msg::Error("No stiffness matrix for an explicit newmark scheme"); + } + virtual void addToMatrix(int row, int col, const scalar &val, const whichMatrix wm) + { + if(wm == stiff){ + this->addToMatrix(row,col,val); + } + else if( wm == mass){ + PetscInt i = row; + PetscScalar s = val; + _try(VecSetValues(_M, 1, &i, &s, ADD_VALUES)); + } + else{ + Msg::Error("stiff and mass are the only possible matrix choice"); + } + + } + + virtual void getFromSolution(int row, scalar &val) const + { +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_currentStep->_x, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_currentStep->_x, &tmp)); + val = s.real(); +#else + VecGetValues(_currentStep->_x, 1, &row, &val); +#endif + } + + virtual void getFromSolution(int row, scalar &val, const initialCondition::whichCondition wv) const + { + switch(wv){ + case initialCondition::position: + this->getFromSolution(row,val); + break; + case initialCondition::velocity: +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_currentStep->_xdot, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_currentStep->_xdot, &tmp)); + val = s.real(); +#else + VecGetValues(_currentStep->_xdot, 1, &row, &val); +#endif + break; + case initialCondition::acceleration: +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_currentStep->_xddot, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_currentStep->_xddot, &tmp)); + val = s.real(); +#else + VecGetValues(_currentStep->_xddot, 1, &row, &val); +#endif + break; + default: + Msg::Error("Impossible to get value from solution. Only possible choices position, velocity, acceleration "); + } + + } + +/* virtual void getFromSolution(int row, scalar &val) const + { +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_currentStep->_x, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_currentStep->_x, &tmp)); + val = s.real(); +#else + VecGetValues(_currentStep->_x, 1, &row, &val); +#endif + }*/ + + + virtual void zeroMatrix(){ + if (_isAllocated) { + _try(VecAssemblyBegin(_M)); + _try(VecAssemblyEnd(_M)); + _try(VecZeroEntries(_M)); + } + } + + virtual void zeroRightHandSide() + { + if (_isAllocated) { + _try(VecAssemblyBegin(_currentStep->_b)); + _try(VecAssemblyEnd(_currentStep->_b)); + _try(VecZeroEntries(_currentStep->_b)); + } + } + + int systemSolve(){ +#if defined(PETSC_USE_COMPLEX) + Msg::Error("explicit Newmark resolution is not implemented for complex number\n"); +#else + // check if the mass matrix is computed or not + if(!_imassAllocated) this->invertMassMatrix(); + +// The following comment are kept to explain what is done component by component +// double x,xdot,xddot,fextMinusfint, imasse, xddotn, xdotn, xn; +// for(PetscInt i=0;i<_nbRows;i++){ + + // accelerations n+1 +// VecGetValues(_previousStep->_b, 1, &i, &fextMinusfint); +// VecGetValues(_invM, 1, &i, &imasse); +// VecGetValues(_previousStep->_xddot, 1 , &i, &xddotn); +// xddot = _oneDivbyOneMinusAlpham*imasse*fextMinusfint + _minusAlphamDivbyOneMinusAlpham * xddotn; +// _try(VecSetValues(_currentStep->_xddot, 1, &i, &xddot, INSERT_VALUES)); + _try(VecPointwiseMult(_currentStep->_xddot,_invM,_previousStep->_b)); + _try(VecScale(_currentStep->_xddot,_oneDivbyOneMinusAlpham)); + _try(VecAXPY(_currentStep->_xddot,_minusAlphamDivbyOneMinusAlpham,_previousStep->_xddot)); + + // velocities n+1 +// VecGetValues(_previousStep->_xdot, 1 , &i, &xdotn); +// xdot = xdotn + _oneMinusgammaDeltat*xddotn + _gammaDeltat*xddot; +// _try(VecSetValues(_currentStep->_xdot, 1 , &i, &xdot, INSERT_VALUES)); + _try(VecCopy(_previousStep->_xdot,_currentStep->_xdot)); + // Regroups the two in one operation with VecMAXPY ?? + _try(VecAXPY(_currentStep->_xdot,_oneMinusgammaDeltat,_previousStep->_xddot)); + _try(VecAXPY(_currentStep->_xdot,_gammaDeltat,_currentStep->_xddot)); + + // positions n+1 +// VecGetValues(_previousStep->_x, 1 , &i, &xn); +// x = xn + _timeStep * xdotn + _Deltat2halfMinusbeta * xddotn + _Deltat2beta * xddot; +// _try(VecSetValues(_currentStep->_x, 1 , &i, &x, INSERT_VALUES)); + _try(VecCopy(_previousStep->_x,_currentStep->_x)); + // Regroups the three in one operation with VecMAXPY ?? + _try(VecAXPY(_currentStep->_x,_timeStep,_previousStep->_xdot)); + _try(VecAXPY(_currentStep->_x,_Deltat2halfMinusbeta,_previousStep->_xddot)); + _try(VecAXPY(_currentStep->_x,_Deltat2beta,_currentStep->_xddot)); + // } +#endif + return 1; + } + + // Specific functions (To put initial conditions) + // set on current step a next step operation is necessary after the prescribtion of initial value step0->step1 + void setInitialCondition(int row, scalar val, const typename initialCondition::whichCondition wc=initialCondition::position){ //CANNOT PASS VAL BY REF WHY ?? + PetscInt i = row; + switch(wc){ + case initialCondition::position: + _try(VecSetValues(_currentStep->_x, 1, &i, &val, INSERT_VALUES)); + break; + case initialCondition::velocity: + _try(VecSetValues(_currentStep->_xdot, 1, &i, &val, INSERT_VALUES)); + break; + case initialCondition::acceleration: + _try(VecSetValues(_currentStep->_xddot, 1 , &i, &val, INSERT_VALUES)); + break; + default: + Msg::Warning("Invalid initial conditions"); + } + } + + // Get mass of system + virtual double getSystemMass(){ + double m,mele; + m=0.; + for(PetscInt i=0;i<_nbRows;i++){ + VecGetValues(_M, 1, &i, &mele); + m+=mele; + } + return m; + } + // function to get the kinetic energy + double getKineticEnergy(){ + if(isAllocated()){ + PetscScalar ener; + _try(VecPointwiseMult(_v2,_currentStep->_xdot,_currentStep->_xdot)); + _try(VecDot(_M,_v2,&ener)); + return 0.5*ener; + } + else return 0.; + } +}; + +#else +template <class scalar> +class explicitHulbertChung : public linearSystem<scalar> { + public : + explicitHulbertChung() + { + Msg::Error("PETSc is not available in this version of Gmsh and so it is impossible to use explicit alpha generalized scheme"); + } + virtual bool isAllocated() const { return false; } + virtual void allocate(int nbRows) {} + virtual void clear(){} + virtual void addToMatrix(int row, int col, const scalar &val) {} + virtual void getFromMatrix(int row, int col, scalar &val) const {} + virtual void addToRightHandSide(int row, const scalar &val) {} + virtual void getFromRightHandSide(int row, scalar &val) const { return 0.; } + virtual void getFromSolution(int row, scalar &val) const { return 0.; } + virtual void zeroMatrix() {} + virtual void zeroRightHandSide() {} + virtual int systemSolve() { return 0; } + virtual double normInfRightHandSide() const{return 0;} +}; + +#endif + +#endif // EXPLICITHULBERTCHUNGSYSTEM_H_ + diff --git a/NonLinearSolver/nlsolver/nlsolAlgorithms.h b/NonLinearSolver/nlsolver/nlsolAlgorithms.h new file mode 100644 index 0000000000..6f922cf652 --- /dev/null +++ b/NonLinearSolver/nlsolver/nlsolAlgorithms.h @@ -0,0 +1,228 @@ +// +// C++ Interface: terms +// +// Description: non linear assembly fonctions +// +// +// Author: <Gauthier BECKER>, (C) 2011 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef NONLINEARSOLVERALGORITHMS_H_ +#define NONLINEARSOLVERALGORITHMS_H_ +#include "dofManager.h" +#include "quadratureRules.h" +#include "MVertex.h" +#include "MInterfaceElement.h" +#include "functionSpace.h" +#include "explicitHulbertChung.h" +#include "solverAlgorithms.h" +#include "explicitDofManager.h" + +// Assemble linear term. The field of term can be pass (compute matrix by perturbation and avoid a additional getKeys) +// FIX THIS (use classical assemble) when field will be defined properly + +template<class Iterator, class Assembler> void Assemble(LinearTermBase<double> *term, FunctionSpaceBase &space, + Iterator itbegin, Iterator itend, + QuadratureBase &integrator, + const unknownField *ufield,Assembler &assembler) +{ + fullVector<typename Assembler::dataMat> localVector(0); + std::vector<Dof> R; + nonLinearTermBase<double> *nlterm = dynamic_cast<nonLinearTermBase<double>*>(term); + if( (nlterm !=NULL) and (nlterm->isData())){ + fullVector<double> disp; + nlterm->set(&disp); + for (Iterator it = itbegin; it != itend; ++it){ + MElement *e = *it; + R.clear(); + IntPt *GP; + int npts = integrator.getIntPoints(e, &GP); + space.getKeys(e, R); + disp.resize(R.size()); + ufield->get(R,disp); + term->get(e, npts, GP, localVector); //localVector.print(); + assembler.assemble(R, localVector); + } + } + else{ + for (Iterator it = itbegin; it != itend; ++it){ + MElement *e = *it; + R.clear(); + IntPt *GP; + int npts = integrator.getIntPoints(e, &GP); + space.getKeys(e, R); + term->get(e, npts, GP, localVector); //localVector.print(); + assembler.assemble(R, localVector); + } + + } +} + +// Function Assemble for mass matrix. An other function is needed because Two matrix in the system +template<class Iterator,class Assembler> void AssembleMass(BilinearTermBase *term,FunctionSpaceBase &space,Iterator itbegin, + Iterator itend,QuadratureBase &integrator,Assembler &assembler) // symmetric +{ + fullMatrix<typename Assembler::dataMat> localMatrix; + // remove the Dynamic Cast + explicitHCDofManager<typename Assembler::dataVec>* expAss = dynamic_cast<explicitHCDofManager<typename Assembler::dataVec>*>(&assembler); + std::vector<Dof> R; + for (Iterator it = itbegin;it!=itend; ++it) + { + MElement *e = *it; + R.clear(); + IntPt *GP; + int npts=integrator.getIntPoints(e,&GP); + term->get(e,npts,GP,localMatrix); + space.getKeys(e,R); + expAss->assemble(R, localMatrix,explicitHulbertChung<double>::mass); + } +} + +// Assemble mass for a rigid contact space. Only ddl of GC +template<class Assembler> +void AssembleMass(BilinearTermBase *term, rigidContactSpace *space,Assembler *assembler){ + fullMatrix<typename Assembler::dataMat> localMatrix; + explicitHCDofManager<typename Assembler::dataVec>* expAss = dynamic_cast<explicitHCDofManager<typename Assembler::dataVec>*>(assembler); + std::vector<Dof> R; + space->getKeysOfGravityCenter(R); + MElement *ele; + IntPt *GP; + term->get(ele,0,GP,localMatrix); + expAss->assemble(R, localMatrix,explicitHulbertChung<double>::mass); +} + +template<class Assembler> void FixNodalDofs(FunctionSpaceBase *space,MElement *e,Assembler &assembler,simpleFunction<typename Assembler::dataVec> &fct,FilterDof &filter,bool fullDg) +{ + std::vector<MVertex*> tabV; + int nv=e->getNumVertices(); + std::vector<Dof> R; + space->getKeys(e,R); + tabV.reserve(nv); + for (int i=0;i<nv;++i) tabV.push_back(e->getVertex(i)); + + if(!fullDg){ + for (std::vector<Dof>::iterator itd=R.begin();itd!=R.end();++itd) + { + Dof key=*itd; + if (filter(key)) + { + for (int i=0;i<nv;++i) + { + if (tabV[i]->getNum()==key.getEntity()) + { + //printf("Fix dof number %d comp %d\n",key.getEntity(),key.getType()); + assembler.fixDof(key, fct(tabV[i]->x(),tabV[i]->y(),tabV[i]->z())); + break; + } + } + } + } + } + else{ + for (std::vector<Dof>::iterator itd=R.begin();itd!=R.end();++itd) + { + Dof key=*itd; + if (filter(key)) + { + for (int i=0;i<nv;++i) + { + assembler.fixDof(key, fct(tabV[i]->x(),tabV[i]->y(),tabV[i]->z())); + break; + } + } + } + } +} + +template<class Iterator,class Assembler> void FixNodalDofs(FunctionSpaceBase *space,Iterator itbegin,Iterator itend,Assembler &assembler, + simpleFunction<typename Assembler::dataVec> &fct,FilterDof &filter,bool fullDg) +{ + for (Iterator it=itbegin;it!=itend;++it) + { + FixNodalDofs(space,*it,assembler,fct,filter,fullDg); + } +} + +template<class Assembler> +void FixNodalDofs(rigidContactSpace *space,simpleFunction<typename Assembler::dataVec> &fct,FilterDof &filter, Assembler &assembler){ + std::vector<Dof> R; + space->getKeysOfGravityCenter(R); + for(int i=0;i<R.size();i++){ + if(filter(R[i])) + assembler.fixDof(R[i], fct(0.,0.,0.)); + } + +} +template<class Assembler> void SetInitialDofs(FunctionSpaceBase *space,MElement *e,Assembler &assembler, + const double &value,const initialCondition::whichCondition whichC, + FilterDof &filter,bool fullDg) +{ + std::vector<MVertex*> tabV; + int nv=e->getNumVertices(); + std::vector<Dof> R; +// FunctionSpace<double> *dgspace = dynamic_cast<FunctionSpace<double>*>(space); + space->getKeys(e,R); + tabV.reserve(nv); + explicitHCDofManager<double> *dynass= dynamic_cast<explicitHCDofManager<double>*>(&assembler); // remove this dynamic_cast + for (int i=0;i<nv;++i) tabV.push_back(e->getVertex(i)); + + if(!fullDg){ + for (std::vector<Dof>::iterator itd=R.begin();itd!=R.end();++itd) + { + Dof key=*itd; + if (filter(key)) + { + for (int i=0;i<nv;++i) + { + if (tabV[i]->getNum()==key.getEntity()) + { + //printf("Fix dof number %d comp %d\n",key.getEntity(),key.getType()); + dynass->setInitialCondition(key,value,whichC); + break; + } + } + } + } + } + else{ + for (std::vector<Dof>::iterator itd=R.begin();itd!=R.end();++itd) + { + Dof key=*itd; + if (filter(key)) + { + for (int i=0;i<nv;++i) + { + dynass->setInitialCondition(key, value,whichC); + break; + } + } + } + } +} + +template<class Iterator,class Assembler> void SetInitialDofs(FunctionSpaceBase *space,Iterator itbegin,Iterator itend, + const double &value,const initialCondition::whichCondition whichC, + Assembler &assembler, FilterDof &filter,bool fullDg) +{ + for (Iterator it=itbegin;it!=itend;++it) + { + SetInitialDofs(space,*it,assembler,value,whichC,filter,fullDg); + } +} + +// Function Numbering Dof for rigid contact (Create Three Dofs for GC of rigid bodies) +template<class Assembler> +void NumberDofs(rigidContactSpace &space, Assembler &assembler){ + // get Dofs of GC + std::vector<Dof> R; + space.getKeysOfGravityCenter(R); + // Put them into DofManager + int nbdofs=R.size(); + for (int i=0;i<nbdofs;++i) + assembler.numberDof(R[i]); +} + +#endif //NONLINEARSOLVERALGORITHMS_H_ + diff --git a/NonLinearSolver/nlsolver/nonLinearMechSolver.cpp b/NonLinearSolver/nlsolver/nonLinearMechSolver.cpp new file mode 100644 index 0000000000..3e7fdce439 --- /dev/null +++ b/NonLinearSolver/nlsolver/nonLinearMechSolver.cpp @@ -0,0 +1,1852 @@ +// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include <string.h> +#include "GmshConfig.h" +#include "nonLinearMechSolver.h" +#include "linearSystemCSR.h" +#include "linearSystemPETSc.h" +#include "linearSystemGMM.h" +#include "Numeric.h" +#include "nlTerms.h" +#include "solverAlgorithms.h" +#include "quadratureRules.h" +#include "MPoint.h" +#include "ipstate.h" +#include "ipField.h" +#include "timeFunction.h" +#include "GModel.h" +#include "explicitHulbertChung.h" +#include "nlsolAlgorithms.h" +#include "nonLinearMechSolver.h" +#include "explicitDofManager.h" +#include "unknownDynamicField.h" +#include "MTriangle.h" +#include "MQuadrangle.h" +#include "energyField.h" +#include "nlsolAlgorithms.h" +#include "solverAlgorithms.h" +#include "quadratureRules.h" +#include "MPoint.h" +#include "timeFunction.h" +#include "unknownStaticField.h" +#include "staticDofManager.h" +#include "contactTerms.h" + + +#if defined(HAVE_POST) +#include "PView.h" +#include "PViewData.h" +#endif + +// nonLinearMechSolver +void nonLinearMechSolver::loadModel(const std::string meshFileName) +{ + pModel = new GModel(); + pModel->readMSH(meshFileName.c_str()); + _dim = pModel->getNumRegions() ? 3 : 2; +} + +void nonLinearMechSolver::init(){ + + // Set the material law for each domain and the gauss integration rule + for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){ + partDomain *dom = *it; + dom->setMaterialLaw(maplaw); + } + + // create interfaceElement + this->createInterfaceElement(); + + for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){ + partDomain *dom = *it; + dom->setGaussIntegrationRule(); + } + + // Split the BC between the different domain HAS TO BE AFTER DOMAIN INITIALIZATION + this->splitBoundaryConditions(); + + // initialisation of archiving force + this->initArchiveForce(); + + // find the domain associated to a physical slave number of a rigid contact interaction + // WARNING a contact interaction cannot be defined on two domains in the same time + // a physical group has to be define by domain + this->initContactInteraction(); +} + +void nonLinearMechSolver::initContactInteraction(){ + // find a common element betwwen slave group of element and the group of element of partdomain + bool flagfind; + for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain *cdom = *it; + flagfind = false; + // get first element + MElement *elementcont = cdom->getFirstElement(); + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + for(groupOfElements::elementContainer::iterator ite=dom->g->begin(); ite!=dom->g->end(); ++ite){ + MElement *ele = *ite; + if(ele == elementcont){ + flagfind =true; + cdom->setDomain(dom); +// spaceManager->addSpace(cdom); + break; + } + } + if(flagfind) break; + } + } + + // now init the contact boundary conditions + for(std::vector<rigidContactBC>::iterator it=allContactBC.begin(); it!=allContactBC.end(); ++it){ + rigidContactBC &diri = *it; + if(diri.onWhat == nonLinearBoundaryCondition::RIGIDCONTACT){ + for(contactContainer::iterator itcdom = _allContact.begin(); itcdom!=_allContact.end(); ++itcdom){ + contactDomain *cdom = *itcdom; + if(cdom->getPhys() == diri._tag){ + rigidContactSpace *sp = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + diri.setSpace(sp); + break; + } + } + } + } +} + +void nonLinearMechSolver::splitBoundaryConditions(){ + + // loop on BC + // BC which are prescribed weakly (the interfaceElement has to be finded in vinter) + // to prescribed the BC + + // Theta + for(std::vector<nonLinearNeumannBC>::iterator it=allTheta.begin(); it!=allTheta.end(); ++it){ + nonLinearNeumannBC &neu = *it; + for(groupOfElements::elementContainer::iterator ite=neu.g->begin(); ite!=neu.g->end(); ++ite){ + MVertex *vv = (*ite)->getVertex(2); + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + if(dom->IsInterfaceTerms()){ // change this (virtual interface has to be defined on domain) + // Ok because 2nd degree min BoundaryInterfaceElement is created only for this vertex + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + groupOfElements *gvi = dgdom->giv; + for(groupOfElements::elementContainer::const_iterator it_inter = gvi->begin(); it_inter!=gvi->end();++it_inter){ + MElement *minter = *it_inter; + //loop on component of map_edge + int numvertexminus1 = minter->getNumVertices()-1; + if((vv == minter->getVertex(2)) or (vv == minter->getVertex(numvertexminus1))){ + dgdom->gib->insert(minter); + break; + } + } + } + } + } + } + + //Dirichlet + for(int i=0;i<allDirichlet.size();i++){ + // loop on element + // map + std::map<partDomain*,std::vector<MElement*> > mapfind; + for(groupOfElements::elementContainer::iterator it=allDirichlet[i].g->begin(); it!=allDirichlet[i].g->end();++it){ + MElement *e = *it; + // Loop on all Domain to find on which domain the BC is applied + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + // if Dimensions are the same the element can be find with a comparison to element + partDomain *dom = *itdom; + // otherwise the vertex must be identified separately + MElement *etest = *(dom->g->begin()); + if( (etest !=NULL) and (etest->getDim() == e->getDim())){ + for(groupOfElements::elementContainer::iterator it2=dom->g->begin(); it2!=dom->g->end(); ++it2){ + if(*it2 == e){ // The Element is contained in the domain + mapfind[dom].push_back(e); + break; + } + } + } + else{ // loop on Vertex identify the BC with first INTERIOR vertex of e degree 2 min OK ( border vertex are included in 2 elements) + // an element is included in one domain --> one vertex of Element is OK + // On interface the BC is put on the first met domain + MVertex *ver = e->getVertex(2); + for(groupOfElements::vertexContainer::iterator itv=dom->g->vbegin(); itv!=dom->g->vend(); ++itv){ + if((*itv) == ver){ + mapfind[(*itdom)].push_back(e); + break; + } + } + } + } + } + // now One BC is created on domain + for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){ + if(it->second.size() !=0){ + allDirichlet[i].g = new groupOfElements(it->second); + nonLinearDirichletBC *diri = new nonLinearDirichletBC(allDirichlet[i]); + it->first->addDirichletBC(diri); + } + } + } + + // Idem for Neumann BC APPLY ON FIRST FOUNDED DOM + for(int i=0;i<allNeumann.size();i++){ + // loop on element + // map + std::map<partDomain*,std::vector<MElement*> > mapfind; + std::map<partDomain*,MElement*> mapelemtype; // need for gauss quadrature rule TODO Regroup with mapfind in a structure but no time benefit + for(groupOfElements::elementContainer::iterator it=allNeumann[i].g->begin(); it!=allNeumann[i].g->end();++it){ + MElement *e = *it; + // Loop on all Domain to find on which domain the BC is applied + bool flagfind = false; + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + // if Dimensions are the same the element can be find with a comparison to element + partDomain *dom = *itdom; + // otherwise the vertex must be identified separately + MElement *etest = *(dom->g->begin()); + mapelemtype[dom] = etest; + if( (etest != NULL) and (etest->getDim() == e->getDim())){ + for(groupOfElements::elementContainer::iterator it2=dom->g->begin(); it2!=dom->g->end(); ++it2){ + if(*it2 == e){ // The Element is contained in the domain + mapfind[dom].push_back(e); + flagfind = true; + break; + } + } + } + else{ // loop on Vertex identify the BC with first vertex of e + // an element is included in one domain --> one vertex of Element is OK + MVertex *ver = e->getVertex(0); + for(groupOfElements::vertexContainer::iterator itv=dom->g->vbegin(); itv!=dom->g->vend(); ++itv){ + if((*itv) == ver){ + mapfind[(*itdom)].push_back(e); + flagfind = true; + break; + } + } + } + if(flagfind) + break; + } + } + // now One BC is created on domain + for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){ + nonLinearNeumannBC *neu = new nonLinearNeumannBC(allNeumann[i]); + neu->g = new groupOfElements(it->second); + it->first->addNeumannBC(neu); + } + } + + // Initial + for(int i=0;i<allinitial.size();i++){ + // loop on element + // map + std::map<partDomain*,std::vector<MElement*> > mapfind; + for(groupOfElements::elementContainer::iterator it=allinitial[i].g->begin(); it!=allinitial[i].g->end();++it){ + MElement *e = *it; + // Loop on all Domain to find on which domain the BC is applied + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + // if Dimensions are the same the element can be find with a comparison to element + partDomain *dom = *itdom; + // otherwise the vertex must be identified separately + MElement *etest = *(dom->g->begin()); + if(etest->getDim() == e->getDim()){ + for(groupOfElements::elementContainer::iterator it2=dom->g->begin(); it2!=dom->g->end(); ++it2){ + if(*it2 == e){ // The Element is contained in the domain + mapfind[dom].push_back(e); + break; + } + } + } + else{ // loop on Vertex identify the BC with first vertex of e + // an element is included in one domain --> one vertex of Element is OK + // On interface the BC is put on the first met domain + MVertex *ver = e->getVertex(0); + for(groupOfElements::vertexContainer::iterator itv=dom->g->vbegin(); itv!=dom->g->vend(); ++itv){ + if((*itv) == ver){ + mapfind[(*itdom)].push_back(e); + break; + } + } + } + } + } + // now One Initial Condition is created on domain + for(std::map<partDomain*,std::vector<MElement*> >::iterator it=mapfind.begin(); it!=mapfind.end(); ++it){ + initialCondition *initC = new initialCondition(allinitial[i]); + initC->g = new groupOfElements(it->second); + it->first->addInitialCondition(initC); + } + } + // At this stage the BC contains in allDirichlet and allNeumann are not used so + // they can be deleted + allNeumann.clear(); + allDirichlet.clear(); + allinitial.clear(); +}; + +void nonLinearMechSolver::setTimeForBC(double time){ + for (std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + (*itdom)->setTimeBC(time); + } + + // set time for rigid contact BC + for(std::vector<rigidContactBC>::iterator it = allContactBC.begin(); it!=allContactBC.end(); ++it){ + (*it)._f.setTime(time); + } +} + +void nonLinearMechSolver::fixNodalDofs(){ + // Fixation (prescribed displacement) + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + for(partDomain::diriContainer::iterator it=dom->diriBegin(); it!=dom->diriEnd(); ++it){ + nonLinearDirichletBC *diri = *it; + FixNodalDofs(diri->_space,diri->g->begin(),diri->g->end(),*pAssembler,diri->_f,*diri->_filter,dom->getFormulation()); + } + } + + // prescribed displacement of rigid bodies (CG) + for(std::vector<rigidContactBC>::iterator it=allContactBC.begin(); it!=allContactBC.end(); ++it){ + rigidContactBC &rcbc = *it; + int physMaster = rcbc._tag; // for rigid BC tag == physMaster; + // Find the associated dom to create filter dof (Store in the BC to avoid search at each iteration !!) + FilterDof *filter; + bool ffind = false; + for(contactContainer::const_iterator it=_allContact.begin(); it!=_allContact.end();++it){ + contactDomain *cdom = *it; + if(cdom->getPhys() == physMaster){ + filter = cdom->getDomain()->createFilterDof(rcbc._comp); + ffind = true; + break; + } + } + if(ffind) + FixNodalDofs(rcbc.space,rcbc._f,*filter,*pAssembler); + else + Msg::Error("Impossible to fix dof for rigid contact BC %d",rcbc._tag); + } +} + +void nonLinearMechSolver::numberDofs(linearSystem<double> *lsys){ + // we number the dofs : when a dof is numbered, it cannot be numbered + // again with another number. + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom) + { + partDomain *dom = *itdom; + NumberDofs(*(dom->getFunctionSpace()), dom->g->begin(), dom->g->end(),*pAssembler); + } + // NumberDofs of Rigid Contact Entities (Dofs for GC) + for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain* cdom = *it; + if(cdom->isRigid()){ + rigidContactSpace *rcspace = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + NumberDofs(*rcspace,*pAssembler); + } + } + // total number of unkowns to allocate the system + double nunk = pAssembler->sizeOfR(); + // allocate system + lsys->allocate(nunk); +} + +void nonLinearMechSolver::addDomain(partDomain* dom){ + // initialization of GroupOfElements + int dim = dom->getDim(); + int phys = dom->getPhysical(); + dom->g = new groupOfElements(dim,phys); + domainVector.push_back(dom); +} + +void nonLinearMechSolver::addMaterialLaw(materialLaw* mlaw){ + maplaw.insert(std::pair<int,materialLaw*>(mlaw->getNum(),mlaw)); +} + +materialLaw* nonLinearMechSolver::getMaterialLaw(const int num){ + return (maplaw.find(num)->second); +} + +void nonLinearMechSolver::thetaBC(const int numphys){ + groupOfElements *goe = new groupOfElements(1,numphys); + this->insertTheta(numphys,goe); +} + +void nonLinearMechSolver::setInitOrRestartFileName(const std::string fname){ + initOrResartfname =fname; + _restart = true; +} + +void nonLinearMechSolver::restart(unknownField *ufield){ + if(!_restart) // no file to restart + return; + // create a map between elem number and adress + std::map<long int,std::pair<partDomain*,MElement*> > allelem; + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + for(groupOfElements::elementContainer::iterator ite = dom->g->begin(); ite!=dom->g->end(); ++ite){ + MElement *ele = *ite; + std::pair<partDomain*,MElement*> pa(dom,ele); + allelem.insert(std::pair<long int,std::pair<partDomain*,MElement*> >(ele->getNum(),pa)); + } + } + + // read data in file + FILE *f = fopen(initOrResartfname.c_str(), "r"); + char what[256]; + while(!feof(f)){ + fscanf(f, "%s", what); + if(!strcmp(what,"$ElementNodeData")){ + int nstring; + fscanf(f,"%d",&nstring); + int i=0; + char what2[256]; + while(i<nstring){ + fscanf(f,"%s",&what2); + i++; + } + int nint, n; + fscanf(f,"%d",&nint); + i=0; + while(i<nint){ + fscanf(f,"%d",&n); + i++; + } + fscanf(f,"%d",&nint); + i=0; + while(i<nint){ + fscanf(f,"%d",&n); + i++; + } + int elemnum,elemtype,ndofs,nvertex,ncomp; + i = 0; + int n2 = n; // because n is modified by fscanf(f,"%ld %d",&elemnum,&elemtype); WHY ?? + while(i<n2){ + fscanf(f,"%d %d",&elemnum,&elemtype); + //MElement *ele = allelem[elemnum].second; + //partDomain *dom = allelem[elem] + std::map<long int,std::pair<partDomain*,MElement*> >::iterator it = allelem.find(elemnum); + MElement *ele = (it->second).second; + partDomain *dom = (it->second).first; + FunctionSpaceBase *space = dom->getFunctionSpace(); + std::vector<Dof> R; + space->getKeys(ele,R); + ndofs = space->getNumKeys(ele); + nvertex = ele->getNumVertices(); + ncomp = ndofs/nvertex; + int j=0; + std::vector<double> disp; + disp.resize(ndofs); + //double temp; + while(j<nvertex){ + for(int k=0;k<ncomp;k++){ + fscanf(f,"%lf",&disp[j+k*nvertex]); + } + j++; + } + // set displacement in displacement field + ufield->setInitial(R,disp); + i++; + } + } + } + fclose(f); + ufield->buildView(domainVector,0.0,0,"displacement",-1,false); +} + +void nonLinearMechSolver::insertTheta(const int numphys, groupOfElements *goe){ + nonLinearNeumannBC neu; + neu.g = goe; + neu.onWhat = nonLinearBoundaryCondition::UNDEF; + neu._tag = numphys; + neu._f = new simpleFunctionTimeWithConstant<double>(0.); + allTheta.push_back(neu); +} + +void nonLinearMechSolver::physInitBroken(const int numphys){ + initbrokeninter.push_back(numphys); +} + +void nonLinearMechSolver::createInterfaceElement(){ + // Compute and add interface element to the model + // Loop on mesh element and store each edge (which will be distributed between InterfaceElement, Boundary InterfaceElement and VirtualInterfaceElement) + // A tag including the vertex number is used to identified the edge common to two elements. In this case a interface element is created + // manage creation of interface between 2 domains + manageInterface maninter(&domainVector); + // loop on element + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom !=domainVector.end(); ++itdom) + { + partDomain *dom = *itdom; + dom->createInterface(maninter); +/* dgPartDomain* dom = dynamic_cast<dgPartDomain*>(*itdom); + if(dom->IsInterfaceTerms()){ + for (groupOfElements::elementContainer::const_iterator it = dom->g->begin(); it != dom->g->end(); ++it) + { + MElement *e=*it; + int nedge = e->getNumEdges(); + for(int j=0;j<nedge;j++){ + std::vector<MVertex*> vv; + e->getEdgeVertices(j,vv); + Iedge ie = Iedge(vv,e,dom->getPhysical()); + unsigned long int key = ie.getkey(); + const std::map<unsigned long int,Iedge>::iterator it_edge=map_edge.find(key); + if(it_edge == map_edge.end()) // The edge doesn't exist -->inserted into the map + map_edge.insert(std::pair<unsigned long int,Iedge>(key,ie)); + else{ // create an interface element and remove the entry in map_edge + MInterfaceElement *interel = new MInterfaceElement(vv, 0, 0, e, it_edge->second.getElement()); + // Two cases + if(ie.getPhys() == it_edge->second.getPhys()) // Internal Interface + dom->gi->insert(interel); + else{ // Interface between 2 domains --> create a new domain if it doesn't exist + // find the domain of itedge + std::vector<partDomain*>::iterator itdom2; + for(itdom2 = domainVector.begin(); itdom2!=domainVector.end(); ++itdom2) + if((*itdom2)->getPhysical() == it_edge->second.getPhys()) break; + manageDom->add(interel,dom,*itdom2,maplaw); + this->addInterface(interel); + } + map_edge.erase(it_edge); + } + } + } + }*/ + } + + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + int phys = dom->getPhysical(); + for(manageInterface::IelementContainer::iterator it=maninter.begin(); it!=maninter.end(); ++it){ + IElement *ie = it->second; + if(ie->getPhys() == phys){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + MElement* interel = dom->createVirtualInterface(ie); + dgdom->giv->insert(interel); + } + } + } +} + +void nonLinearMechSolver::createInterfaceElement_2() +{ + // The contructor of dgGroupCollection create automatically the GroupsOfElements +/* _groups = dgGroupCollection(this->pModel,this->_dim,1); // TODO ?? Add parameter to model to store order + _groups.buildGroupsOfInterfaces(); + // Affichage temporaire pour vérification + int nn = _groups.getNbFaceGroups(); + printf("Number of group of faces : %d\n",nn); + for(int i=0;i<nn;i++){ + printf("Group of face number %d\n",i); + dgGroupOfFaces *inter = _groups.getFaceGroup(i); + int nnn = inter->getNbGroupOfConnections(); + printf("Number of connection group %d \n",nnn); + for(int j=0;j<nnn;j++){ + const dgGroupOfConnections connec = inter->getGroupOfConnections(j); + printf("Connection's group number %d\n",j); + int nnnn = connec.getNbClosures(); + printf("Number of closures %d\n",nnnn); + for(int k=0;k<nnnn;k++){ + printf("Closure number %d\n",k); + std::vector<int> vec = connec.getClosure(k); + for(int kk=0;kk<vec.size();kk++){ + printf(" %d ",vec[kk]); + } + printf("\n"); + } + } + }*/ +} + +void nonLinearMechSolver::initTerms(unknownField *ufield, IPField *ipf){ + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + dom->initializeTerms(ufield,ipf); + } + + // contact domain + for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain *cdom = *it; + if(cdom->getContactType() == contactDomain::rigidCylinder){ + rigidCylinderContact *rcc = dynamic_cast<rigidCylinderContact*>(cdom); + rcc->initializeTerms(ufield); + } + else Msg::Error("Terms are not defined for contact type %d",cdom->getContactType()); + } + +} + +void nonLinearMechSolver::solveStaticLinar() +{ +// init data +this->init(); +linearSystem<double> *lsys; +if(nonLinearMechSolver::whatSolver == Taucs){ + #if defined(HAVE_TAUCS) + lsys = new linearSystemCSRTaucs<double>; + printf("Taucs is chosen to solve\n"); + #else + lsys = new linearSystemGmm<double>; + lsys = dynamic_cast<linearSystemGmm<double>*>(lsys); + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + printf("Taucs is not installed\n Gmm is chosen to solve\n"); + #endif +} +else if(nonLinearMechSolver::whatSolver == Petsc){ + #if defined(HAVE_PETSC) + lsys = new linearSystemPETSc<double>; + printf("PETSc is chosen to solve\n"); + #else + lsys = new linearSystemGmm<double>; + lsys = dynamic_cast<linearSystemGmm<double>*>(lsys); + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + printf("PETSc is not installed\n Gmm is chosen to solve\n"); + #endif +} +else{ + lsys = new linearSystemGmm<double>; + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + printf("Gmm is chosen to solve\n"); +} + + if (pAssembler) delete pAssembler; + pAssembler = new dofManager<double>(lsys); + + std::cout << "Dirichlet BC"<< std::endl; + // we first do all fixations. the behavior of the dofManager is to + // give priority to fixations : when a dof is fixed, it cannot be + // numbered afterwards + // Fix dof to allow the numbering of Dof by dofManager + this->fixNodalDofs(); + this->numberDofs(lsys); + + // displacement field + unknownField *ufield = new unknownStaticField(pAssembler,domainVector,&_allContact,3,anoded,varcd); + this->restart(ufield); // CHANGE THIS + // Store stress and deformation at each gauss point + // IPState "declaration" reserve place for data + IPField ipf(&domainVector,pAssembler, pModel, ufield, vaip); // Todo fix this + ipf.compute1state(IPStateBase::initial); + ipf.copy(IPStateBase::initial,IPStateBase::current); // initialization of Bvector and LocalBasis + this->initTerms(ufield,&ipf); + + // Now we start the assembly process + // First build the force vector + std::cout << "Neumann BC"<< std::endl; + this->computeExternalForces(&ipf,ufield); + this->computeStiffMatrix(ufield); + printf("-- done assembling!\n"); + lsys->systemSolve(); + printf("-- done solving!\n"); + + // compute stress after solve + ufield->update(); + ipf.compute1state(IPStateBase::current); + // save solution (for visualisation) + ipf.buildView(domainVector,0.,1,"VonMises",-1,false); + ufield->buildView(domainVector,0.,1,"displacement",-1,false); + ufield->archiving(1.); + ipf.archive(1.); + delete ufield; +} + +void nonLinearMechSolver::computeExternalForces(IPField *ipf, const unknownField *ufield){ + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end();++itdom){ + partDomain *dom = *itdom; + for(partDomain::neuContainer::iterator it=dom->neuBegin(); it!=dom->neuEnd();++it){ + nonLinearNeumannBC *neu = *it; + Assemble(neu->_term,*(neu->_space),neu->g->begin(),neu->g->end(),*(neu->integ),ufield,*pAssembler); + } + } +} + +void nonLinearMechSolver::snlData(const int ns, const double et, const double reltol){ + if(whatScheme==StaticNonLinear){ + numstep=ns;endtime=et;_tol=reltol; + } + else{ + Msg::Error("Impossible to set data for Static Non Linear scheme because another is chosen to solve the problem"); + } +} + +void nonLinearMechSolver::explicitData(const double ftime, const double gams, const double beta, const double gamma, const double alpham){ + endtime = ftime; + _beta=beta; + _gamma=gamma; + _alpham = alpham; + // depends on numerical damping + double omegas; + _rhoinfty = (alpham+1.)/(2.-alpham); + omegas = sqrt((12.*(1.+_rhoinfty)*(1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty))/(10.+15.*_rhoinfty-_rhoinfty*_rhoinfty+_rhoinfty*_rhoinfty*_rhoinfty-_rhoinfty*_rhoinfty*_rhoinfty*_rhoinfty)); + _gammas = gams*omegas; +} + +void nonLinearMechSolver::explicitSpectralRadius(const double ftime,const double gams, const double rho){ + endtime = ftime; + _rhoinfty=rho; + _beta = (5.-3.*_rhoinfty)/((1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty)); + _alpham = (2.*_rhoinfty-1.)/(1.+_rhoinfty); + _gamma = 1.5-_alpham; + double omegas = sqrt((12.*(1.+_rhoinfty)*(1.+_rhoinfty)*(1.+_rhoinfty)*(2.-_rhoinfty))/(10.+15.*_rhoinfty-_rhoinfty*_rhoinfty+_rhoinfty*_rhoinfty*_rhoinfty-_rhoinfty*_rhoinfty*_rhoinfty*_rhoinfty)); + _gammas = gams*omegas; +} + +void nonLinearMechSolver::explicitTimeStepEvaluation(const int nst){ + numstep = nst; +} + +void nonLinearMechSolver::solve(){ + switch(whatScheme){ + case StaticLinear : + this->solveStaticLinar(); + break; + case StaticNonLinear : + this->solveSNL(); + break; + case Explicit: + this->solveExplicit(); + } +} + +void nonLinearMechSolver::displacementBC(std::string onwhat, const int numphys, const int comp, const double value){ + nonLinearDirichletBC diri; + const std::string node("Node"); + const std::string edge("Edge"); + const std::string face("Face"); + if(onwhat==node){ + diri.g = new groupOfElements (0, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_VERTEX; + } + else if(onwhat==edge){ + diri.g = new groupOfElements (1, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_EDGE; + } + else if(onwhat==face){ + diri.g = new groupOfElements (2, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_FACE; + } + else Msg::Error("Impossible to prescribe a displacement on a %s\n",onwhat.c_str()); + diri._f= simpleFunctionTime<double>(value); + diri._comp=comp; + diri._tag=numphys; + allDirichlet.push_back(diri); +} + +void nonLinearMechSolver::displacementRigidContactBC(const int numphys, const int comp_, const double value){ + rigidContactBC diri(numphys); + diri.onWhat = nonLinearBoundaryCondition::RIGIDCONTACT; + diri._comp = comp_; + diri._f = simpleFunctionTime<double>(value); + allContactBC.push_back(diri); +} + +void nonLinearMechSolver::initialBC(std::string onwhat, std::string whichC, const int numphys, + const int comp, const double value){ + + const std::string node("Node"); + const std::string edge("Edge"); + const std::string face("Face"); + const std::string position("Position"); + const std::string velocity("Velocity"); + const std::string acceleration("Acceleration"); + + nonLinearBoundaryCondition::location ow; + groupOfElements *gr; + if(onwhat == node){ + ow = nonLinearBoundaryCondition::ON_VERTEX; + gr = new groupOfElements(0,numphys); + } + else if(onwhat == edge){ + ow = nonLinearBoundaryCondition::ON_EDGE; + gr = new groupOfElements(1,numphys); + } + else if(onwhat == face){ + ow = nonLinearBoundaryCondition::ON_FACE; + gr = new groupOfElements(2,numphys); + } + else{ + ow = nonLinearBoundaryCondition::UNDEF; + gr = new groupOfElements(2,numphys); + } + + initialCondition::whichCondition wc; + if(whichC == position) + wc = initialCondition::position; + else if(whichC == velocity) + wc = initialCondition::velocity; + else if(whichC == acceleration) + wc = initialCondition::acceleration; + else{ + Msg::Warning("Impossible to prescribed an initial condition %d",numphys); + //return; + } + initialCondition initc(value,comp,wc); + initc.onWhat = ow; + initc.g = gr; + initc._tag = numphys; + allinitial.push_back(initc); +} + +void nonLinearMechSolver::independentDisplacementBC(std::string onwhat, const int numphys, const int comp, const double value){ + nonLinearDirichletBC diri; + const std::string node("Node"); + const std::string edge("Edge"); + const std::string face("Face"); + if(onwhat==node){ + diri.g = new groupOfElements (0, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_VERTEX; + } + else if(onwhat==edge){ + diri.g = new groupOfElements (1, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_EDGE; + } + else if(onwhat==face){ + diri.g = new groupOfElements (2, numphys); + diri.onWhat=nonLinearBoundaryCondition::ON_FACE; + } + else Msg::Error("Impossible to prescribe a displacement on a %s\n",onwhat.c_str()); + diri._f= simpleFunctionTime<double>(value,false); + diri._comp=comp; + diri._tag=numphys; + allDirichlet.push_back(diri); +} + +void nonLinearMechSolver::forceBC(std::string onwhat, const int numphys, const int comp, const double val){ + nonLinearNeumannBC neu; + const std::string node("Node"); + const std::string edge("Edge"); + const std::string face("Face"); + const std::string volume("Volume"); + if(onwhat==node){ + neu.g = new groupOfElements (0, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_VERTEX; + } + else if(onwhat==edge){ + neu.g = new groupOfElements (1, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_EDGE; + } + else if(onwhat==face){ + neu.g = new groupOfElements (2, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_FACE; + } + else if(onwhat==volume){ + neu.g = new groupOfElements (3, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_VOLUME; + } + else Msg::Error("Impossible to prescribe a force on a %s\n",onwhat.c_str()); + neu._f= new simpleFunctionTimeWithConstant<double>(val); + neu._tag=numphys; + neu._comp=comp; + allNeumann.push_back(neu); +} + +void nonLinearMechSolver::independentForceBC(std::string onwhat, const int numphys, const int comp, const double val){ + nonLinearNeumannBC neu; + const std::string node("Node"); + const std::string edge("Edge"); + const std::string face("Face"); + const std::string volume("Volume"); + if(onwhat==node){ + neu.g = new groupOfElements (0, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_VERTEX; + } + else if(onwhat==edge){ + neu.g = new groupOfElements (1, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_EDGE; + } + else if(onwhat==face){ + neu.g = new groupOfElements (2, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_FACE; + } + else if(onwhat==volume){ + neu.g = new groupOfElements (3, numphys); + neu.onWhat=nonLinearBoundaryCondition::ON_VOLUME; + } + else Msg::Error("Impossible to prescribe a force on a %s\n",onwhat.c_str()); + neu._f= new simpleFunctionTimeWithConstant<double>(val,false); + neu._tag=numphys; + neu._comp = comp; + allNeumann.push_back(neu); +} + +void nonLinearMechSolver::pressureOnPhysicalGroupBC(const int numphys, const double press, const double p0){ + nonLinearNeumannBC neu; + neu.g = new groupOfElements(2,numphys); // Always group of face ?? + neu.onWhat = nonLinearBoundaryCondition::PRESSURE; + neu._f = new simpleFunctionTimeWithConstant<double>(press,true,1.,p0); // Use a SVector3 because it was defined like this in + neu._tag=numphys; + allNeumann.push_back(neu); +} + +void nonLinearMechSolver::blastPressureBC(const int numphys,const double p0,const double p1, const double plexp, + const double t0, const double t1){ + powerDecreasingFunctionTime *pdl = new powerDecreasingFunctionTime(p0,p1,plexp,t0,t1,this->endtime); + nonLinearNeumannBC neu(numphys,5,pdl); + allNeumann.push_back(neu); +} + +void nonLinearMechSolver::archivingForceOnPhysicalGroup(const std::string onwhat, const int numphys, const int comp){ + // get the node of the edge + std::string node("Node"); + std::string edge("Edge"); + std::string face("Face"); + std::string volu("Volume"); + int dim=0; + if(onwhat == node ) + dim = 0; + else if(onwhat == edge) + dim = 1; + else if(onwhat == face) + dim = 2; + else if(onwhat == volu) + dim = 3; + + vaf.push_back(archiveForce(numphys,dim,comp)); + + // remove old file (linux only ??) + std::ostringstream oss; + oss << numphys; + std::string s = oss.str(); + oss.str(""); + oss << comp; + std::string s2 = oss.str(); + std::string rfname = "rm force"+s+"comp"+s2+".csv"; + system(rfname.c_str()); +} + +void nonLinearMechSolver::initArchiveForce(){ + for(std::vector<archiveForce>::iterator itf=vaf.begin(); itf!=vaf.end(); ++itf){ + archiveForce &af = *itf; + std::vector<MVertex*> vv; + pModel->getMeshVerticesForPhysicalGroup(af.dim,af.numphys,vv); + std::vector<Dof> vdof;// all dof include in the edge + + // shell element + // loop on domain (to find the domain where the force is applied) + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + FilterDof* filter = dom->createFilterDof(af.comp); + if(!(dom->getFormulation())){ // Cg/Dg + for(groupOfElements::vertexContainer::iterator itv=dom->g->vbegin(); itv!=dom->g->vend(); ++itv){ + MVertex *ver = *itv; + for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){ + MVertex *vver = *it; + if(ver == vver){ + MPoint ele = MPoint(ver,-1); // We don't care about element number it's just to have the vertex keys + // build the dof + sp->getKeys(&ele,R); + for(int j=0;j<R.size(); j++) + if(filter->operator()(R[j])) + vdof.push_back(R[j]); + R.clear(); + break; + } + } + } + } + else{ // full Dg + for(groupOfElements::elementContainer::iterator ite = dom->g->begin(); ite!=dom->g->end(); ++ite){ + MElement *ele = *ite; + int nbvertex = ele->getNumVertices(); + sp->getKeys(ele,R); + for(std::vector<MVertex*>::iterator it=vv.begin(); it!=vv.end(); ++it){ + for(int j=0;j<nbvertex; j++){ + if(ele->getVertex(j) == *it){ + vdof.push_back(R[j+nbvertex*af.comp]); + break; + } + } + } + R.clear(); + } + } + } + // keys = 10*numphys + comp otherwise no way to archive different components + int key = 10*af.numphys+af.comp; + aef[key] = vdof; + aefvalue[key] = 0.; + } + // force on prescribed displacement (needed to compute external work) + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!= domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + std::vector<Dof> R; + bool flag; + for(partDomain::diriContainer::iterator itd = dom->diriBegin(); itd!=dom->diriEnd(); ++itd){ + nonLinearDirichletBC *diri = *itd; + if(diri->_f(0.,0.,0.) != 0.){ // f = simplke Function independant of position otherwise wext = 0 + FunctionSpaceBase *sp = diri->_space; + for(groupOfElements::elementContainer::iterator it = diri->g->begin(); it!=diri->g->end(); ++it){ + MElement *ele = *it; + sp->getKeys(ele,R); + for(int i=0; i<R.size(); i++){ + flag = true; + for(std::vector<fextPrescribedDisp>::iterator it2 = _allaef.begin(); it2 != _allaef.end(); ++it2){ + if(R[i] == (*it2).D){ + flag = false; + break; + } + } + if(flag) + { + fextPrescribedDisp fpd = fextPrescribedDisp(R[i]); + _allaef.push_back(fpd); + } + } + R.clear(); + } + } + } + } +} + +void nonLinearMechSolver::archivingNodeDisplacement(const int numphys, const int comp){ + this->archivingNode(numphys,comp,initialCondition::position); +} + +void nonLinearMechSolver::archivingNodeVelocity(const int numphys, const int comp){ + this->archivingNode(numphys,comp,initialCondition::velocity); +} + +void nonLinearMechSolver::archivingNodeAcceleration(const int numphys, const int comp){ + this->archivingNode(numphys,comp,initialCondition::acceleration); +} + +void nonLinearMechSolver::archivingNode(const int numphys, const int comp, initialCondition::whichCondition wc){ + // no distinction between cG/dG and full Dg formulation. class Displacement Field manage it + std::vector<MVertex*> vv; + pModel->getMeshVerticesForPhysicalGroup(0,numphys,vv); + + if(vv.size() !=0){ + std::pair< Dof,initialCondition::whichCondition > pai(Dof(vv[0]->getNum(),Dof3IntType::createTypeWithThreeInts(comp,_tag)),wc); + anoded.push_back(pai); + // remove old file (linux only ??) + std::ostringstream oss; + oss << vv[0]->getNum(); // Change this + std::string s = oss.str(); + oss.str(""); + oss << comp; + std::string s2 = oss.str(); + std::string rfname; + switch(wc){ + case initialCondition::position: + rfname= "rm NodalDisplacement"+s+"comp"+s2+".csv"; + break; + case initialCondition::velocity: + rfname= "rm NodalVelocity"+s+"comp"+s2+".csv"; + break; + case initialCondition::acceleration: + rfname= "rm NodalAcceleration"+s+"comp"+s2+".csv"; + break; + } + system(rfname.c_str()); + } + else{ + Msg::Warning("No physical group %d So it is impossible to archive nodal displacement",numphys); + } +} + +void nonLinearMechSolver::archivingRigidContact(const int numphys, const int comp, const int wc){ + initialCondition::whichCondition whc; + switch(wc){ + case 0: + whc = initialCondition::position; + break; + case 1: + whc = initialCondition::velocity; + break; + case 2: + whc = initialCondition::acceleration; + break; + default: + whc = initialCondition::position; + } + // find domain + partDomain *domf=NULL; + for(contactContainer::const_iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain *cdom = *it; + if(cdom->getPhys() == numphys){ + int physDom = cdom->getPhysSlave(); + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + if(dom->getPhysical() == physDom){ + domf = dom; + break; + } + } + break; + } + } + if(domf != NULL){ + archiveRigidContactDisp ar(numphys,comp,whc,domf); + varcd.push_back(ar); + + // remove of csv file Linux only + std::ostringstream oss; + oss << numphys; // Change this + std::string s = oss.str(); + oss.str(""); + oss << comp; + std::string s2 = oss.str(); + std::string rfname; + switch(whc){ + case initialCondition::position: + rfname= "rm NodalDisplacement"+s+"comp"+s2+".csv"; + break; + case initialCondition::velocity: + rfname= "rm NodalVelocity"+s+"comp"+s2+".csv"; + break; + case initialCondition::acceleration: + rfname= "rm NodalAcceleration"+s+"comp"+s2+".csv"; + break; + } + system(rfname.c_str()); + } + else{ + Msg::Error("Impossible to archive displacement for contact number %d",numphys); + } +} + +void nonLinearMechSolver::archivingNodeIP(const int numphys, const int ipval){ + vaip.push_back(archiveIPVariable(numphys,ipval)); +} + +void nonLinearMechSolver::contactInteraction(contactDomain *cdom){ + _allContact.insert(cdom); +} + + +// +// C++ Interface: terms explicit +// +// Description: Files with definition of function : nonLinearMechSolver::solveExplicit() +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +double distanceMin(const double x1, const double x2, const double x3, + const double y1, const double y2, const double y3, + const double z1, const double z2, const double z3){ + double dist1 = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)); + double dist2 = sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+(z2-z3)*(z2-z3)); + if(dist1 > dist2) + dist1 = sqrt((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1)); + else + dist2 = sqrt((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1)); + if(dist1 > dist2) + return dist2; + else + return dist1; +} +// PUT THIS IN MELEMENT ?? +double triangleCharacteristicSize(MElement *ele, unknownField *ufield, std::vector<Dof> &R){ + std::vector<double> disp; + ufield->get(R,disp); + double x1 = ele->getVertex(0)->x() + disp[0]; + double x2 = ele->getVertex(1)->x() + disp[1]; + double x3 = ele->getVertex(2)->x() + disp[2]; + double y1 = ele->getVertex(0)->y() + disp[3]; + double y2 = ele->getVertex(1)->y() + disp[4]; + double y3 = ele->getVertex(2)->y() + disp[5]; + double z1 = ele->getVertex(0)->z() + disp[6]; + double z2 = ele->getVertex(1)->z() + disp[7]; + double z3 = ele->getVertex(2)->z() + disp[8]; + return distanceMin(x1,x2,x3,y1,y2,y3,z1,z2,z3); +/* double dist1 = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)); + double dist2 = sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)+(z2-z3)*(z2-z3)); + if(dist1 > dist2) + dist1 = sqrt((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1)); + else + dist2 = sqrt((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)+(z3-z1)*(z3-z1)); + if(dist1 > dist2) + return dist2; + else + return dist1;*/ +} + +// For quadrangle make the search for 2 triangle +double quadrangleCharacteriticSize(MElement *ele,unknownField *ufield, std::vector<Dof> &R){ + double hmin1,hmin2; + // first triangle node 1,2,3 + std::vector<Dof> R2; + + R2.push_back(R[0]); R2.push_back(R[1]); R2.push_back(R[2]); + R2.push_back(R[4]); R2.push_back(R[5]); R2.push_back(R[6]); + R2.push_back(R[8]); R2.push_back(R[9]); R2.push_back(R[10]); + MTriangle etri = MTriangle(ele->getVertex(0),ele->getVertex(1),ele->getVertex(2),-1,0); + hmin1 = triangleCharacteristicSize(&etri,ufield,R2); + + R2[0] = R[0]; R2[1] = R[2]; R2[2] = R[3]; + R2[3] = R[4]; R2[4] = R[6]; R2[5] = R[7]; + R2[6] = R[8]; R2[7] = R[10]; R2[8] = R[11]; + etri = MTriangle(ele->getVertex(0),ele->getVertex(2),ele->getVertex(3),-1,0); + hmin2 = triangleCharacteristicSize(&etri,ufield,R2); + + if(hmin1 > hmin2) return hmin2; + else return hmin1; +} + +double quadrangle2orderCharacteristicSize(MElement *ele,unknownField *ufield, std::vector<Dof> &R){ + double hmin1, hmin2; + // make 4 simple quadrangles + std::vector<Dof> R2; + + R2.push_back(R[0]); R2.push_back(R[4]); R2.push_back(R[8]); R2.push_back(R[7]); + R2.push_back(R[9]); R2.push_back(R[13]); R2.push_back(R[17]); R2.push_back(R[16]); + R2.push_back(R[18]);R2.push_back(R[22]); R2.push_back(R[26]); R2.push_back(R[25]); + MQuadrangle equad = MQuadrangle(ele->getVertex(0),ele->getVertex(4),ele->getVertex(8),ele->getVertex(7),-1,0); + hmin1 = quadrangleCharacteriticSize(&equad,ufield,R2); + + R2[0] = R[4]; R2[1] = R[1]; R2[2] = R[5]; R2[3] = R[8]; + R2[4] = R[13]; R2[5] = R[10]; R2[6] = R[14]; R2[7] = R[17]; + R2[8] = R[22]; R2[9] = R[19]; R2[10] = R[23]; R2[11] = R[26]; + equad = MQuadrangle(ele->getVertex(4),ele->getVertex(1),ele->getVertex(5),ele->getVertex(8),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + R2[0] = R[8]; R2[1] = R[5]; R2[2] = R[2]; R2[3] = R[6]; + R2[4] = R[17]; R2[5] = R[14]; R2[6] = R[11]; R2[7] = R[15]; + R2[8] = R[26]; R2[9] = R[23]; R2[10] = R[20]; R2[11] = R[24]; + equad = MQuadrangle(ele->getVertex(8),ele->getVertex(5),ele->getVertex(1),ele->getVertex(6),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + R2[0] = R[8]; R2[1] = R[6]; R2[2] = R[3]; R2[3] = R[7]; + R2[4] = R[17]; R2[5] = R[15]; R2[6] = R[12]; R2[7] = R[16]; + R2[8] = R[26]; R2[9] = R[24]; R2[10] = R[21]; R2[11] = R[25]; + equad = MQuadrangle(ele->getVertex(8),ele->getVertex(6),ele->getVertex(3),ele->getVertex(7),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + return hmin1; +} + +double quadrangle3orderCharacteristicSize(MElement *ele,unknownField *ufield, std::vector<Dof> &R){ + // 5 quadrangles of 1st order + One second order quadrangle + double hmin1,hmin2; + std::vector<Dof> R2; + + R2.push_back(R[0]); R2.push_back(R[4]); R2.push_back(R[12]); R2.push_back(R[11]); + R2.push_back(R[16]); R2.push_back(R[20]); R2.push_back(R[28]); R2.push_back(R[27]); + R2.push_back(R[32]); R2.push_back(R[36]); R2.push_back(R[44]); R2.push_back(R[43]); + MQuadrangle equad = MQuadrangle(ele->getVertex(0),ele->getVertex(4), ele->getVertex(12), ele->getVertex(11),-1,0); + hmin1 = quadrangleCharacteriticSize(&equad,ufield,R2); + + R2[0] = R[4]; R2[1] = R[5]; R2[2] = R[3]; R2[13] = R[12]; + R2[4] = R[20]; R2[5] = R[21]; R2[6] = R[19]; R2[7] = R[28]; + R2[8] = R[36]; R2[9] = R[37]; R2[10] = R[35]; R2[11] = R[44]; + equad = MQuadrangle(ele->getVertex(4),ele->getVertex(5),ele->getVertex(13),ele->getVertex(12),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + R2[0] = R[5]; R2[1] = R[1]; R2[2] = R[6]; R2[13] = R[13]; + R2[4] = R[21]; R2[5] = R[17]; R2[6] = R[22]; R2[7] = R[29]; + R2[8] = R[37]; R2[9] = R[33]; R2[10] = R[38]; R2[11] = R[45]; + equad = MQuadrangle(ele->getVertex(5),ele->getVertex(1),ele->getVertex(6),ele->getVertex(13),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + R2[0] = R[13]; R2[1] = R[6]; R2[2] = R[7]; R2[13] = R[14]; + R2[4] = R[29]; R2[5] = R[22]; R2[6] = R[23]; R2[7] = R[30]; + R2[8] = R[45]; R2[9] = R[38]; R2[10] = R[39]; R2[11] = R[46]; + equad = MQuadrangle(ele->getVertex(13),ele->getVertex(6),ele->getVertex(7),ele->getVertex(14),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + R2[0] = R[14]; R2[1] = R[7]; R2[2] = R[2]; R2[13] = R[8]; + R2[4] = R[30]; R2[5] = R[23]; R2[6] = R[18]; R2[7] = R[24]; + R2[8] = R[46]; R2[9] = R[39]; R2[10] = R[34]; R2[11] = R[40]; + equad = MQuadrangle(ele->getVertex(14),ele->getVertex(7),ele->getVertex(2),ele->getVertex(8),-1,0); + hmin2 = quadrangleCharacteriticSize(&equad,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + + // second order quadrangle + R2.clear(); + + R2.push_back(R[11]); R2.push_back(R[13]); R2.push_back(R[8]); R2.push_back(R[3]); R2.push_back(R[12]); R2.push_back(R[14]); R2.push_back(R[9]); R2.push_back(R[10]); R2.push_back(R[15]); + R2.push_back(R[27]); R2.push_back(R[29]); R2.push_back(R[24]); R2.push_back(R[19]); R2.push_back(R[28]); R2.push_back(R[30]); R2.push_back(R[25]); R2.push_back(R[26]); R2.push_back(R[31]); + R2.push_back(R[43]); R2.push_back(R[45]); R2.push_back(R[40]); R2.push_back(R[35]); R2.push_back(R[44]); R2.push_back(R[46]); R2.push_back(R[41]); R2.push_back(R[42]); R2.push_back(R[47]); + + MQuadrangle9 equad2 = MQuadrangle9(ele->getVertex(11),ele->getVertex(13),ele->getVertex(8),ele->getVertex(3), + ele->getVertex(12),ele->getVertex(14),ele->getVertex(9),ele->getVertex(10), + ele->getVertex(15),-1,0); + hmin2 = quadrangle2orderCharacteristicSize(&equad2,ufield,R2); + if(hmin1 > hmin2) hmin1 = hmin2; + return hmin1; + +} + +// dont use previous function change this ? +double triangular3orderCharacteristicSize(MElement *ele,unknownField *ufield,std::vector<Dof> &R){ + std::vector<double> disp; + ufield->get(R,disp); + double x0 = ele->getVertex(0)->x() + disp[0]; + double x1 = ele->getVertex(1)->x() + disp[1]; + double x2 = ele->getVertex(2)->x() + disp[2]; + double x3 = ele->getVertex(3)->x() + disp[3]; + double x4 = ele->getVertex(4)->x() + disp[4]; + double x5 = ele->getVertex(5)->x() + disp[5]; + double x6 = ele->getVertex(6)->x() + disp[6]; + double x7 = ele->getVertex(7)->x() + disp[7]; + double x8 = ele->getVertex(8)->x() + disp[8]; + double x9 = ele->getVertex(9)->x() + disp[9]; + + double y0 = ele->getVertex(0)->y() + disp[10]; + double y1 = ele->getVertex(1)->y() + disp[11]; + double y2 = ele->getVertex(2)->y() + disp[12]; + double y3 = ele->getVertex(3)->y() + disp[13]; + double y4 = ele->getVertex(4)->y() + disp[14]; + double y5 = ele->getVertex(5)->y() + disp[15]; + double y6 = ele->getVertex(6)->y() + disp[16]; + double y7 = ele->getVertex(7)->y() + disp[17]; + double y8 = ele->getVertex(8)->y() + disp[18]; + double y9 = ele->getVertex(9)->y() + disp[19]; + + double z0 = ele->getVertex(0)->z() + disp[20]; + double z1 = ele->getVertex(1)->z() + disp[21]; + double z2 = ele->getVertex(2)->z() + disp[22]; + double z3 = ele->getVertex(3)->z() + disp[23]; + double z4 = ele->getVertex(4)->z() + disp[24]; + double z5 = ele->getVertex(5)->z() + disp[25]; + double z6 = ele->getVertex(6)->z() + disp[26]; + double z7 = ele->getVertex(7)->z() + disp[27]; + double z8 = ele->getVertex(8)->z() + disp[28]; + double z9 = ele->getVertex(9)->z() + disp[29]; + double dist, distmin; + distmin = distanceMin(x0,x3,x8,y0,y3,y8,z0,z3,z8); + dist = distanceMin(x3,x9,x8,y3,y9,y8,z3,z9,z8); + if (dist < distmin) distmin = dist; + dist = distanceMin(x9,x3,x4,y9,y3,y4,z9,z3,z4); + if (dist < distmin) distmin = dist; + dist = distanceMin(x4,x5,x9,y4,y5,y9,z4,z5,z9); + if (dist < distmin) distmin = dist; + dist = distanceMin(x4,x5,x1,y4,y5,y1,z4,z5,z1); + if (dist < distmin) distmin = dist; + dist = distanceMin(x5,x6,x9,y5,y6,y9,z5,z6,z9); + if (dist < distmin) distmin = dist; + dist = distanceMin(x6,x9,x7,y6,y9,y7,z6,z9,z7); + if (dist < distmin) distmin = dist; + dist = distanceMin(x7,x8,x9,y7,y8,y9,z7,z8,z9); + if (dist < distmin) distmin = dist; + dist = distanceMin(x7,x6,x2,y7,y6,y2,z7,z6,z2); + if (dist < distmin) distmin = dist; + return distmin; +} + +double nonLinearMechSolver::criticalExplicitTimeStep(unknownField *ufield){ + // evaluate the critical time step carachteristic length = hs + // criteria = distance min between 2 nodes + double hs; + double dtmin=1.e100; // Initialization to infinity + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + double hsmin= 1.e100; // Initialization to infinity + FunctionSpaceBase *spdom = dom->getFunctionSpace(); + std::vector<Dof> R; + // As time step is compute on element the dom is not an "interface domain" + // so getMaterialLawMinus() == getMaterialLawPlus() + materialLaw *mlt = dom->getMaterialLaw(); + double celerity = mlt->soundSpeed(); + double scaleTimeStep = dom->scaleTimeStep(); + for(groupOfElements::elementContainer::iterator it=dom->g->begin(); it!=dom->g->end(); ++it){ + MElement *e = *it; + // nodal displacement + spdom->getKeys(e,R); + + // Unfortunally, computation of characteristic length depends on the element type + // Element are cut in several triangles of degree one + // ADD THIS FUNCTIONS directly in gmsh (method of MELEMENT) + switch(e->getTypeForMSH()){ + case MSH_TRI_3: + hs = triangleCharacteristicSize(e,ufield,R); + break; + case MSH_QUA_4: + hs = quadrangleCharacteriticSize(e,ufield,R); + break; + case MSH_QUA_9 : + hs = quadrangle2orderCharacteristicSize(e,ufield,R); + break; + case MSH_QUA_16: + hs = quadrangle3orderCharacteristicSize(e,ufield,R); + break; + case MSH_TRI_10: + hs = triangular3orderCharacteristicSize(e,ufield,R); + break; + default : + // default criteria area/(degree*perimter); + Msg::Warning("Use a invariant time step predictor because rule for time step computation is unknow for this element type"); + hs = MInterfaceElement::characSize(e); + hs/= e->getPolynomialOrder(); + } + + if(hs<hsmin) hsmin = hs; + R.clear(); + } + double dt = 0.5*scaleTimeStep*hsmin/celerity; // WHY 0.5 ?? + if(dt < dtmin ) dtmin = dt; + } + + // Delta t of contact +/* explicitHCDofManager<double>* dynass = dynamic_cast<explicitHCDofManager<double>*>(pAssembler); + // filter because one component is needed (same mass in all direction) + DgC0ShellFilterDofComponent filDof(0); + for(nonLinearMechSolver::contactContainer::iterator itc = _allContact.begin(); itc!=_allContact.end(); ++itc){ + contactDomain *cdom = *itc; + DgC0rigidContactSpace *csp = dynamic_cast<DgC0rigidContactSpace*>(spaceManager->get(cdom)); + double penalty = cdom->getPenalty(); + for(groupOfElements::elementContainer::iterator it = cdom->gSlave->begin(); it!=cdom->gSlave->end(); ++it){ + MElement *ele = *it; + // get mass +// int nbdofs = csp->getNumKeys(ele); + int nbvertex = ele->getNumVertices(); +// int nbdofsGC = csp->getNumKeysOfGravityCenter(); +// int nbcomp = (nbdofs-nbdofsGC)/nbvertex; + std::vector<Dof> R; + std::vector<double> vmass; + csp->getKeys(ele,R); + std::vector<Dof> Rfilter; + filDof.filter(R,Rfilter); + dynass->getVertexMass(Rfilter,vmass); + double Mmaster = vmass[nbvertex]; + for(int i=0; i<nbvertex; i++){ + double dt = 10000.*sqrt(0.5*Mmaster*vmass[i]/penalty/(Mmaster+vmass[i])); + if(dt < dtmin ){ + dtmin = dt; + Msg::Info("Dtc is fixed by contact"); + } + } + } + }*/ + return dtmin; +} + +void nonLinearMechSolver::setInitialCondition(){ + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + for(partDomain::initContainer::iterator it=dom->initCBegin(); it!=dom->initCEnd(); ++it){ + initialCondition *initC = *it; + SetInitialDofs(initC->_space,initC->g->begin(),initC->g->end(),initC->_value,initC->_wc,*pAssembler,*initC->_filter,dom->getFormulation()); + } + } + // Eventually read file with initial position +/* if(initOrResartfname != ""){ + // loop on all elements on all domain + FunctionSpaceBase *sp; // to create the dofs + std::vector<Dof> R; + std::vector<double> val; + for(std::vector<partDomain*>::iterator itdom = domainVector.begin(); itdom != domainVector.end(); ++itdom){ + partDomain *dom = *itdom; + sp = spaceManager->get(dom); + for(groupOfElements::elementContainer::iterator it = dom->g->begin(); it != dom->g->end(); ++it){ + MElement *ele = *it; + // create dof of element + sp->getKeys(ele,R); + + // clear + R.clear(); + } + + } + + }*/ +} + +void nonLinearMechSolver::solveExplicit(){ +#if defined(HAVE_PETSC) + Msg::Info("Explicit Data: endtime = %lf beta=%f gamma=%f alpha_m=%f",this->getEndTime(), this->_beta, this->_gamma, this->_alpham); + + //init + this->init(); + + // Creation of system + if(nonLinearMechSolver::whatSolver!= Petsc) + Msg::Warning("Explicit scheme uses Petsc only!"); + + explicitHulbertChung<double> *esys = new explicitHulbertChung<double>(_alpham,_beta,_gamma); + + // dof Manager + if(pAssembler) delete pAssembler; + pAssembler = new explicitHCDofManager<double>(esys); + + // time initialization + double curtime = 0.; + // Fix Dof + this->setTimeForBC(curtime); // otherwise BC which depend on time are put to t=1; and initial value are wrong + this->fixNodalDofs(); + this->numberDofs(esys); + + // System is allocated by numberDofs + // so now initial condition can be given to system + this->setInitialCondition(); + + // definition of ufield and ipfield + unknownField *ufield = new unknownDynamicField(pAssembler,domainVector,&_allContact,3,anoded,varcd); // 3 components by nodes User choice ?? + unknownDynamicField *dynufield = dynamic_cast<unknownDynamicField*>(ufield); + this->restart(ufield); // CHANGE THIS + IPField ipf(&domainVector,pAssembler,pModel,ufield,vaip); // Field for GaussPoint + energeticField efield(esys,&ipf,ufield,pAssembler,domainVector,_allaef); + ipf.compute1state(IPStateBase::initial); + ipf.initialBroken(pModel, initbrokeninter); + ipf.copy(IPStateBase::initial,IPStateBase::current); + this->initTerms(ufield,&ipf); + + // compute mass Matrix (outside loop) + for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){ + partDomain *dom = *it; + AssembleMass(dom->getBilinearMassTerm(),*(dom->getFunctionSpace()),dom->g->begin(),dom->g->end(), + *(dom->getBulkGaussIntegrationRule()),*pAssembler); + } + + for(nonLinearMechSolver::contactContainer::iterator itc = _allContact.begin(); itc!= _allContact.end(); ++itc){ + contactDomain *cdom = *itc; + if(cdom->isRigid()){ + rigidContactSpace *rcsp = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + AssembleMass(cdom->getMassTerm(),rcsp,pAssembler); + } + } + + // masse OK +// double mas = esys->getSystemMass(); + + // initial forces + this->computeRightHandSide(esys,pAssembler,ufield,&ipf); + esys->nextStep(); + long int step=0; + double timeStep; + + + while(curtime<endtime){ + + // compute time step and current time + if(step%numstep ==0 ){ + timeStep = _gammas * this->criticalExplicitTimeStep(ufield); + Msg::Info("time step value: %e",timeStep); + esys->setTimeStep(timeStep); + } + curtime+=timeStep; + if(curtime>endtime) curtime = endtime; + esys->systemSolve(); + + // new forces + // Update Boundary Conditions + this->setTimeForBC(curtime); + this->fixNodalDofs(); + dynufield->updateFixedDof(timeStep); + ipf.compute1state(IPStateBase::current); + // eval fracture +// ipf.evalFracture(IPState::current,curtime); + this->computeRightHandSide(esys,pAssembler,ufield,&ipf); + // Archiving + if((step+1)%nsba == 0){ + Msg::Info("Archiving view at time %e",curtime); + ufield->buildView(domainVector,curtime,step+1,"displacement",-1,false); + ufield->buildView(domainVector,curtime,step+1,"velocity",1,false); + ipf.buildView(domainVector,curtime,step+1,"VonMises",-1,false); + ipf.buildView(domainVector,curtime,step+1,"sigmaxx",0,false); + ipf.buildView(domainVector,curtime,step+1,"sigmayy",1,false); + ipf.buildView(domainVector,curtime,step+1,"tauxy",3,false); + ipf.buildView(domainVector,curtime,step+1,"VonMisesMax",4,false); + efield.buildView(domainVector,curtime,step+1,"total",-1,false); + } + ufield->archiving(curtime); + ipf.archive(curtime); + efield.archive(curtime); + // Edge force value; + FILE *fp; + for(std::map<int,double>::iterator it=aefvalue.begin(); it!=aefvalue.end(); ++it){ + std::ostringstream oss; + oss << (it->first)/10; + std::string s = oss.str(); + oss.str(""); + oss << (it->first)%10; + std::string s2 = oss.str(); + std::string fname = "force"+s+"comp"+s2+".csv"; + fp = fopen(fname.c_str(),"a"); + fprintf(fp,"%e;%e\n",curtime,it->second); + fclose(fp); + } + + + // next step + ipf.nextStep(curtime); + esys->nextStep(); + step++; + } + delete ufield; + Msg::Info("Explicit OK"); +#else + Msg::Error("Petsc is not available and so it is impossible to solve the problem. Please install PETsc correctly"); +#endif +} + + +// +// C++ Interface: terms Quasi Static +// +// Description: Files with definition of function : nonLinearMechSolver::solveSNL() +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +// Function to compute the initial norm +double nonLinearMechSolver::computeNorm0(linearSystem<double> *lsys, dofManager<double> *pAssembler, + unknownField *ufield, IPField *ipf){ + double normFext,normFint; + // Set all component of RightHandSide to zero (only RightHandSide is used to compute norm + lsys->zeroRightHandSide(); + + // fext norm + // compute ext forces + this->computeExternalForces(ipf,ufield); + + // Contact forces + this->computeContactForces(); + + // norm + normFext = lsys->normInfRightHandSide(); + + // Internal forces + lsys->zeroRightHandSide(); + // compute internal forces + this->computeInternalForces(ufield); + //norm + normFint = lsys->normInfRightHandSide(); + + // archive + return normFext+normFint; +} +// compute Fext-Fint +double nonLinearMechSolver::computeRightHandSide(linearSystem<double> *lsys, dofManager<double> *pAssembler, + unknownField *ufield, IPField *ipf){ + lsys->zeroRightHandSide(); + staticDofManager<double> *pA2 = dynamic_cast<staticDofManager<double>*>(pAssembler); + pA2->clearRHSfixed(); + this->computeInternalForces(ufield); + // save Fint component to archive ( write in file when Fint = Fext) + pA2->getForces(aef,aefvalue,_allaef); + // compute ext forces + this->computeExternalForces(ipf,ufield); + // compute contact forces + this->computeContactForces(); + return lsys->normInfRightHandSide(); +} + +void nonLinearMechSolver::computeInternalForces(unknownField *ufield){ + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end();++itdom) + { + partDomain *dom = *itdom; + dom->inverseLinearTermSign(); // Because rightHandSide = Fext - Fint + Assemble(dom->getLinearBulkTerm(),*(dom->getFunctionSpace()),dom->g->begin(),dom->g->end(), + *(dom->getBulkGaussIntegrationRule()),ufield,*pAssembler); + + if(dom->IsInterfaceTerms()){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + // Assembling loop on elementary interface terms + Assemble(dgdom->getLinearInterfaceTerm(),*(dgdom->getFunctionSpace()),dgdom->gi->begin(),dgdom->gi->end(),*(dgdom->getInterfaceGaussIntegrationRule()), + ufield,*pAssembler); // Use the same GaussQuadrature rule than on the boundary + // Assembling loop on elementary boundary interface terms + Assemble(dgdom->getLinearVirtualInterfaceTerm(),*(dgdom->getFunctionSpace()),dgdom->gib->begin(),dgdom->gib->end(), + *(dgdom->getInterfaceGaussIntegrationRule()),ufield,*pAssembler); // Use the same GaussQuadrature rule than on the boundary + } + dom->inverseLinearTermSign(); // Otherwise Fint has not the right sign + } +} + +void nonLinearMechSolver::computeContactForces(){ + for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain *cdom = *it; + Assemble(*(cdom->getForceTerm()),*(cdom->getSpace()),cdom->gSlave->begin(), + cdom->gSlave->end(),*(cdom->getGaussIntegration()),*pAssembler); + } +} + +void nonLinearMechSolver::computeStiffMatrix(const unknownField *ufield){ + + for(std::vector<partDomain*>::iterator itdom=domainVector.begin(); itdom!=domainVector.end(); ++itdom) + { + partDomain* dom = *itdom; + // Assembling loop on Elementary terms + Assemble(*(dom->getBilinearBulkTerm()),*(dom->getFunctionSpace()),dom->g->begin(),dom->g->end(), + *(dom->getBulkGaussIntegrationRule()),*pAssembler); + + if(dom->IsInterfaceTerms()){ + dgPartDomain *dgdom = dynamic_cast<dgPartDomain*>(dom); + // Assembling loop on elementary interface terms + Assemble(*(dgdom->getBilinearInterfaceTerm()),*(dom->getFunctionSpace()),dgdom->gi->begin(),dgdom->gi->end(), + *(dgdom->getInterfaceGaussIntegrationRule()),*pAssembler); + // Assembling loop on elementary boundary interface terms + Assemble(*(dgdom->getBilinearVirtualInterfaceTerm()),*(dom->getFunctionSpace()),dgdom->gib->begin(),dgdom->gib->end(), + *(dgdom->getInterfaceGaussIntegrationRule()),*pAssembler); + } + } + + // Contact + // little particular because it the term itself which know (via its linked linear term) the element + // where there is contact and so a bilinearterm != 0 as to be computed + for(contactContainer::iterator it = _allContact.begin(); it!=_allContact.end(); ++it){ + contactDomain *cdom = *it; + contactBilinearTermBase<double> *sterm = dynamic_cast<contactBilinearTermBase<double>*>(cdom->getStiffnessTerm()); + Assemble(*sterm,*(cdom->getSpace()),sterm->getContactNodes()->elemBegin(), + sterm->getContactNodes()->elemEnd(),*(cdom->getGaussIntegration()),*pAssembler); + sterm->clearContactNodes(); + } +} + +// Newton Raphson scheme to solve one step +void nonLinearMechSolver::NewtonRaphson(linearSystem<double> *lsys, dofManager<double> *pAssembler,unknownField *ufield, + IPField *ipf,const double Mtime){ + // compute ipvariable + ipf->compute1state(IPStateBase::current); + + // Compute the norm0 : norm(Fint) + norm(Fext) for relative convergence + double norm0 = this->computeNorm0(lsys,pAssembler,ufield,ipf); + + // Compute Right Hand Side (Fext-Fint) + double normFinf = this->computeRightHandSide(lsys,pAssembler,ufield,ipf); + + // loop until convergence + int iter=0; + double relnorm = normFinf/norm0; + printf("iteration n° %d : residu : %lf\n",iter,relnorm); + while(relnorm>_tol){ + iter++; + // Compute Stiffness Matrix + this->computeStiffMatrix(ufield); + + // Solve KDu = Fext-Fint + lsys->systemSolve(); + + // update displacement + ufield->update(); + + // update ipvariable + ipf->compute1state(IPStateBase::current); + + // new forces + normFinf = this->computeRightHandSide(lsys,pAssembler,ufield,ipf); + + // Check of convergence + relnorm = normFinf/norm0; + printf("iteration n° %d : residu : %lf\n",iter,relnorm); + lsys->zeroMatrix(); // here otherwise if it has been in computeMatrix the first iteration is very low HOW ?? + } +} + +// For now no initial displacement +void nonLinearMechSolver::solveSNL() +{ + Msg::Info("SNL Data : nstep =%d endtime=%f",this->getNumStep(),this->getEndTime()); + // init + this->init(); + // Select the solver for linear system Ax=b (KDeltau = Fext-Fint) + linearSystem<double> *lsys; + if(nonLinearMechSolver::whatSolver == Taucs){ + #if defined(HAVE_TAUCS) + lsys = new linearSystemCSRTaucs<double>; + Msg::Info("Taucs is chosen to solve\n"); + #else + lsys = new linearSystemGmm<double>; + lsys = dynamic_cast<linearSystemGmm<double>*>(lsys); + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + Msg::Error("Taucs is not installed\n Gmm is chosen to solve\n"); + #endif + } + else if(nonLinearMechSolver::whatSolver == Petsc){ + #if defined(HAVE_PETSC) + lsys = new linearSystemPETSc<double>; + Msg::Info("PETSc is chosen to solve\n"); + #else + lsys = new linearSystemGmm<double>; + lsys = dynamic_cast<linearSystemGmm<double>*>(lsys); + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + Msg::Error("PETSc is not installed\n Gmm is chosen to solve\n"); + #endif + } + else{ + lsys = new linearSystemGmm<double>; + dynamic_cast<linearSystemGmm<double>*>(lsys)->setNoisy(2); + Msg::Info("Gmm is chosen to solve\n"); + } + + // Creation of dof manager. The Dof where the displacement is prescribed are fixe to zero + // for initialization and numerotation of Dof (t=0 at initialization --> prescribed displacement =0) + + if (pAssembler) delete pAssembler; + pAssembler = new staticDofManager<double>(lsys); + + // we first do all fixations. the behavior of the dofManager is to + // give priority to fixations : when a dof is fixed, it cannot be + // numbered afterwards + + // ATTENTION The BC must be rewriten to take into account different fields (CG/DG and fullDG field for exemple) + // Fix dof to allow the dofManager to number the dofs + this->fixNodalDofs(); + this->numberDofs(lsys); + + // iterative scheme (loop on timestep) + double curtime = 0.; + double dt = double(endtime)/double(numstep); + unknownField *ufield = new unknownStaticField(pAssembler,domainVector,&_allContact,3,anoded,varcd); // 3 components by nodes User choice ?? + this->restart(ufield); // CHANGE THIS + IPField ipf(&domainVector,pAssembler,pModel,ufield,vaip); // Field for GaussPoint + energeticField enerfield(lsys,&ipf,ufield,pAssembler,domainVector,_allaef); + ipf.compute1state(IPStateBase::initial); + ipf.initialBroken(pModel, initbrokeninter); + ipf.copy(IPStateBase::initial,IPStateBase::previous); // if initial stress previous must be initialized before computation + this->initTerms(ufield,&ipf); + + for(int ii=0;ii<numstep;ii++){ + curtime+=dt; + printf("t= %lf on %lf\n",curtime,endtime); + + this->setTimeForBC(curtime); + + // Update prescribed Dof displacement + this->fixNodalDofs(); + ufield->updateFixedDof(); + + // Solve one step by NR scheme + NewtonRaphson(lsys,pAssembler,ufield,&ipf,curtime); + + if((ii+1)%nsba == 0){ + ufield->buildView(domainVector,curtime,ii+1,"displacement",-1,false); + ipf.buildView(domainVector,curtime,ii+1,"VonMises",-1,false); + ipf.buildView(domainVector,curtime,ii+1,"sigmaxx",0,false); + ipf.buildView(domainVector,curtime,ii+1,"sigmayy",1,false); + ipf.buildView(domainVector,curtime,ii+1,"tauxy",3,false); + enerfield.buildView(domainVector,curtime,ii+1,"total",-1,false); + } + + // Archiving + ufield->archiving(curtime); + ipf.archive(curtime); + enerfield.archive(curtime); + // Edge force value; + FILE *fp; + for(std::map<int,double>::iterator it=aefvalue.begin(); it!=aefvalue.end(); ++it){ + std::ostringstream oss; + oss << (it->first)/10; + std::string s = oss.str(); + oss.str(""); + oss << (it->first)%10; + std::string s2 = oss.str(); + std::string fname = "force"+s+"comp"+s2+".csv"; + fp = fopen(fname.c_str(),"a"); + fprintf(fp,"%lf;%lf\n",curtime,it->second); + fclose(fp); + } + + // next step for ipvariable + ipf.nextStep(curtime); + } + delete ufield; +} + diff --git a/NonLinearSolver/nlsolver/nonLinearMechSolver.h b/NonLinearSolver/nlsolver/nonLinearMechSolver.h new file mode 100644 index 0000000000..50f9b75e19 --- /dev/null +++ b/NonLinearSolver/nlsolver/nonLinearMechSolver.h @@ -0,0 +1,254 @@ +// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#ifndef _DGC0SHELL_SOLVER_H_ +#define _DGC0SHELL_SOLVER_H_ +#ifndef SWIG +#include <map> +#include <string> +#include "SVector3.h" +#include "dofManager.h" +#include "simpleFunction.h" +#include "functionSpace.h" +#include "MInterfaceElement.h" +#include "groupOfElements.h" +#include "partDomain.h" +#include "explicitHulbertChung.h" +#include "contactDomain.h" + + +class PView; +class groupOfElements; +class binding; +class unknownField; +class unknownDynamicField; +class IPField; +template<class T1,class T2> class DgC0BilinearTerm; +template<class T1> class DgC0LinearTerm; + +struct archiveForce{ + int numphys; + int dim; + int comp; + archiveForce() : numphys(0), dim(0), comp(0){} + archiveForce(const archiveForce &source){ + numphys = source.numphys; + dim = source.dim; + comp = source.comp; + } + archiveForce(int np, int d, int c) : numphys(np), dim(d), comp(c){} + ~archiveForce(){} +}; + +struct archiveRigidContactDisp{ + int _physmaster; + int _comp; + FilterDof *_fdof; + initialCondition::whichCondition _wc; + archiveRigidContactDisp() : _physmaster(0), _comp(0), _wc(initialCondition::position), _fdof(NULL){} + archiveRigidContactDisp(const int nphys, const int cmp, + initialCondition::whichCondition wc, partDomain *dom) : _physmaster(nphys), _comp(cmp), _wc(wc) + { + // change this HOW + _fdof = dom->createFilterDof(cmp); + } + archiveRigidContactDisp(const archiveRigidContactDisp &source){ + _physmaster = source._physmaster; + _comp = source._comp; + _wc = source._wc; + _fdof = source._fdof; + } + ~archiveRigidContactDisp(){} +}; + +struct archiveIPVariable{ + int numphys; // physical number of the node + int ipval; // num of the component to archive // must be defined for each ipvariable + archiveIPVariable() : numphys(0), ipval(0){} + archiveIPVariable(const archiveIPVariable &source){ + numphys = source.numphys; + ipval = source.ipval; + } + archiveIPVariable(const int numphys_, const int ipval_) : numphys(numphys_), ipval(ipval_){} + ~archiveIPVariable(){} +}; + +struct fextPrescribedDisp{ + Dof D; + double val; + fextPrescribedDisp(Dof D_) : D(D_), val(0.){} + fextPrescribedDisp(const fextPrescribedDisp &source) : D(source.D){ + val = source.val; + } +}; +#endif +class nonLinearMechSolver +{ + public: + typedef std::set<contactDomain*> contactContainer; + protected: + GModel *pModel; + int _dim, _tag; + dofManager<double> *pAssembler; +// dgGroupCollection _groups; + std::vector<partDomain*> domainVector; + contactContainer _allContact; + // contact + + // neumann BC + std::vector<nonLinearNeumannBC> allNeumann; + // dirichlet BC + std::vector<nonLinearDirichletBC> allDirichlet; + + // initial BC + std::vector<initialCondition> allinitial; + + // neumann BC theta (weak enforcement of rotation) regroup this with allNeumann + std::vector<nonLinearNeumannBC> allTheta; + + // dirichlet BC on rigid surface (prescribed the motion of gravity center) + std::vector<rigidContactBC> allContactBC; + + // set with virtual interfaceElements used to prescribed BC put this in an other place ?? + std::map<int,groupOfElements> mapvinter; + + // vector with material law + std::map<int,materialLaw*> maplaw; + // physical entities that are initialy broken + std::vector<int> initbrokeninter; + + // map to archive force + std::map<int,std::vector<Dof> > aef; + std::map<int,double> aefvalue; + std::vector<fextPrescribedDisp> _allaef; + // std vector to archive a node displacement + std::vector<std::pair<Dof,initialCondition::whichCondition> > anoded; + // std::vector to archive a force (info musy be store before creation because functionSpace are not initialize) + std::vector<archiveForce> vaf; + // std vector to archive ipvariable + std::vector<archiveIPVariable> vaip; + // std vector to archive rigid contact disp + std::vector<archiveRigidContactDisp> varcd; + + // specific data + int numstep; // Number of step not used for StaticLinearScheme and number of step between time step evaluation for Explicit Scheme + double endtime; // final time not used for StaticLinearScheme but it is not necesary to derive class because (small useless data) + double _tol; // relative tolerance for iteration not used for StaticLinearScheme but it is not necesary to derive class because (small useless data) + int nsba; // number of step between 2 archiving (=1 by default) + + // specific data for explicit scheme + double _beta, _gamma, _alpham, _gammas, _rhoinfty; + + // File name for restart or initial value + std::string initOrResartfname; + bool _restart; + + // Function to initiate the solver before solve + // (create interfaceElement and link the materialLaw and dgLinearShellDomain) +#ifndef SWIG + void init(); + void initTerms(unknownField *ufield, IPField *ipf); + + // Split Boundary Condition Between the different partDomain + void splitBoundaryConditions(); + + // Function used by non linear solver + void NewtonRaphson(linearSystem<double> *lsys, dofManager<double> *pAssembler, unknownField *ufield, + IPField *ipf,const double time); + + double computeNorm0(linearSystem<double> *lsys, dofManager<double> *pAssembler, unknownField *ufield, + IPField *ipf); + + double computeRightHandSide(linearSystem<double> *lsys, dofManager<double> *pAssembler, unknownField *ufield, + IPField *ipf); + + void computeStiffMatrix(const unknownField *ufield); + void computeExternalForces(IPField *ipf, const unknownField *ufield); + void computeContactForces(); + void computeInternalForces(unknownField *ufield); + void fixNodalDofs(); + void numberDofs(linearSystem<double> *lsys); + void insertTheta(const int numphys, groupOfElements *goe); + double criticalExplicitTimeStep(unknownField *ufield); + void setInitialCondition(); + void setTimeForBC(double time); + void initArchiveForce(); + void initContactInteraction(); +#endif + public : //protected with lua ?? + enum solver{ Gmm=0,Taucs=1,Petsc=2}; + enum scheme{StaticLinear=0, StaticNonLinear=1, Explicit=2}; + solver whatSolver; // Solver used to solve + scheme whatScheme; // scheme used to solve equation + public: + nonLinearMechSolver(int tag) : _tag(tag), pAssembler(0), numstep(1), endtime(1.), _tol(1.e-6), nsba(1), + whatSolver(nonLinearMechSolver::Gmm), whatScheme(nonLinearMechSolver::StaticLinear), + _beta(0.), _gamma(0.5), _alpham(0.), _rhoinfty(1.), initOrResartfname(""), _restart(false) + {} // default Gmm and static linear scheme + + virtual ~nonLinearMechSolver() + { + if (pAssembler) delete pAssembler; +// for(std::map<int,materialLaw*>::iterator it = maplaw.begin(); it!=maplaw.end();++it){ delete it->second;} + // I can't delete or problem at the end since swig. +// for(std::vector<partDomain*>::iterator it = domainVector.begin(); it!=domainVector.end(); ++it){delete *it;} + } +#ifndef SWIG + int getStepBetweenArchiving() const{return nsba;} + int getNumStep() const{return numstep;} + double getEndTime() const{return endtime;} + scheme getScheme() const{return whatScheme;} + virtual void solveStaticLinar(); + virtual void solveSNL(); + virtual void solveExplicit(); + virtual void createInterfaceElement(); + virtual materialLaw* getMaterialLaw(const int num); + // create interfaceelement with dgGoupOfElement from dg project doesn't work (segmentation fault) + virtual void createInterfaceElement_2(); +#endif + // functions for lua interaction + void loadModel(const std::string meshFileName); + virtual void solve(); +// virtual void addDgLinearElasticShellDomain(dgLinearShellDomain* dom); +// virtual void addInterShellDomain(interDomainBetweenShell *dom); + virtual void addDomain(partDomain *dom); +// virtual void addDomain(dgLinearShellDomain* dom); + virtual void addMaterialLaw(materialLaw *mlaw); +// virtual void addLinearElasticShellLaw(linearElasticShellLaw *mlaw); +// virtual void addShellLinearCohesiveLaw(shellLinearCohesiveLaw *mlaw); +// virtual void addLinearElasticOrthotropicShellLaw(linearElasticOrthotropicShellLaw *mlaw); +// virtual void addshellFractureByCohesiveLaw(shellFractureByCohesiveLaw *mlaw); + void Solver(const int s){whatSolver= (solver)s;} + void Scheme(const int s){whatScheme=(scheme)s;} + void snlData(const int ns, const double et, const double reltol); + void explicitData(const double ftime, const double gams=0.666667, const double beta=0, const double gamma=0.5, const double alpham=0.); + void explicitSpectralRadius(const double ftime,const double gams=0.666667,const double rho=1.); + void explicitTimeStepEvaluation(const int nst); + void stepBetweenArchiving(const int n){nsba = n;} + virtual void thetaBC(const int numphys); + virtual void displacementBC(std::string onwhat, const int numphys, const int comp, const double value); + virtual void displacementRigidContactBC(const int numphys, const int comp,const double value); + virtual void initialBC(std::string onwhat, std::string whichC, const int numphys, const int comp, const double value); + virtual void forceBC(std::string onwhat, const int numphys, const int comp, const double val); + virtual void independentDisplacementBC(std::string onwhat, const int numphys, const int comp, const double value); + virtual void independentForceBC(std::string onwhat, const int numphys, const int comp, const double val); + virtual void blastPressureBC(const int numphys,const double p0,const double p1, const double plexp, const double t0, const double t1); + virtual void pressureOnPhysicalGroupBC(const int numphys, const double press, const double p0); + virtual void archivingForceOnPhysicalGroup(const std::string onwhat, const int numphys, const int comp); + virtual void archivingNodeDisplacement(const int num, const int comp); + virtual void archivingNodeVelocity(const int num, const int comp); + virtual void archivingNodeAcceleration(const int num, const int comp); + virtual void archivingNode(const int num, const int comp, initialCondition::whichCondition); + virtual void archivingNodeIP(const int numphys, const int ipval); + virtual void physInitBroken(const int phys); + virtual void setInitOrRestartFileName(const std::string fname); + virtual void restart(unknownField *ufield); + virtual void contactInteraction(contactDomain *cdom); + virtual void archivingRigidContact(const int numphys, const int comp, const int wc=0); +}; + + +#endif // nonLinearMechSolver + diff --git a/NonLinearSolver/nlsolver/staticDofManager.h b/NonLinearSolver/nlsolver/staticDofManager.h new file mode 100644 index 0000000000..99950b79f0 --- /dev/null +++ b/NonLinearSolver/nlsolver/staticDofManager.h @@ -0,0 +1,157 @@ +// +// C++ Interface: terms +// +// Description: dofManager for non linear system (rewritte of assemble(fullMatrix) no contribution for fixed Dof +// The contribution is taken into account in the assemble(fullvector) of RightHandSide +// More add functions to archiving force can be placed in dofManager but I put it here to not pollute gmsh code +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef _STATICDOFMANAGER_H_ +#define _STATICDOFMANAGER_H_ + +#include "dofManager.h" +#include "nonLinearMechSolver.h" +template<class T> +class staticDofManager : public dofManager<T>{ + protected : + // map to retains the force of fixed dof (needed for archiving) the other RHS value are accessible in RHS + std::map<Dof, typename dofManager<T>::dataVec> RHSfixed; + + public : + + staticDofManager(linearSystem< typename dofManager<T>::dataMat > *l) : dofManager<T>(l){ +// for(int i=0;i<varchdof.size();i++) +// RHSfixed[varchdof[i]] = value; + +} + staticDofManager(linearSystem< typename dofManager<T>::dataMat > *l1, linearSystem<typename dofManager<T>::dataMat> *l2) : dofManager<T>(l1,l2){ +// for(int i=0;i<varchdof.size();i++) +// RHSfixed[varchdof[i]] = value; +} + + // this function is replaced to avoid a double contribution in right hand side for fixed dof + virtual inline void assemble(std::vector<Dof> &R, const fullMatrix<typename dofManager<T>::dataMat> &m) + { + if (!this->_current->isAllocated()) this->_current->allocate(this->unknown.size()); + std::vector<int> NR(R.size()); + for (unsigned int i = 0; i < R.size(); i++) + { + std::map<Dof, int>::iterator itR = this->unknown.find(R[i]); + if (itR != this->unknown.end()) NR[i] = itR->second; + else NR[i] = -1; + } + for (unsigned int i = 0; i < R.size(); i++) + { + if (NR[i] != -1) + { + for (unsigned int j = 0; j < R.size(); j++) + { + if (NR[j] != -1) + { + this->_current->addToMatrix(NR[i], NR[j], m(i, j)); + } + else + { + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator itFixed = this->fixed.find(R[j]); + if (itFixed == this->fixed.end()) + assembleLinConst(R[i],R[j],m(i,j)); + } + } + } + else + { + for (unsigned int j = 0; j < R.size(); j++){ + assembleLinConst(R[i],R[j],m(i,j)); + } + } + } + } + + // + // Function to fix dof (Create the key in RHS fixed too) + inline void fixDof(Dof key, const typename dofManager<T>::dataVec &value){ + if(this->unknown.find(key) != this->unknown.end()) + return; + this->fixed[key] = value; + this->RHSfixed[key]=0.; + } + + // function assemble(vect) is rewritten to archiving rhs if needed + virtual inline void assemble(std::vector<Dof> &R, const fullVector<typename dofManager<T>::dataMat> &m) // for linear forms + { + if (!this->_current->isAllocated()) this->_current->allocate(this->unknown.size()); + std::vector<int> NR(R.size()); + // Archiving + for (unsigned int i = 0; i < R.size(); i++) + { + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator itR = RHSfixed.find(R[i]); + if (itR != RHSfixed.end()) itR->second += m(i); // add of contribution set to zero when the value is by a function FIX it + else NR[i] = -1; + } + + for (unsigned int i = 0; i < R.size(); i++) + { + std::map<Dof, int>::iterator itR = this->unknown.find(R[i]); + if (itR != this->unknown.end()) NR[i] = itR->second; + else NR[i] = -1; + } + for (unsigned int i = 0; i < R.size(); i++) + { + if (NR[i] != -1) + { + this->_current->addToRightHandSide(NR[i], m(i)); + } + else + { + typename std::map<Dof,DofAffineConstraint<typename dofManager<T>::dataVec> >::iterator itConstraint; + itConstraint = this->constraints.find(R[i]); + if (itConstraint != this->constraints.end()) + { + for (unsigned i=0;i<(itConstraint->second).linear.size();i++) + { + std::map<Dof, int>::iterator itC = this->unknown.find((itConstraint->second).linear[i].first); // lin dep in unknown ?! + this->_current->addToRightHandSide(itC->second, m(i)*(itConstraint->second).linear[i].second); + } + } + } + } + } + // zero for RHSfixed + void clearRHSfixed(){ + for(typename std::map<Dof,typename dofManager<T>::dataVec>::iterator itR = RHSfixed.begin();itR != RHSfixed.end(); ++itR) + itR->second = 0.; + } + + void getForces(std::map<int,std::vector<Dof> > &aef, std::map<int,typename dofManager<T>::dataVec> &data, + std::vector<fextPrescribedDisp> &allaef){ + for(std::map<int,std::vector<Dof> >::iterator it = aef.begin(); it != aef.end(); ++it){ + double Fint =0.; + for(int i=0;i<it->second.size();i++){ + // look in RHSfixed + typename std::map<Dof, typename dofManager<T>::dataVec>::iterator itRHS = RHSfixed.find(it->second[i]); + if(itRHS != RHSfixed.end()) + Fint -= itRHS->second; // as internal forces are computed with a minus sign in computeRightHandSide; + else{ + typename std::map<Dof,int>::iterator itunk = this->unknown.find(it->second[i]); + if(itunk != this->unknown.end()){ + double ff; + this->_current->getFromRightHandSide(itunk->second,ff); + Fint -= ff; + } + } + } + data[it->first] = Fint; + + } + // needed to compute work of external force external => fixed ?? + for(int i=0; i<allaef.size(); i++){ + allaef[i].val = - RHSfixed[allaef[i].D]; + } + } +}; + +#endif // STATICDOFMANAGERSYSTEM_H_ + diff --git a/NonLinearSolver/nlsolver/timeFunction.h b/NonLinearSolver/nlsolver/timeFunction.h new file mode 100644 index 0000000000..c2d94dabfb --- /dev/null +++ b/NonLinearSolver/nlsolver/timeFunction.h @@ -0,0 +1,83 @@ +// +// C++ Interface: terms +// +// Description: Derivate class of SimpleFunction to include a time dependency +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef TIMEFUNCTION_H_ +#define TIMEFUNCTION_H_ +#include "simpleFunction.h" +template<class scalar> +class simpleFunctionTime : public simpleFunction<scalar>{ + protected : + double time; + bool timeDependency; + public : + simpleFunctionTime(scalar val=0, bool td=true, double t=1.) : simpleFunction<scalar>(val), time(t), timeDependency(td){}; // time=1 by default to avoid set time for Static linear Scheme + ~simpleFunctionTime(){}; +#ifndef SWIG + virtual scalar operator () (double x, double y, double z) const { if(timeDependency) return time*this->_val; else return this->_val;} + void setTime(const double t){time=t;} + void scaleVal(const double fac){this->_val*=fac;} +#endif +}; +#ifndef SWIG +template<class scalar> +class simpleFunctionTimeWithConstant : public simpleFunctionTime<scalar>{ + protected: + scalar _b; + public: + simpleFunctionTimeWithConstant(scalar val=0, bool td=true, double t=1.,scalar b=0.) : simpleFunctionTime<scalar>(val,td,t), _b(b){}; + ~simpleFunctionTimeWithConstant(){}; + virtual scalar operator () (double x, double y, double z) const { if(this->timeDependency) return this->time*this->_val+_b; else return this->_val;} + +}; +#endif +class powerDecreasingFunctionTime : public simpleFunctionTime<double>{ + protected: +// _val = p0 const double p0; // minimal pressure + const double _p1; // maximal pressure + const double _a; // power exponent + const double _t0; // if t < t0 p = p0 + const double _t1; // if t0 < t < t1 p = p0 + (p1-p0)*(t-t0)/(t1-t0) + const double _tf; // if t1 < t < tf p = (p1-p0)*(tf-t1)^-a*(tf-t)^a + p0 + public: + powerDecreasingFunctionTime(double p0, const double p1, const double a, const double t0, + const double t1, const double tf) : simpleFunctionTime<double>(p0,true,1.), + _p1(p1), _a(a), _t0(t0), _t1(t1), _tf(tf){} + ~powerDecreasingFunctionTime(){} + virtual double operator () (double x, double y, double z) const{ + double p0 = _val; + if((_t0<time) and(time<_t1)) + return p0 + (_p1-p0)*(time-_t0)/(_t1-_t0); + else if ((_t1<time) and (time<_tf)) + return (_p1-p0)*pow(_tf-_t1,-_a)*pow(_tf-time,_a)+p0; + else + return p0; + } +// void setTime(const double t){time=t;} +/* static void registerBindings(binding *b){ + classBinding *cb = b->addClass<powerDecreasingFunctionTime>("powerDecreasingTime"); + cb->setDescription("Function power decreasing in time. Three parts: First one t<t0 value=cste=p0 , Second part t0<t<t1 value= (p1-p0)*(t-t0)/(t1-t0)+p0 Third part value = (p1-p0)*(tf-t1)^-a*(tf-t)^a+p0"); + methodBinding *cm; + cm = cb->setConstructor<powerDecreasingFunctionTime,double,double,double,double,double,double>(); + cm->setArgNames("p0","p1","a","t0","t1","tf",NULL); + cm->setDescription("power decresing law. See class description to see how it has to be used"); + + // use to validate +// cm = cb->addMethod("setTime", &powerDecreasingFunctionTime::setTime); +// cm->setArgNames("t",NULL); +// cm->setDescription("set time t"); +// cm = cb->addMethod("get", &powerDecreasingFunctionTime::operator()); +// cm->setArgNames("x","y","z",NULL); +// cm->setDescription("get value"); + } +*/ +}; +#endif // TIMEFUNCTION + diff --git a/NonLinearSolver/nlsolver/unknownDynamicField.cpp b/NonLinearSolver/nlsolver/unknownDynamicField.cpp new file mode 100644 index 0000000000..38fe57ceb3 --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownDynamicField.cpp @@ -0,0 +1,179 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field for a dynamic system +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// + +#include "unknownDynamicField.h" +#include "nlsolAlgorithms.h" +unknownDynamicField::unknownDynamicField(dofManager<double> *pas, std::vector<partDomain*> &vdom, + nonLinearMechSolver::contactContainer *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool view_, const std::string filen) : unknownField(pas,vdom,acontact,nc,archiving,contactarch,view_,filen) +{ + // to avoid constant dynamic cast + dynassembler = dynamic_cast<explicitHCDofManager<double>*>(pAssembler); +} + +void unknownDynamicField::update(){ + Msg::Warning("The update of displacement field is unnecessary for a dynamic scheme"); +} + +void unknownDynamicField::get(Dof &D,double &udof) const { + this->get(D,udof,initialCondition::position); +} +void unknownDynamicField::get(Dof &D, double &udof, initialCondition::whichCondition wv) const { + dynassembler->getDofValue(D,udof,wv); +} + +void unknownDynamicField::get(std::vector<Dof> &R, std::vector<double> &udofs) const { + this->get(R,udofs,initialCondition::position); +} + +void unknownDynamicField::get(std::vector<Dof> &R, fullVector<double> &udofs) const { + this->get(R,udofs,initialCondition::position); +} + +void unknownDynamicField::get(std::vector<Dof> &R, std::vector<double> &udofs, initialCondition::whichCondition wv) const { + double du; + for(int i=0;i<R.size(); i++){ + this->get(R[i],du,wv); + udofs.push_back(du); + } +} +void unknownDynamicField::get(std::vector<Dof> &R, fullVector<double> &udofs, initialCondition::whichCondition wv) const { + double du; + for(int i=0;i<R.size(); i++){ + this->get(R[i],du,wv); + udofs(i) = du; + } +} + +void unknownDynamicField::get(partDomain *dom,MElement *ele, std::vector<double> &udofs, const int cc){ + // -1 or 0 = position + // 1 = velocity + // 2 = acceleration + initialCondition::whichCondition wv; + if (cc==1) + wv= initialCondition::velocity; + else if(cc==2) + wv= initialCondition::acceleration; + else + wv= initialCondition::position; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + sp->getKeys(ele,R); + this->get(R,udofs,wv); +} + +void unknownDynamicField::get(partDomain *dom,MElement *ele, fullVector<double> &udofs, const int cc){ + // -1 or 0 = position + // 1 = velocity + // 2 = acceleration + initialCondition::whichCondition wv; + if (cc==1) + wv= initialCondition::velocity; + else if(cc==2) + wv= initialCondition::acceleration; + else + wv= initialCondition::position; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + sp->getKeys(ele,R); + udofs.resize(sp->getNumKeys(ele)); + this->get(R,udofs,wv); +} + +void unknownDynamicField::get(partDomain *dom,MInterfaceElement *iele, std::vector<double> &udofs){ + this->get(dom,iele,udofs,initialCondition::position); +} + +void unknownDynamicField::get(partDomain *dom,MInterfaceElement *iele, std::vector<double> &udofs, initialCondition::whichCondition wv){ + this->get(dom,iele->getElem(0),udofs,wv); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + this->get(dom,iele->getElem(1),udofs,wv); + } +} + +void unknownDynamicField::get(partDomain *dom1, partDomain *dom2, + MInterfaceElement *iele, std::vector<double> &udofs){ + this->get(dom1,dom2,iele,udofs,initialCondition::position); +} + +void unknownDynamicField::get(FunctionSpaceBase*sp1, FunctionSpaceBase *sp2, + MInterfaceElement *iele, std::vector<double> &udofs){ + this->get(sp1,sp2,iele,udofs,initialCondition::position); +} + +void unknownDynamicField::get(partDomain *dom1, partDomain *dom2, + MInterfaceElement *iele, std::vector<double> &udofs, initialCondition::whichCondition wv){ + this->get(dom1,iele->getElem(0),udofs,wv); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + this->get(dom2,iele->getElem(1),udofs,wv); + } +} + +void unknownDynamicField::get(FunctionSpaceBase *sp1, FunctionSpaceBase *sp2, + MInterfaceElement *iele, std::vector<double> &udofs, initialCondition::whichCondition wv){ + std::vector<Dof> R; + sp1->getKeys(iele->getElem(0),R); + this->get(R,udofs,wv); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + R.clear(); + sp2->getKeys(iele->getElem(1),R); + this->get(R,udofs,wv); + } +} + +void unknownDynamicField::updateFixedDof(){ + Msg::Warning("Impossible to update the fixed dof because the time step is not passed in argument"); +} + +void unknownDynamicField::updateFixedDof(const double timeStep){ + dynassembler->updateFixedDof(timeStep); +} + +void unknownDynamicField::archiving(const double time){ + FILE *fp; + double u; + for(std::vector<archiveNode>::iterator it = varch.begin(); it!=varch.end();++it){ + Dof D = it->D; + dynassembler->getDofValue(D,u,it->wc); + // write in File + std::ostringstream oss; + oss << it->nodenum; + std::string s = oss.str(); + // component of displacement + int field,comp,num; + Dof3IntType::getThreeIntsFromType(it->D.getType(),comp,field,num); + oss.str(""); + oss << comp; + std::string s2 = oss.str(); + std::string fname; + switch(it->wc){ + case initialCondition::position: + fname = "NodalDisplacement"+s+"comp"+s2+".csv"; + break; + case initialCondition::velocity: + fname = "NodalVelocity"+s+"comp"+s2+".csv"; + break; + case initialCondition::acceleration: + fname = "NodalAcceleration"+s+"comp"+s2+".csv"; + break; + } + fp = fopen(fname.c_str(),"a"); + fprintf(fp,"%e;%e\n",time,u); + fclose(fp); + } +} + +void unknownDynamicField::setInitial(const std::vector<Dof> &R, const std::vector<double> &disp){ + for(int i=0;i<R.size();i++){ + dynassembler->setInitialCondition(R[i],disp[i],initialCondition::position); + } +} diff --git a/NonLinearSolver/nlsolver/unknownDynamicField.h b/NonLinearSolver/nlsolver/unknownDynamicField.h new file mode 100644 index 0000000000..e42eae29a7 --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownDynamicField.h @@ -0,0 +1,51 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field for a dynamic system +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +#ifndef UNKNOWNDYNAMICFIELD_H_ +#define UNKNOWNDYNAMICFIELD_H_ +#include "unknownField.h" +#include "explicitDofManager.h" +#include "explicitHulbertChung.h" + +class unknownDynamicField : public unknownField{ + protected: + explicitHCDofManager<double> *dynassembler; + + public: + unknownDynamicField(dofManager<double> *pas, std::vector<partDomain*> &vdom, + nonLinearMechSolver::contactContainer *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool view_=true, const std::string filen="disp.msh"); + + virtual void update(); + virtual void get(Dof &D, double &udof) const; + virtual void get(Dof &D, double &udof, initialCondition::whichCondition wv) const ; + virtual void get(std::vector<Dof> &R, std::vector<double> &disp) const; + virtual void get(std::vector<Dof> &R, fullVector<double> &disp) const; + virtual void get(std::vector<Dof> &R, std::vector<double> &disp,initialCondition::whichCondition wv) const ; + virtual void get(std::vector<Dof> &R, fullVector<double> &disp,initialCondition::whichCondition wv) const ; + virtual void get(partDomain *dom,MElement *ele, std::vector<double> &udofs, const int cc= -1); + virtual void get(partDomain *dom,MElement *ele, fullVector<double> &udofs, const int cc= -1); + virtual void get(partDomain *dom, MInterfaceElement *iele, std::vector<double> &udofs); + + virtual void get(partDomain *dom, MInterfaceElement *iele, std::vector<double> &udofs, initialCondition::whichCondition); + virtual void get(partDomain *dom1, partDomain *dom2, MInterfaceElement *iele, std::vector<double> &udofs) ; + virtual void get(FunctionSpaceBase *sp1, FunctionSpaceBase *sp2, MInterfaceElement *iele, std::vector<double> &udofs) ; + virtual void get(partDomain *dom1, partDomain *dom2, MInterfaceElement *iele, std::vector<double> &udofs, + initialCondition::whichCondition wv= initialCondition::position) ; + virtual void get(FunctionSpaceBase *sp1, FunctionSpaceBase *sp2, MInterfaceElement *iele, std::vector<double> &udofs, + initialCondition::whichCondition wv= initialCondition::position) ; + virtual void updateFixedDof(); + virtual void updateFixedDof(const double timeStep); + virtual void archiving(const double time); + virtual void setInitial(const std::vector<Dof> &R, const std::vector<double> &disp); +}; +#endif // UNKNOWNDYNAMICFIELD_H_ + diff --git a/NonLinearSolver/nlsolver/unknownField.cpp b/NonLinearSolver/nlsolver/unknownField.cpp new file mode 100644 index 0000000000..a08cb504e2 --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownField.cpp @@ -0,0 +1,106 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "unknownField.h" +#include "nonLinearMechSolver.h" +#include "nlsolAlgorithms.h" +#include "MPoint.h" +// constructor + +unknownField::unknownField(dofManager<double> *pas, std::vector<partDomain*> &vdom, nonLinearMechSolver::contactContainer *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool view_, const std::string filen): pAssembler(pas), + domainVector(&vdom), + _allContact(acontact), + elementField(filen,100000000,nc,elementField::ElementNodeData,view_) +{ + + + pAssembler->getFixedDof(fixedDof); + std::vector<bool> alfind; + for(int i=0;i<archiving.size(); i++) + alfind.push_back(false); + long int totelem=0; + for(std::vector<partDomain*>::iterator itdom=vdom.begin(); itdom!=vdom.end(); ++itdom){ + partDomain *dom = *itdom; + bool fullDg = dom->getFormulation(); + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + totelem += dom->g->size(); + if(!fullDg){ + for(groupOfElements::vertexContainer::iterator it=dom->g->vbegin(); it!=dom->g->vend(); ++it){ + MVertex *ver = *it; + MPoint ele = MPoint(ver,-1); // We don't care about element number it is just to have the vertex keys; + sp->getKeys(&ele,R); + // make dof for archiving node + for(int i=0;i<archiving.size();i++){ + if( (alfind[i] == false) and (ver->getNum() == archiving[i].first.getEntity())){ + // get the comp of the archiving node + int comp,field,num; + Dof3IntType::getThreeIntsFromType(archiving[i].first.getType(),comp,field,num); + FilterDof* filter = dom->createFilterDof(comp); + for(int j=0;j<R.size();j++){ + if(filter->operator()(R[j])){ + alfind[i] = true; + varch.push_back(archiveNode(R[j],ver->getNum(),archiving[i].second)); + } + } + } + } + R.clear(); + } + } + else{ + // loop on element (entity of formulation) + for(groupOfElements::elementContainer::iterator it=dom->g->begin(); it!=dom->g->end(); ++it){ + MElement *ele = *it; + sp->getKeys(ele,R); + // loop on vertex element (for archiving node) + int nbvertex = ele->getNumVertices(); + for(int j=0;j<nbvertex;j++){ + MVertex *ver = ele->getVertex(j); + for(int i=0; i<archiving.size(); i++){ + if((alfind[i] == false) and(ver->getNum() == archiving[i].first.getEntity())){ + // get the comp of the archiving node + int comp,field,num; + Dof3IntType::getThreeIntsFromType(archiving[i].first.getType(),comp,field,num); + alfind[i] = true; + varch.push_back(archiveNode(R[j+comp*nbvertex],ver->getNum(),archiving[i].second)); + break; + } + } + } + R.clear(); + } + } + } + // increment the total element with rigid contact and add archiving if necessary + + for(nonLinearMechSolver::contactContainer::iterator it = _allContact->begin(); it!=_allContact->end(); ++it){ + contactDomain *cdom = *it; + if(cdom->isRigid()){ + totelem += cdom->gMaster->size(); + int pMaster = cdom->getTag(); + for(int i=0;i<contactarch.size(); i++){ + if(contactarch[i]._physmaster == pMaster){ + rigidContactSpace *sp = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + std::vector<Dof> R; + sp->getKeysOfGravityCenter(R); + for(int j=0;j<R.size(); j++) + if(contactarch[i]._fdof->operator()(R[j])) + varch.push_back(archiveNode(R[j],pMaster,contactarch[i]._wc)); + } + } + } + } + this->setTotElem(totelem); +} diff --git a/NonLinearSolver/nlsolver/unknownField.h b/NonLinearSolver/nlsolver/unknownField.h new file mode 100644 index 0000000000..93c510554d --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownField.h @@ -0,0 +1,64 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef UNKNOWNFIELD_H_ +#define UNKNOWNFIELD_H_ +#include "dofManager.h" +#include "PView.h" +#include "PViewData.h" +#include <stdint.h> +#include <stdlib.h> +#include "elementField.h" +#include "nonLinearBC.h" +#include "MInterfaceElement.h" +class contactDomain; +class elementField; +struct archiveRigidContactDisp; +struct archiveNode{ + long int nodenum; + Dof D; + initialCondition::whichCondition wc; + archiveNode(Dof R, int n, initialCondition::whichCondition wv=initialCondition::position) : nodenum(n), D(R), wc(wv){} + ~archiveNode(){}; + +}; + +class unknownField : public elementField{ + protected: + dofManager<double> *pAssembler; // To access to component of equation system template this + std::vector<Dof> fixedDof; + std::vector<archiveNode> varch; + std::vector<partDomain*> *domainVector; + std::set<contactDomain*> *_allContact; + public: + // update all displacement value + unknownField(dofManager<double> *pas, std::vector<partDomain*> &elas, std::set<contactDomain*> *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool =true, const std::string="disp.msh"); + ~unknownField(){} + virtual void update()=0; + virtual void updateFixedDof()=0; + // get Operation + virtual void get(Dof &D,double &udof) const=0; + virtual void get(std::vector<Dof> &R, std::vector<double> &disp) const=0; + virtual void get(std::vector<Dof> &R, fullVector<double> &disp) const=0; + virtual void get(partDomain *dom, MElement *ele,std::vector<double> &udofs, const int=-1)=0; + virtual void get(partDomain *dom, MElement *ele,fullVector<double> &udofs, const int=-1)=0; + virtual void get(partDomain *dom, MInterfaceElement* iele, std::vector<double> &udofs)=0; + virtual void get(partDomain *dom1, partDomain*dom2, MInterfaceElement* iele, std::vector<double> &udofs)=0; + virtual void get(FunctionSpaceBase *sp1,FunctionSpaceBase *sp2, MInterfaceElement *iele,std::vector<double> &udofs)=0; + virtual void archiving(const double time)=0; + virtual void setInitial(const std::vector<Dof> &R,const std::vector<double> &disp)=0; +// virtual void buildView(std::vector<partDomain*> &vdom,const double time, +// const int nstep, const std::string &valuename, const int cc,const bool binary); +}; +#endif // _UNKNOWNFIELD_H_ diff --git a/NonLinearSolver/nlsolver/unknownStaticField.cpp b/NonLinearSolver/nlsolver/unknownStaticField.cpp new file mode 100644 index 0000000000..934d5c95eb --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownStaticField.cpp @@ -0,0 +1,298 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "unknownStaticField.h" +#include "nonLinearMechSolver.h" +#include "MPoint.h" +unknownStaticField::unknownStaticField(dofManager<double> *pas, std::vector<partDomain*> &vdom, nonLinearMechSolver::contactContainer *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool view_, const std::string filen + ) : unknownField(pas,vdom,acontact,nc,archiving,contactarch,view_,filen) +{ + // build umap + for(std::vector<partDomain*>::iterator itdom=vdom.begin(); itdom!=vdom.end(); ++itdom){ + partDomain *dom = *itdom; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + for(groupOfElements::elementContainer::iterator it=dom->g->begin(); it!=dom->g->end(); ++it){ + MElement *ele = *it; + sp->getKeys(ele,R); + for(int i=0;i<R.size(); i++) + umap.insert(std::pair<Dof,double>(R[i],0.)); + R.clear(); + } + } + + // insert rigid contact Dof in umap + for(nonLinearMechSolver::contactContainer::iterator it = acontact->begin(); it!=acontact->end(); ++it){ + contactDomain *cdom = *it; + if(cdom->isRigid()){ + std::vector<Dof> R; + rigidContactSpace *sp = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + sp->getKeysOfGravityCenter(R); + for(int i=0;i<R.size(); i++) + umap.insert(std::pair<Dof,double>(R[i],0.)); + } + } + + this->buildView(vdom,0.,0,"displacement",-1,false); +} + +void unknownStaticField::update(){ + double du; + for(std::vector<partDomain*>::iterator itdom = domainVector->begin(); itdom!=domainVector->end(); ++itdom){ + partDomain *dom = *itdom; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + std::vector<Dof> R; + if(!(dom->getFormulation())){ + for(groupOfElements::vertexContainer::iterator it=dom->g->vbegin(); it!=dom->g->vend(); ++it){ + MVertex *ver = *it; + MPoint ele = MPoint(ver,-1); // We don't care about element number it's just to have the vertex keys + sp->getKeys(&ele,R); + for(int i=0;i<R.size();i++){ + pAssembler->getDofValue(R[i],du); + bool in=false; + for(std::vector<Dof>::iterator itD=fixedDof.begin(); itD<fixedDof.end();++itD) + if(*itD==R[i]){in=true;break;} + if(in) umap[R[i]] = du; + else umap[R[i]] +=du; + } + R.clear(); + } + } + else{ + + for(groupOfElements::elementContainer::iterator it=dom->g->begin(); it!=dom->g->end(); ++it){ + MElement *ele = *it; + sp->getKeys(ele,R); + for(int i=0;i<R.size();i++){ + pAssembler->getDofValue(R[i],du); + bool in=false; + for(std::vector<Dof>::iterator itD=fixedDof.begin(); itD<fixedDof.end();++itD) + if(*itD==R[i]){in=true;break;} + if(in) umap[R[i]] = du; + else umap[R[i]] +=du; + } + R.clear(); + } + } + } +} + + +void unknownStaticField::get(Dof &D,double &udof) const{ + udof = umap.find(D)->second; +} + +void unknownStaticField::get(std::vector<Dof> &R, std::vector<double> &disp) const{ + double du; + for(int i=0;i<R.size(); i++){ + this->get(R[i],du); + disp.push_back(du); + } +} + +void unknownStaticField::get(std::vector<Dof> &R, fullVector<double> &disp) const{ + double du; + for(int i=0;i<R.size(); i++){ + this->get(R[i],du); + disp(i) = du; + } +} + +/*void unknownStaticField:get(MVertex *ver,std::vector<double> &udofs){ + long int ent; + if(!fullDg){ + ent = ver->getNum(); + udofs = umap.find(ent)->second; + } + else{ + Msg::Error("Impossible to get displacement by vertex for full Dg formulation. Work only with MElement"); + } +}*/ + +void unknownStaticField::get(partDomain *dom, MElement *ele,std::vector<double> &udofs, const int cc){ + std::vector<Dof> R; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + sp->getKeys(ele,R); + this->get(R,udofs); +} + +void unknownStaticField::get(partDomain *dom, MElement *ele,fullVector<double> &udofs, const int cc){ + std::vector<Dof> R; + FunctionSpaceBase *sp = dom->getFunctionSpace(); + udofs.resize(sp->getNumKeys(ele)); + sp->getKeys(ele,R); + this->get(R,udofs); +} + +void unknownStaticField::get(partDomain *dom,MInterfaceElement* iele, std::vector<double> &udofs){ + this->get(dom,iele->getElem(0),udofs); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + this->get(dom,iele->getElem(1),udofs); + } +} + +void unknownStaticField::get(partDomain *dom1, partDomain *dom2,MInterfaceElement* iele, std::vector<double> &udofs){ + this->get(dom1,iele->getElem(0),udofs); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + this->get(dom2,iele->getElem(1),udofs); + } +} + +void unknownStaticField::get(FunctionSpaceBase *sp1, FunctionSpaceBase *sp2,MInterfaceElement* iele, std::vector<double> &udofs){ + std::vector<Dof> R; + sp1->getKeys(iele->getElem(0),R); + this->get(R,udofs); + if(!(iele->getElem(0)==iele->getElem(1))){// Virtual interface element + R.clear(); + sp2->getKeys(iele->getElem(1),R); + this->get(R,udofs); + } +} + +/*void unknownStaticField:getForPerturbation(FunctionSpaceBase &sp, MInterfaceElement* iele, const bool minus, Dof &D, double pert, std::vector<double> &udofs){ + double eps = -pert; + std::vector<Dof> R; + sp.getKeys(iele->getElem(0),R); + if(!minus){ + this->set(D,eps); + this->get(R,udofs); + this->set(D,pert); + } + else{ + this->get(R,udofs); + this->set(D,eps); + } + if(!(iele->getElem(0)==iele->getElem(1)))// Virtual interface element + R.clear(); + sp.getKeys(iele->getElem(1),R); + this->get(R,udofs); + if(minus) + this->set(D,pert); +}*/ + +void unknownStaticField::updateFixedDof(){ + double u; + for(std::vector<Dof>::iterator itD=fixedDof.begin(); itD<fixedDof.end();++itD){ + pAssembler->getDofValue(*itD,u); + umap.find(*itD)->second=u; + } + +} +void unknownStaticField::archiving(const double time){ + FILE *fp; + double u; + for(std::vector<archiveNode>::iterator it = varch.begin(); it!=varch.end();++it){ + Dof D = it->D; + this->get(D,u); + // write in File + std::ostringstream oss; + oss << it->nodenum; + std::string s = oss.str(); + // component of displacement + int field,comp,num; + Dof3IntType::getThreeIntsFromType(it->D.getType(),comp,field,num); + oss.str(""); + oss << comp; + std::string s2 = oss.str(); + std::string fname = "NodalDisplacement"+s+"comp"+s2+".csv"; + fp = fopen(fname.c_str(),"a"); + fprintf(fp,"%e;%e\n",time,u); + fclose(fp); + } +} + +void unknownStaticField::setInitial(const std::vector<Dof> &R, const std::vector<double> &disp){ + for(int i=0;i<R.size();i++){ + umap[R[i]] = disp[i]; + } +} + +/* +void unknownField::buildView(std::vector<partDomain*> &vdom,const double time, + const int nstep, const std::string &valuename, const int cc=-1, const bool binary=false){ + if(view){ + // test file size (and create a new one if needed) + uint32_t fileSize; + FILE *fp = fopen(fileName.c_str(), "r"); + if(!fp){ + Msg::Error("Unable to open file '%s'", fileName.c_str()); + return; + } + fseek (fp, 0, SEEK_END); + fileSize = (uint32_t) (ftell(fp)); + if(fileSize > fmaxsize) this->updateFileName(); + fclose(fp); + fp = fopen(fileName.c_str(), "a"); + + // compute the number of element + if(binary) Msg::Warning("Binary write not implemented yet"); + fprintf(fp, "$%s\n",dataname.c_str()); + fprintf(fp, "1\n\"%s\"\n",valuename.c_str()); + fprintf(fp, "1\n%.16g\n", time); + fprintf(fp, "3\n%d\n%d\n%d\n", nstep, numcomp, totelem); + std::vector<double> fieldData; + if(type == ElementNodeData){ + for(std::vector<partDomain*>::iterator itdom=vdom.begin(); itdom!=vdom.end(); ++itdom){ + partDomain *dom = *itdom; + for (groupOfElements::elementContainer::const_iterator it = dom->g->begin(); it != dom->g->end(); ++it){ + MElement *ele = *it; + int numv = ele->getNumVertices(); + this->get(dom,ele,fieldData,cc); + fprintf(fp, "%d %d",ele->getNum(),numv); + for(int i=0;i<numv;i++) + for(int j=0;j<numcomp;j++) + fprintf(fp, " %.16g",fieldData[i+j*numv]); + fprintf(fp,"\n"); + fieldData.clear(); + } + } + // loop on contact domain + for(nonLinearMechSolver::contactContainer::iterator it=_allContact->begin(); it!=_allContact->end(); ++it){ + contactDomain *cdom = *it; + if(cdom->isRigid()){ + for (groupOfElements::elementContainer::const_iterator it = cdom->gMaster->begin(); it != cdom->gMaster->end(); ++it){ + MElement *ele = *it; + int numv = ele->getNumVertices(); + rigidContactSpace *spgc = dynamic_cast<rigidContactSpace*>(cdom->getSpace()); + std::vector<Dof> R; + spgc->getKeysOfGravityCenter(R); + this->get(R,fieldData); + fprintf(fp, "%d %d",ele->getNum(),numv); + for(int i=0;i<numv;i++) + for(int j=0;j<numcomp;j++) + fprintf(fp, " %.16g",fieldData[j]); + fprintf(fp,"\n"); + fieldData.clear(); + } + } + } + } + else if(type == ElementData){ + for (unsigned int i = 0; i < vdom.size(); ++i) + for (groupOfElements::elementContainer::const_iterator it = vdom[i]->g->begin(); it != vdom[i]->g->end(); ++it){ + MElement *ele = *it; + fieldData.resize(numcomp); + this->get(vdom[i],ele,fieldData,cc); + fprintf(fp, "%d",ele->getNum()); + for(int j=0;j<numcomp;j++) + fprintf(fp, " %.16g",fieldData[j]); + fprintf(fp,"\n"); + } + } + fprintf(fp, "$End%s\n",dataname.c_str()); + fclose(fp); + } + else Msg::Warning("No displacement view created because the variable view is set to false for this field\n"); +} +*/ diff --git a/NonLinearSolver/nlsolver/unknownStaticField.h b/NonLinearSolver/nlsolver/unknownStaticField.h new file mode 100644 index 0000000000..8ac8d04544 --- /dev/null +++ b/NonLinearSolver/nlsolver/unknownStaticField.h @@ -0,0 +1,53 @@ +// +// C++ Interface: terms +// +// Description: Class with the displacement field +// +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef UNKNOWNSTATICFIELD_H_ +#define UNKNOWNSTATICFIELD_H_ +#include "dofManager.h" +#include "PView.h" +#include "PViewData.h" +#include <stdint.h> +#include <stdlib.h> +#include "elementField.h" +#include "contactDomain.h" + +class unknownStaticField : public unknownField{ + protected : + std::map<Dof,double> umap; // One Entry by Dof allow to manage more than 1 domain + public : + unknownStaticField(dofManager<double> *pas, std::vector<partDomain*> &elas, std::set<contactDomain*> *acontact, + const int nc, std::vector<std::pair<Dof,initialCondition::whichCondition> > &archiving, + std::vector<archiveRigidContactDisp> &contactarch, const bool =true, const std::string="disp.msh" + ) ; + // update all displacement value + virtual void update(); + virtual void updateFixedDof(); + // get Operation + virtual void get(Dof &D,double &udof) const; + virtual void get(std::vector<Dof> &R, std::vector<double> &disp) const; + virtual void get(std::vector<Dof> &R, fullVector<double> &disp) const; +// virtual void get(MVertex *ver,std::vector<double> &udofs); // works only for cG/dG (TODO fullDg case) + virtual void get(partDomain *dom, MElement *ele,std::vector<double> &udofs, const int=-1); + virtual void get(partDomain *dom, MElement *ele,fullVector<double> &udofs, const int=-1); + virtual void get(partDomain *dom, MInterfaceElement* iele, std::vector<double> &udofs); + virtual void get(partDomain *dom1, partDomain*dom2, MInterfaceElement* iele, std::vector<double> &udofs); + virtual void get(FunctionSpaceBase *sp1,FunctionSpaceBase *sp2, MInterfaceElement *iele,std::vector<double> &udofs); + virtual void set(Dof &D, double &val){ + umap[D] += val; + } +// virtual void getForPerturbation(FunctionSpaceBase &sp,MInterfaceElement* iele, const bool minus, Dof &D, double pert, std::vector<double> &udofs); + virtual void archiving(const double time); + virtual void setInitial(const std::vector<Dof> &R,const std::vector<double> &disp); +// virtual void buildView(std::vector<partDomain*> &vdom,const double time, +// const int nstep, const std::string &valuename, const int cc,const bool binary); +}; +#endif // DISPLACEMENTFIELD_H_ diff --git a/NonLinearSolver/space/CMakeLists.txt b/NonLinearSolver/space/CMakeLists.txt new file mode 100644 index 0000000000..4e6e8449eb --- /dev/null +++ b/NonLinearSolver/space/CMakeLists.txt @@ -0,0 +1,11 @@ +# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + functionSpaceType.h +) + +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(NonLinearSolver/space "${SRC};${HDR}") diff --git a/NonLinearSolver/space/functionSpaceType.h b/NonLinearSolver/space/functionSpaceType.h new file mode 100644 index 0000000000..c0f8448eeb --- /dev/null +++ b/NonLinearSolver/space/functionSpaceType.h @@ -0,0 +1,22 @@ +// +// group for interface element +// +// Description: Choose a function space. Can be integrated in functionSpace.h +// +// Author: <Gauthier BECKER>, (C) 2010 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef FUNCTIONSPACETYPE_H_ +#define FUNCTIONSPACETYPE_H_ +// Enum that allow to choose a function space +class functionSpaceType{ + public : + // To chosen the space type + enum whichSpace{Lagrange, Inter}; + functionSpaceType(){}; + ~functionSpaceType(){}; // rewrite to delete object +}; +#endif // FUNCTIONSPACETYPE_H_ diff --git a/Numeric/simpleFunction.h b/Numeric/simpleFunction.h index c833015189..883f717603 100644 --- a/Numeric/simpleFunction.h +++ b/Numeric/simpleFunction.h @@ -11,6 +11,7 @@ template <class scalar> class simpleFunction { + protected: scalar _val; public : simpleFunction(scalar val=0.0) : _val(val) {} diff --git a/Solver/quadratureRules.h b/Solver/quadratureRules.h index 880bfbb37f..fbcc755317 100644 --- a/Solver/quadratureRules.h +++ b/Solver/quadratureRules.h @@ -24,6 +24,16 @@ class QuadratureBase virtual int getIntPoints(MElement *e, IntPt **GP) =0; }; +// For rigid contact no need of Gauss'integration +// but to use classcal get function in term npts and IntPt are needed +// so use a empty gaussQuadrature rule +class QuadratureVoid : public QuadratureBase +{ + public: + QuadratureVoid() : QuadratureBase(){} + ~QuadratureVoid(){} + int getIntPoints(MElement *e, IntPt **GP){GP=NULL; return 0;} +} ; class GaussQuadrature : public QuadratureBase { @@ -36,7 +46,7 @@ class GaussQuadrature : public QuadratureBase GaussQuadrature(int order_ = 0) : order(order_), info(Other) {} GaussQuadrature(IntegCases info_) : order(0), info(info_) {} virtual ~GaussQuadrature(){} - int getIntPoints(MElement *e, IntPt **GP) + virtual int getIntPoints(MElement *e, IntPt **GP) { int integrationOrder; int npts; @@ -65,5 +75,4 @@ class GaussQuadrature : public QuadratureBase } }; - #endif //_QUADRATURERULES_H_ diff --git a/Solver/terms.h b/Solver/terms.h index e3540ec8ee..4721f09014 100644 --- a/Solver/terms.h +++ b/Solver/terms.h @@ -65,7 +65,7 @@ public : ScalarTermConstant(T2 val_ = T2()) : cst(val_) {} virtual ~ScalarTermConstant() {} virtual void get(MElement *ele, int npts, IntPt *GP, T2 &val) const; - virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<T2> &vval) const; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector<T2> &vval) const; virtual void get(MVertex *ver, T2 &val) const; virtual ScalarTermBase<T2>* clone () const {return new ScalarTermConstant<T2>(cst);} }; @@ -259,7 +259,7 @@ public : } virtual ~LagrangeMultiplierTerm() {} virtual void get(MElement *ele, int npts, IntPt *GP, fullMatrix<double> &m) const; - virtual void get(MElement *ele, int npts, IntPt *GP, std::vector< fullMatrix<double> > &vm) const{}; + virtual void get(MElement *ele, int npts, IntPt *GP, std::vector< fullMatrix<double> > &vm) const{}; virtual BilinearTermBase* clone () const {return new LagrangeMultiplierTerm(BilinearTerm<SVector3, double>::space1,BilinearTerm<SVector3, double>::space2,_d);} }; -- GitLab