AbstractContinuumMechanicsSolver.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #ifndef ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_
00037 #define ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_
00038 
00039 #include "ContinuumMechanicsProblemDefinition.hpp"
00040 #include "CompressibilityType.hpp"
00041 #include "LinearSystem.hpp"
00042 #include "OutputFileHandler.hpp"
00043 #include "ReplicatableVector.hpp"
00044 #include "AbstractTetrahedralMesh.hpp"
00045 #include "QuadraticMesh.hpp"
00046 #include "DistributedQuadraticMesh.hpp"
00047 #include "Warnings.hpp"
00048 #include "PetscException.hpp"
00049 #include "GaussianQuadratureRule.hpp"
00050 #include "PetscTools.hpp"
00051 #include "MechanicsEventHandler.hpp"
00052 #include "CommandLineArguments.hpp"
00053 #include "VtkMeshWriter.hpp"
00054 
00055 
00061 typedef enum _ApplyDirichletBcsType
00062 {
00063     LINEAR_PROBLEM,
00064     NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY,
00065     NONLINEAR_PROBLEM_APPLY_TO_EVERYTHING
00066 } ApplyDirichletBcsType;
00067 
00068 //forward declarations
00069 template<unsigned DIM> class StressRecoveror;
00070 template<unsigned DIM> class VtkNonlinearElasticitySolutionWriter;
00071 
00086 template<unsigned DIM>
00087 class AbstractContinuumMechanicsSolver
00088 {
00089     friend class StressRecoveror<DIM>;
00090     friend class VtkNonlinearElasticitySolutionWriter<DIM>;
00091 
00092 protected:
00097     AbstractTetrahedralMesh<DIM, DIM>& mrQuadMesh;
00098 
00100     ContinuumMechanicsProblemDefinition<DIM>& mrProblemDefinition;
00101 
00103     bool mWriteOutput;
00104 
00106     std::string mOutputDirectory;
00107 
00109     OutputFileHandler* mpOutputFileHandler;
00110 
00114     std::vector<c_vector<double,DIM> > mSpatialSolution;
00115 
00117     std::vector<double> mPressureSolution;
00118 
00119 
00126     std::vector<double> mCurrentSolution;
00127 
00129     GaussianQuadratureRule<DIM>* mpQuadratureRule;
00130 
00132     GaussianQuadratureRule<DIM-1>* mpBoundaryQuadratureRule;
00133 
00138     CompressibilityType mCompressibilityType;
00139 
00148     unsigned mProblemDimension;
00149 
00153     unsigned mNumDofs;
00154 
00160     bool mVerbose;
00161 
00182     Vec mResidualVector;
00183 
00187     Vec mLinearSystemRhsVector;
00188 
00192     Mat mSystemLhsMatrix;
00193 
00197     Vec mDirichletBoundaryConditionsVector;
00198 
00202     Mat mPreconditionMatrix;
00203 
00207     void AllocateMatrixMemory();
00208 
00209 
00235     void ApplyDirichletBoundaryConditions(ApplyDirichletBcsType type, bool symmetricProblem);
00236 
00269     void AddIdentityBlockForDummyPressureVariables(ApplyDirichletBcsType type);
00270 
00271 
00288     void RemovePressureDummyValuesThroughLinearInterpolation();
00289 
00290 public:
00298     AbstractContinuumMechanicsSolver(AbstractTetrahedralMesh<DIM, DIM>& rQuadMesh,
00299                                      ContinuumMechanicsProblemDefinition<DIM>& rProblemDefinition,
00300                                      std::string outputDirectory,
00301                                      CompressibilityType compressibilityType);
00302 
00304     virtual ~AbstractContinuumMechanicsSolver();
00305 
00317     void WriteCurrentSpatialSolution(std::string fileName, std::string fileExtension, int counterToAppend=-1);
00318 
00331     void WriteCurrentPressureSolution( int counterToAppend=-1);
00332 
00338     void SetWriteOutput(bool writeOutput=true);
00339 
00347     void CreateVtkOutput(std::string spatialSolutionName="Spatial solution");
00348 
00353     std::vector<double>& rGetCurrentSolution()
00354     {
00355         return mCurrentSolution;
00356     }
00357 
00362     virtual std::vector<c_vector<double,DIM> >& rGetSpatialSolution()=0;
00363 
00372     std::vector<double>& rGetPressures();
00373 
00374 };
00375 
00376 
00377 template<unsigned DIM>
00378 AbstractContinuumMechanicsSolver<DIM>::AbstractContinuumMechanicsSolver(AbstractTetrahedralMesh<DIM, DIM>& rQuadMesh,
00379                                                                         ContinuumMechanicsProblemDefinition<DIM>& rProblemDefinition,
00380                                                                         std::string outputDirectory,
00381                                                                         CompressibilityType compressibilityType)
00382     : mrQuadMesh(rQuadMesh),
00383       mrProblemDefinition(rProblemDefinition),
00384       mOutputDirectory(outputDirectory),
00385       mpOutputFileHandler(NULL),
00386       mpQuadratureRule(NULL),
00387       mpBoundaryQuadratureRule(NULL),
00388       mCompressibilityType(compressibilityType),
00389       mResidualVector(NULL),
00390       mSystemLhsMatrix(NULL),
00391       mPreconditionMatrix(NULL)
00392 {
00393     assert(DIM==2 || DIM==3);
00394 
00395     //Check that the mesh is Quadratic
00396     QuadraticMesh<DIM>* p_quad_mesh = dynamic_cast<QuadraticMesh<DIM>* >(&rQuadMesh);
00397     DistributedQuadraticMesh<DIM>* p_distributed_quad_mesh = dynamic_cast<DistributedQuadraticMesh<DIM>* >(&rQuadMesh);
00398 
00399     if(p_quad_mesh == NULL && p_distributed_quad_mesh == NULL)
00400     {
00401         EXCEPTION("Continuum mechanics solvers require a quadratic mesh");
00402     }
00403 
00404 
00405     mVerbose = (mrProblemDefinition.GetVerboseDuringSolve() ||
00406                 CommandLineArguments::Instance()->OptionExists("-mech_verbose") ||
00407                 CommandLineArguments::Instance()->OptionExists("-mech_very_verbose") );
00408 
00409     mWriteOutput = (mOutputDirectory != "");
00410     if (mWriteOutput)
00411     {
00412         mpOutputFileHandler = new OutputFileHandler(mOutputDirectory);
00413     }
00414 
00415     // see dox for mProblemDimension
00416     mProblemDimension = mCompressibilityType==COMPRESSIBLE ? DIM : DIM+1;
00417     mNumDofs = mProblemDimension*mrQuadMesh.GetNumNodes();
00418 
00419     AllocateMatrixMemory();
00420 
00421     // In general the Jacobian for a mechanics problem is non-polynomial.
00422     // We therefore use the highest order integration rule available.
00423     mpQuadratureRule = new GaussianQuadratureRule<DIM>(3);
00424     // The boundary forcing terms (or tractions) are also non-polynomial in general.
00425     // Again, we use the highest order integration rule available.
00426     mpBoundaryQuadratureRule = new GaussianQuadratureRule<DIM-1>(3);
00427 
00428     mCurrentSolution.resize(mNumDofs, 0.0);
00429 }
00430 
00431 
00432 template<unsigned DIM>
00433 AbstractContinuumMechanicsSolver<DIM>::~AbstractContinuumMechanicsSolver()
00434 {
00435     if (mpOutputFileHandler)
00436     {
00437         delete mpOutputFileHandler;
00438     }
00439 
00440     if (mpQuadratureRule)
00441     {
00442         delete mpQuadratureRule;
00443         delete mpBoundaryQuadratureRule;
00444     }
00445 
00446     if (mResidualVector)
00447     {
00448         PetscTools::Destroy(mResidualVector);
00449         PetscTools::Destroy(mLinearSystemRhsVector);
00450         PetscTools::Destroy(mSystemLhsMatrix);
00451         PetscTools::Destroy(mPreconditionMatrix);
00452     }
00453 
00454     if (mDirichletBoundaryConditionsVector)
00455     {
00456         PetscTools::Destroy(mDirichletBoundaryConditionsVector);
00457     }
00458 }
00459 
00460 template<unsigned DIM>
00461 void AbstractContinuumMechanicsSolver<DIM>::WriteCurrentSpatialSolution(std::string fileName,
00462                                                                         std::string fileExtension,
00463                                                                         int counterToAppend)
00464 {
00465     // Only write output if the flag mWriteOutput has been set
00466     if (!mWriteOutput)
00467     {
00468         return;
00469     }
00470 
00471     if (PetscTools::AmMaster())
00472     {
00473         std::stringstream file_name;
00474 
00475         file_name << fileName;
00476         if (counterToAppend >= 0)
00477         {
00478             file_name << "_" << counterToAppend;
00479         }
00480         file_name << "." << fileExtension;
00481 
00482         out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
00483 
00484         std::vector<c_vector<double,DIM> >& r_spatial_solution = rGetSpatialSolution();
00485         for (unsigned i=0; i<r_spatial_solution.size(); i++)
00486         {
00487     //        for (unsigned j=0; j<DIM; j++)
00488     //        {
00489     //            *p_file << mrQuadMesh.GetNode(i)->rGetLocation()[j] << " ";
00490     //        }
00491             for (unsigned j=0; j<DIM; j++)
00492             {
00493                 *p_file << r_spatial_solution[i](j) << " ";
00494             }
00495             *p_file << "\n";
00496         }
00497         p_file->close();
00498     }
00499     PetscTools::Barrier("WriteSpatial");
00500 }
00501 
00502 template<unsigned DIM>
00503 void AbstractContinuumMechanicsSolver<DIM>::WriteCurrentPressureSolution(int counterToAppend)
00504 {
00505     // Only write output if the flag mWriteOutput has been set
00506     if (!mWriteOutput)
00507     {
00508         return;
00509     }
00510 
00511     if (PetscTools::AmMaster())
00512     {
00513         std::stringstream file_name;
00514 
00515         file_name << "pressure";
00516         if (counterToAppend >= 0)
00517         {
00518             file_name << "_" << counterToAppend;
00519         }
00520         file_name << ".txt";
00521 
00522         out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
00523 
00524         std::vector<double>& r_pressure = rGetPressures();
00525         for (unsigned i=0; i<r_pressure.size(); i++)
00526         {
00527             for (unsigned j=0; j<DIM; j++)
00528             {
00529                 *p_file << mrQuadMesh.GetNode(i)->rGetLocation()[j] << " ";
00530             }
00531 
00532             *p_file << r_pressure[i] << "\n";
00533         }
00534         p_file->close();
00535     }
00536     PetscTools::Barrier("WritePressure");
00537 }
00538 
00539 
00540 template<unsigned DIM>
00541 void AbstractContinuumMechanicsSolver<DIM>::SetWriteOutput(bool writeOutput)
00542 {
00543     if (writeOutput && (mOutputDirectory==""))
00544     {
00545         EXCEPTION("Can't write output if no output directory was given in constructor");
00546     }
00547     mWriteOutput = writeOutput;
00548 }
00549 
00550 // ** TO BE DEPRECATED - see #2321 **
00551 template<unsigned DIM>
00552 void AbstractContinuumMechanicsSolver<DIM>::CreateVtkOutput(std::string spatialSolutionName)
00553 {
00554     if (this->mOutputDirectory=="")
00555     {
00556         EXCEPTION("No output directory was given so no output was written, cannot convert to VTK format");
00557     }
00558 #ifdef CHASTE_VTK
00559     VtkMeshWriter<DIM, DIM> mesh_writer(this->mOutputDirectory + "/vtk", "solution", true);
00560 
00561     mesh_writer.AddPointData(spatialSolutionName, this->rGetSpatialSolution());
00562 
00563     if (mCompressibilityType==INCOMPRESSIBLE)
00564     {
00565         mesh_writer.AddPointData("Pressure", rGetPressures());
00566     }
00567 
00568     //Output the element attribute as cell data.
00569     std::vector<double> element_attribute;
00570     for(typename QuadraticMesh<DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
00571         iter != this->mrQuadMesh.GetElementIteratorEnd();
00572         ++iter)
00573     {
00574         element_attribute.push_back(iter->GetAttribute());
00575     }
00576     mesh_writer.AddCellData("Attribute", element_attribute);
00577 
00578     mesh_writer.WriteFilesUsingMesh(this->mrQuadMesh);
00579 #endif
00580 }
00581 
00582 
00583 template<unsigned DIM>
00584 std::vector<double>& AbstractContinuumMechanicsSolver<DIM>::rGetPressures()
00585 {
00586     assert(mProblemDimension==DIM+1);
00587 
00588     mPressureSolution.clear();
00589     mPressureSolution.resize(mrQuadMesh.GetNumNodes());
00590 
00591     for (unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
00592     {
00593         mPressureSolution[i] = mCurrentSolution[mProblemDimension*i + DIM];
00594     }
00595     return mPressureSolution;
00596 }
00597 
00598 
00599 template<unsigned DIM>
00600 void AbstractContinuumMechanicsSolver<DIM>::RemovePressureDummyValuesThroughLinearInterpolation()
00601 {
00602     assert(mProblemDimension==DIM+1);
00603 
00604     // For quadratic triangles, node 3 is between nodes 1 and 2, node 4 is between 0 and 2, etc
00605     unsigned internal_nodes_2d[3] = {3,4,5};
00606     unsigned neighbouring_vertices_2d[3][2] = { {1,2}, {2,0}, {0,1} };
00607 
00608     // ordering for quadratic tetrahedra
00609     unsigned internal_nodes_3d[6] = {4,5,6,7,8,9};
00610     unsigned neighbouring_vertices_3d[6][2] = { {0,1}, {1,2}, {0,2}, {0,3}, {1,3}, {2,3} };
00611 
00612     unsigned num_internal_nodes_per_element = DIM==2 ? 3 : 6;
00613 
00614     // loop over elements, then loop over edges.
00615     for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = mrQuadMesh.GetElementIteratorBegin();
00616          iter != mrQuadMesh.GetElementIteratorEnd();
00617          ++iter)
00618     {
00619         for(unsigned i=0; i<num_internal_nodes_per_element; i++)
00620         {
00621             unsigned global_index;
00622             double left_val;
00623             double right_val;
00624 
00625             if(DIM==2)
00626             {
00627                 global_index = iter->GetNodeGlobalIndex( internal_nodes_2d[i] );
00628                 unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][0] );
00629                 unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][1] );
00630                 left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM];
00631                 right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM];
00632             }
00633             else
00634             {
00635                 global_index = iter->GetNodeGlobalIndex( internal_nodes_3d[i] );
00636                 unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][0] );
00637                 unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][1] );
00638                 left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM];
00639                 right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM];
00640             }
00641 
00642             // this line assumes the internal node is midway between the two vertices
00643             mCurrentSolution[mProblemDimension*global_index + DIM] =  0.5 * (left_val + right_val);
00644         }
00645     }
00646 }
00647 
00648 /*
00649  * This method applies the appropriate BCs to the residual and/or linear system
00650  *
00651  * For the latter, and second input parameter==true, the BCs are imposed in such a way as
00652  * to ensure that a symmetric linear system remains symmetric. For each row with boundary condition
00653  * applied, both the row and column are zero'd and the RHS vector modified to take into account the
00654  * zero'd column.
00655  *
00656  * Suppose we have a matrix
00657  * [a b c] [x] = [ b1 ]
00658  * [d e f] [y]   [ b2 ]
00659  * [g h i] [z]   [ b3 ]
00660  * and we want to apply the boundary condition x=v without losing symmetry if the matrix is
00661  * symmetric. We apply the boundary condition
00662  * [1 0 0] [x] = [ v  ]
00663  * [d e f] [y]   [ b2 ]
00664  * [g h i] [z]   [ b3 ]
00665  * and then zero the column as well, adding a term to the RHS to take account for the
00666  * zero-matrix components
00667  * [1 0 0] [x] = [ v  ] - v[ 0 ]
00668  * [0 e f] [y]   [ b2 ]    [ d ]
00669  * [0 h i] [z]   [ b3 ]    [ g ]
00670  * Note the last term is the first column of the matrix, with one component zeroed, and
00671  * multiplied by the boundary condition value. This last term is then stored in
00672  * mDirichletBoundaryConditionsVector, and in general is equal to:
00673  * SUM_{d=1..D} v_d a'_d
00674  * where v_d is the boundary value of boundary condition d (d an index into the matrix),
00675  * and a'_d is the dth-column of the matrix but with the d-th component zeroed, and where
00676  * there are D boundary conditions
00677  */
00678 template<unsigned DIM>
00679 void AbstractContinuumMechanicsSolver<DIM>::ApplyDirichletBoundaryConditions(ApplyDirichletBcsType type, bool symmetricProblem)
00680 {
00681     std::vector<unsigned> rows;
00682     std::vector<double> values;
00683 
00684     // Whether to apply symmetrically, ie alter columns as well as rows (see comment above)
00685     bool applySymmetrically = (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) && symmetricProblem;
00686 
00687     if (applySymmetrically)
00688     {
00689         if(mDirichletBoundaryConditionsVector==NULL)
00690         {
00691             VecDuplicate(mResidualVector, &mDirichletBoundaryConditionsVector);
00692         }
00693 
00694         PetscVecTools::Zero(mDirichletBoundaryConditionsVector);
00695         PetscMatTools::Finalise(mSystemLhsMatrix);
00696     }
00697 
00699     // collect the entries to be altered
00701 
00702     for (unsigned i=0; i<mrProblemDefinition.rGetDirichletNodes().size(); i++)
00703     {
00704         unsigned node_index = mrProblemDefinition.rGetDirichletNodes()[i];
00705 
00706         for (unsigned j=0; j<DIM; j++)
00707         {
00708             double dirichlet_val = mrProblemDefinition.rGetDirichletNodeValues()[i](j);
00709 
00710             if(dirichlet_val != ContinuumMechanicsProblemDefinition<DIM>::FREE)
00711             {
00712                 double val;
00713                 unsigned dof_index = mProblemDimension*node_index+j;
00714 
00715                 if(type == LINEAR_PROBLEM)
00716                 {
00717                     val = dirichlet_val;
00718                 }
00719                 else
00720                 {
00721                     // The boundary conditions on the NONLINEAR SYSTEM are x=boundary_values
00722                     // on the boundary nodes. However:
00723                     // The boundary conditions on the LINEAR SYSTEM at each Newton step (Ju=f,
00724                     // where J is the Jacobian, u the negative update vector and f is the residual) is:
00725                     // u=current_soln-boundary_values on the boundary nodes
00726                     val = mCurrentSolution[dof_index] - dirichlet_val;
00727                 }
00728                 rows.push_back(dof_index);
00729                 values.push_back(val);
00730             }
00731         }
00732     }
00733 
00735     // do the alterations
00737 
00738     if (applySymmetrically)
00739     {
00740         // Modify the matrix columns
00741         for (unsigned i=0; i<rows.size(); i++)
00742         {
00743             unsigned col = rows[i];
00744             double minus_value = -values[i];
00745 
00746             // Get a vector which will store the column of the matrix (column d, where d is
00747             // the index of the row (and column) to be altered for the boundary condition.
00748             // Since the matrix is symmetric when get row number "col" and treat it as a column.
00749             // PETSc uses compressed row format and therefore getting rows is far more efficient
00750             // than getting columns.
00751             Vec matrix_col = PetscMatTools::GetMatrixRowDistributed(mSystemLhsMatrix,col);
00752 
00753             // Zero the correct entry of the column
00754             PetscVecTools::SetElement(matrix_col, col, 0.0);
00755 
00756             // Set up the RHS Dirichlet boundary conditions vector
00757             // E.g. for a boundary node at the zeroth node (x_0 = value), this is equal to
00758             //   -value*[0 a_21 a_31 .. a_N1]
00759             // and will be added to the RHS.
00760             PetscVecTools::AddScaledVector(mDirichletBoundaryConditionsVector, matrix_col, minus_value);
00761             PetscTools::Destroy(matrix_col);
00762         }
00763     }
00764 
00765     if (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) // ie doing a whole linear system
00766     {
00767         // Now zero the appropriate rows and columns of the matrix. If the matrix is symmetric we apply the
00768         // boundary conditions in a way the symmetry isn't lost (rows and columns). If not only the row is
00769         // zeroed.
00770         if (applySymmetrically)
00771         {
00772             PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mSystemLhsMatrix, rows, 1.0);
00773             PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
00774 
00775             // Apply the RHS boundary conditions modification if required.
00776             PetscVecTools::AddScaledVector(mLinearSystemRhsVector, mDirichletBoundaryConditionsVector, 1.0);
00777         }
00778         else
00779         {
00780             PetscMatTools::ZeroRowsWithValueOnDiagonal(mSystemLhsMatrix, rows, 1.0);
00781             PetscMatTools::ZeroRowsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
00782         }
00783     }
00784 
00785     if (type!=LINEAR_PROBLEM)
00786     {
00787         for (unsigned i=0; i<rows.size(); i++)
00788         {
00789             PetscVecTools::SetElement(mResidualVector, rows[i], values[i]);
00790         }
00791     }
00792 
00793     if (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY)
00794     {
00795         for (unsigned i=0; i<rows.size(); i++)
00796         {
00797             PetscVecTools::SetElement(mLinearSystemRhsVector, rows[i], values[i]);
00798         }
00799     }
00800 }
00801 
00802 
00803 template<unsigned DIM>
00804 void AbstractContinuumMechanicsSolver<DIM>::AddIdentityBlockForDummyPressureVariables(ApplyDirichletBcsType type)
00805 {
00806     assert(mCompressibilityType==INCOMPRESSIBLE);
00807 
00808     int lo, hi;
00809     VecGetOwnershipRange(mResidualVector, &lo, &hi);
00810 
00811     for(unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
00812     {
00813         if(mrQuadMesh.GetNode(i)->IsInternal())
00814         {
00815             unsigned row = (DIM+1)*i + DIM; // DIM+1 is the problem dimension
00816             if(lo <= (int)row && (int)row < hi)
00817             {
00818                 if(type!=LINEAR_PROBLEM)
00819                 {
00820                     PetscVecTools::SetElement(mResidualVector, row, mCurrentSolution[row]-0.0);
00821                 }
00822                 if(type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) // ie doing a whole linear system
00823                 {
00824                     double rhs_vector_val = type==LINEAR_PROBLEM ? 0.0 : mCurrentSolution[row]-0.0;
00825                     PetscVecTools::SetElement(mLinearSystemRhsVector, row, rhs_vector_val);
00826                     // this assumes the row is already zero, which is should be..
00827                     PetscMatTools::SetElement(mSystemLhsMatrix, row, row, 1.0);
00828                     PetscMatTools::SetElement(mPreconditionMatrix, row, row, 1.0);
00829                 }
00830             }
00831         }
00832     }
00833 }
00834 
00835 
00836 
00837 template<unsigned DIM>
00838 void AbstractContinuumMechanicsSolver<DIM>::AllocateMatrixMemory()
00839 {
00840     Vec template_vec = mrQuadMesh.GetDistributedVectorFactory()->CreateVec(mProblemDimension);
00841 
00843     // three vectors
00845     VecDuplicate(template_vec, &mResidualVector);
00846     VecDuplicate(mResidualVector, &mLinearSystemRhsVector);
00847     // the one is only allocated if it will be needed (in ApplyDirichletBoundaryConditions),
00848     // depending on whether the matrix is kept symmetric.
00849     mDirichletBoundaryConditionsVector = NULL;
00850     PetscTools::Destroy(template_vec);
00851 
00853     // two matrices
00855 
00856     int lo, hi;
00857     VecGetOwnershipRange(mResidualVector, &lo, &hi);
00858     PetscInt local_size = hi - lo;
00859 
00860 
00861     if (DIM==2)
00862     {
00863         // 2D: N elements around a point => 7N+3 non-zeros in that row? Assume N<=10 (structured mesh would have N_max=6) => 73.
00864         unsigned num_non_zeros = std::min(75u, mNumDofs);
00865 
00866         PetscTools::SetupMat(mSystemLhsMatrix, mNumDofs, mNumDofs, num_non_zeros, local_size, local_size);
00867         PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, num_non_zeros, local_size, local_size);
00868     }
00869     else
00870     {
00871         assert(DIM==3);
00872 
00873         // in 3d we get the number of containing elements for each node and use that to obtain an upper bound
00874         // for the number of non-zeros for each DOF associated with that node.
00875 
00876         int* num_non_zeros_each_row = new int[mNumDofs];
00877         for (unsigned i=0; i<mNumDofs; i++)
00878         {
00879             num_non_zeros_each_row[i] = 0;
00880         }
00881 
00882         for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mrQuadMesh.GetNodeIteratorBegin();
00883              iter != mrQuadMesh.GetNodeIteratorEnd();
00884              ++iter)
00885         {
00886             // this upper bound neglects the fact that two containing elements will share the same nodes..
00887             // 4 = max num dofs associated with this node
00888             // 30 = 3*9+3 = 3 dimensions x 9 other nodes on this element   +  3 vertices with a pressure unknown
00889             unsigned num_non_zeros_upper_bound = 4 + 30*iter->GetNumContainingElements();
00890 
00891             num_non_zeros_upper_bound = std::min(num_non_zeros_upper_bound, mNumDofs);
00892 
00893             unsigned i = iter->GetIndex();
00894 
00895             num_non_zeros_each_row[mProblemDimension*i + 0] = num_non_zeros_upper_bound;
00896             num_non_zeros_each_row[mProblemDimension*i + 1] = num_non_zeros_upper_bound;
00897             num_non_zeros_each_row[mProblemDimension*i + 2] = num_non_zeros_upper_bound;
00898 
00899             if (mCompressibilityType==INCOMPRESSIBLE)
00900             {
00901                 if(!iter->IsInternal())
00902                 {
00903                     num_non_zeros_each_row[mProblemDimension*i + 3] = num_non_zeros_upper_bound;
00904                 }
00905                 else
00906                 {
00907                     num_non_zeros_each_row[mProblemDimension*i + 3] = 1;
00908                 }
00909             }
00910         }
00911 
00912         // NOTE: PetscTools::SetupMat() or the below creates a MATAIJ matrix, which means the matrix will
00913         // be of type MATSEQAIJ if num_procs=1 and MATMPIAIJ otherwise. In the former case
00914         // MatSeqAIJSetPreallocation MUST be called [MatMPIAIJSetPreallocation will have
00915         // no effect (silently)], and vice versa in the latter case
00916 
00919         //PetscTools::SetupMat(mSystemLhsMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
00920         //PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
00922 
00923         // possible todo: create a PetscTools::SetupMatNoAllocation()
00924 
00925 
00926 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00927         MatCreate(PETSC_COMM_WORLD,local_size,local_size,mNumDofs,mNumDofs,&mSystemLhsMatrix);
00928         MatCreate(PETSC_COMM_WORLD,local_size,local_size,mNumDofs,mNumDofs,&mPreconditionMatrix);
00929 #else //New API
00930         MatCreate(PETSC_COMM_WORLD,&mSystemLhsMatrix);
00931         MatCreate(PETSC_COMM_WORLD,&mPreconditionMatrix);
00932         MatSetSizes(mSystemLhsMatrix,local_size,local_size,mNumDofs,mNumDofs);
00933         MatSetSizes(mPreconditionMatrix,local_size,local_size,mNumDofs,mNumDofs);
00934 #endif
00935 
00936         if (PetscTools::IsSequential())
00937         {
00938             MatSetType(mSystemLhsMatrix, MATSEQAIJ);
00939             MatSetType(mPreconditionMatrix, MATSEQAIJ);
00940             MatSeqAIJSetPreallocation(mSystemLhsMatrix,    PETSC_DEFAULT, num_non_zeros_each_row);
00941             MatSeqAIJSetPreallocation(mPreconditionMatrix, PETSC_DEFAULT, num_non_zeros_each_row);
00942         }
00943         else
00944         {
00945             int* num_non_zeros_each_row_in_diag = new int[local_size];
00946             int* num_non_zeros_each_row_off_diag = new int[local_size];
00947             for (unsigned i=0; i<unsigned(local_size); i++)
00948             {
00949                 num_non_zeros_each_row_in_diag[i] = num_non_zeros_each_row[lo+i];
00950                 num_non_zeros_each_row_off_diag[i] = num_non_zeros_each_row[lo+i];
00951                 // In the on process ("diagonal block") there cannot be more non-zero columns specified than there are rows
00952                 if(num_non_zeros_each_row_in_diag[i] > local_size)
00953                 {
00954                     num_non_zeros_each_row_in_diag[i] = local_size;
00955                 }
00956             }
00957 
00958             MatSetType(mSystemLhsMatrix, MATMPIAIJ);
00959             MatSetType(mPreconditionMatrix, MATMPIAIJ);
00960             MatMPIAIJSetPreallocation(mSystemLhsMatrix,    PETSC_DEFAULT, num_non_zeros_each_row_in_diag, PETSC_DEFAULT, num_non_zeros_each_row_off_diag);
00961             MatMPIAIJSetPreallocation(mPreconditionMatrix, PETSC_DEFAULT, num_non_zeros_each_row_in_diag, PETSC_DEFAULT, num_non_zeros_each_row_off_diag);
00962         }
00963 
00964         MatSetFromOptions(mSystemLhsMatrix);
00965         MatSetFromOptions(mPreconditionMatrix);
00966 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
00967         MatSetOption(mSystemLhsMatrix, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00968         MatSetOption(mPreconditionMatrix, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00969 #else
00970         MatSetOption(mSystemLhsMatrix, MAT_IGNORE_OFF_PROC_ENTRIES);
00971         MatSetOption(mPreconditionMatrix, MAT_IGNORE_OFF_PROC_ENTRIES);
00972 #endif
00973 
00974         //unsigned total_non_zeros = 0;
00975         //for (unsigned i=0; i<mNumDofs; i++)
00976         //{
00977         //   total_non_zeros += num_non_zeros_each_row[i];
00978         //}
00979         //std::cout << total_non_zeros << " versus " << 500*mNumDofs << "\n" << std::flush;
00980 
00981         delete [] num_non_zeros_each_row;
00982     }
00983 }
00984 #endif // ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_

Generated by  doxygen 1.6.2