00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef ABSTRACTNONLINEARELASTICITYASSEMBLER_HPP_
00030 #define ABSTRACTNONLINEARELASTICITYASSEMBLER_HPP_
00031
00032 #include <vector>
00033 #include <cmath>
00034 #include "LinearSystem.hpp"
00035 #include "AbstractIncompressibleMaterialLaw.hpp"
00036 #include "OutputFileHandler.hpp"
00037 #include "LogFile.hpp"
00038 #include "PetscTools.hpp"
00039 #include "MechanicsEventHandler.hpp"
00040
00044
00045
00046 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00047 #include "DealiiLinearSystem.hpp"
00048 #endif
00049
00050
00051
00052
00053 template<unsigned DIM>
00054 class AbstractNonlinearElasticityAssembler
00055 {
00056 protected:
00058 static const double MAX_NEWTON_ABS_TOL = 1e-8;
00060 static const double MIN_NEWTON_ABS_TOL = 1e-12;
00062 static const double NEWTON_REL_TOL = 1e-4;
00063
00068 unsigned mNumDofs;
00069
00075 std::vector<AbstractIncompressibleMaterialLaw<DIM>*> mMaterialLaws;
00081 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00082 DealiiLinearSystem* mpLinearSystem;
00083 #else
00084 LinearSystem* mpLinearSystem;
00085 #endif
00086
00104 LinearSystem* mpPreconditionMatrixLinearSystem;
00105
00107 c_vector<double,DIM> mBodyForce;
00109 double mDensity;
00110
00112 std::string mOutputDirectory;
00114 std::vector<unsigned> mFixedNodes;
00116 std::vector<c_vector<double,DIM> > mFixedNodeDisplacements;
00117
00119 bool mWriteOutput;
00120
00126 std::vector<double> mCurrentSolution;
00127
00132 FourthOrderTensor2<DIM> dTdE;
00133
00135 unsigned mNumNewtonIterations;
00136
00137
00139 std::vector<c_vector<double,DIM> > mDeformedPosition;
00140
00145 std::vector<double> mPressures;
00150 std::vector<c_vector<double,DIM> > mSurfaceTractions;
00151
00153 c_vector<double,DIM> (*mpBodyForceFunction)(c_vector<double,DIM>&);
00157 c_vector<double,DIM> (*mpTractionBoundaryConditionFunction)(c_vector<double,DIM>&);
00159 bool mUsingBodyForceFunction;
00161 bool mUsingTractionBoundaryConditionFunction;
00162
00163
00164
00165 virtual void FormInitialGuess()=0;
00166 virtual void AssembleSystem(bool assembleResidual, bool assembleJacobian)=0;
00167 virtual std::vector<c_vector<double,DIM> >& rGetDeformedPosition()=0;
00168
00172 void ApplyBoundaryConditions(bool applyToMatrix)
00173 {
00174 assert(mFixedNodeDisplacements.size()==mFixedNodes.size());
00175
00176
00177
00178
00179
00180
00181 for(unsigned i=0; i<mFixedNodes.size(); i++)
00182 {
00183 unsigned node_index = mFixedNodes[i];
00184 for(unsigned j=0; j<DIM; j++)
00185 {
00186 unsigned dof_index = DIM*node_index+j;
00187 double value = mCurrentSolution[dof_index] - mFixedNodeDisplacements[i](j);
00188 if (applyToMatrix)
00189 {
00190 mpLinearSystem->ZeroMatrixRow(dof_index);
00191 mpLinearSystem->SetMatrixElement(dof_index,dof_index,1);
00192
00193
00194 mpPreconditionMatrixLinearSystem->ZeroMatrixRow(dof_index);
00195 mpPreconditionMatrixLinearSystem->SetMatrixElement(dof_index,dof_index,1);
00196 }
00197 mpLinearSystem->SetRhsVectorElement(dof_index, value);
00198 }
00199 }
00200 }
00201
00203 double CalculateResidualNorm()
00204 {
00205 double norm;
00206 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00207 norm = mpLinearSystem->GetRhsVectorNorm();
00208 #else
00209 VecNorm(mpLinearSystem->rGetRhsVector(), NORM_2, &norm);
00210 #endif
00211 return norm/mNumDofs;
00212 }
00213
00221 double TakeNewtonStep()
00222 {
00223
00224
00226
00228 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
00229 AssembleSystem(true, true);
00230 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
00231
00232
00233
00235
00236
00237
00238
00240 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::SOLVE);
00241
00242 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00243
00244 mpLinearSystem->Solve();
00245 Vector<double>& update = mpLinearSystem->rGetLhsVector();
00246
00247 #else
00248 KSP solver;
00249 Vec solution;
00250 VecDuplicate(mpLinearSystem->rGetRhsVector(),&solution);
00251
00252 Mat& r_jac = mpLinearSystem->rGetLhsMatrix();
00253 Mat& r_precond_jac = mpPreconditionMatrixLinearSystem->rGetLhsMatrix();
00254
00255 KSPCreate(MPI_COMM_SELF,&solver);
00256
00257 KSPSetOperators(solver, r_jac, r_precond_jac, SAME_NONZERO_PATTERN );
00258
00259
00260 KSPSetTolerances(solver, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 10000);
00261 KSPSetType(solver,KSPGMRES);
00262 KSPGMRESSetRestart(solver,100);
00263
00264 KSPSetFromOptions(solver);
00265 KSPSetUp(solver);
00266
00267 PC pc;
00268 KSPGetPC(solver, &pc);
00269 PCSetType(pc, PCLU);
00270
00271 KSPSetFromOptions(solver);
00272 KSPSolve(solver,mpLinearSystem->rGetRhsVector(),solution);
00273
00274
00275
00276 ReplicatableVector update(solution);
00277 #endif
00278 MechanicsEventHandler::EndEvent(MechanicsEventHandler::SOLVE);
00279
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00293 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::UPDATE);
00294 std::vector<double> old_solution(mNumDofs);
00295 for(unsigned i=0; i<mNumDofs; i++)
00296 {
00297 old_solution[i] = mCurrentSolution[i];
00298 }
00299
00300 std::vector<double> damping_values;
00301 for (unsigned i=10; i>=1; i--)
00302 {
00303 damping_values.push_back((double)i/10.0);
00304 }
00305 damping_values.push_back(0.05);
00306 assert(damping_values.size()==11);
00307
00308 double initial_norm_resid = CalculateResidualNorm();
00309 unsigned index = 0;
00310 for(unsigned j=0; j<mNumDofs; j++)
00311 {
00312 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00313 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update(j);
00314 #else
00315 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update[j];
00316 #endif
00317 }
00318
00319
00320 AssembleSystem(true, false);
00321 double norm_resid = CalculateResidualNorm();
00322 std::cout << "\tTesting s = " << damping_values[index] << ", |f| = " << norm_resid << "\n" << std::flush;
00323
00324 double next_norm_resid = -DBL_MAX;
00325 index = 1;
00326
00327
00328 while(next_norm_resid < norm_resid && index<damping_values.size())
00329 {
00330 if(index!=1)
00331 {
00332 norm_resid = next_norm_resid;
00333 }
00334
00335 for(unsigned j=0; j<mNumDofs; j++)
00336 {
00337 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00338 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update(j);
00339 #else
00340 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update[j];
00341 #endif
00342 }
00343
00344
00345 AssembleSystem(true, false);
00346 next_norm_resid = CalculateResidualNorm();
00347 std::cout << "\tTesting s = " << damping_values[index] << ", |f| = " << next_norm_resid << "\n" << std::flush;
00348 index++;
00349 }
00350
00351 if (initial_norm_resid < norm_resid)
00352 {
00353 #define COVERAGE_IGNORE
00354 assert(0);
00355 EXCEPTION("Residual does not appear to decrease in newton direction, quitting");
00356 #undef COVERAGE_IGNORE
00357 }
00358 else
00359 {
00360 index-=2;
00361 std::cout << "\tBest s = " << damping_values[index] << "\n" << std::flush;
00362 for(unsigned j=0; j<mNumDofs; j++)
00363 {
00364 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00365 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update(j);
00366 #else
00367 mCurrentSolution[j] = old_solution[j] - damping_values[index]*update[j];
00368 #endif
00369 }
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 MechanicsEventHandler::EndEvent(MechanicsEventHandler::UPDATE);
00431
00432
00433 #ifndef ___USE_DEALII_LINEAR_SYSTEM___
00434 VecDestroy(solution);
00435 KSPDestroy(solver);
00436 #endif
00437 return norm_resid;
00438 }
00439
00440
00445 virtual void PostNewtonStep(unsigned counter, double normResidual)
00446 {
00447 }
00448
00449 public:
00450 AbstractNonlinearElasticityAssembler(unsigned numDofs,
00451 AbstractIncompressibleMaterialLaw<DIM>* pMaterialLaw,
00452 c_vector<double,DIM> bodyForce,
00453 double density,
00454 std::string outputDirectory,
00455 std::vector<unsigned>& fixedNodes)
00456 : mNumDofs(numDofs),
00457 mBodyForce(bodyForce),
00458 mDensity(density),
00459 mOutputDirectory(outputDirectory),
00460 mFixedNodes(fixedNodes),
00461 mUsingBodyForceFunction(false),
00462 mUsingTractionBoundaryConditionFunction(false)
00463 {
00464 assert(pMaterialLaw != NULL);
00465 mMaterialLaws.push_back(pMaterialLaw);
00466
00467 assert(DIM==2 || DIM==3);
00468 assert(density > 0);
00469 assert(fixedNodes.size()>0);
00470 mWriteOutput = (mOutputDirectory != "");
00471
00472 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00474 //mpLinearSystem = new DealiiLinearSystem( mesh );
00475 #else
00476 mpLinearSystem = new LinearSystem(mNumDofs);
00477 #endif
00478 mpPreconditionMatrixLinearSystem = new LinearSystem(mNumDofs, (MatType)MATAIJ);
00479 }
00480
00481
00482 AbstractNonlinearElasticityAssembler(unsigned numDofs,
00483 std::vector<AbstractIncompressibleMaterialLaw<DIM>*>& rMaterialLaws,
00484 c_vector<double,DIM> bodyForce,
00485 double density,
00486 std::string outputDirectory,
00487 std::vector<unsigned>& fixedNodes)
00488 : mNumDofs(numDofs),
00489 mBodyForce(bodyForce),
00490 mDensity(density),
00491 mOutputDirectory(outputDirectory),
00492 mFixedNodes(fixedNodes),
00493 mUsingBodyForceFunction(false),
00494 mUsingTractionBoundaryConditionFunction(false)
00495 {
00496 mMaterialLaws.resize(rMaterialLaws.size(), NULL);
00497 for(unsigned i=0; i<mMaterialLaws.size(); i++)
00498 {
00499 assert(rMaterialLaws[i] != NULL);
00500 mMaterialLaws[i] = rMaterialLaws[i];
00501 }
00502
00503 assert(DIM==2 || DIM==3);
00504 assert(density > 0);
00505 assert(fixedNodes.size()>0);
00506 mWriteOutput = (mOutputDirectory != "");
00507
00508 #ifdef ___USE_DEALII_LINEAR_SYSTEM___
00510 //mpLinearSystem = new DealiiLinearSystem( mesh );
00511 #else
00512 mpLinearSystem = new LinearSystem(mNumDofs);
00513 #endif
00514 mpPreconditionMatrixLinearSystem = new LinearSystem(mNumDofs, (MatType)MATAIJ);
00515 }
00516
00517
00518 virtual ~AbstractNonlinearElasticityAssembler()
00519 {
00520 delete mpLinearSystem;
00521 delete mpPreconditionMatrixLinearSystem;
00522 }
00523
00524
00528 void Solve(double tol = -1.0,
00529 unsigned offset=0,
00530 unsigned maxNumNewtonIterations=INT_MAX,
00531 bool quitIfNoConvergence=true)
00532 {
00533 if(mWriteOutput)
00534 {
00535 WriteOutput(0+offset);
00536 }
00537
00538
00539 AssembleSystem(true, false);
00540 double norm_resid = this->CalculateResidualNorm();
00541 std::cout << "\nNorm of residual is " << norm_resid << "\n";
00542
00543 mNumNewtonIterations = 0;
00544 unsigned counter = 1;
00545
00546 if(tol<0)
00547 {
00548 tol = NEWTON_REL_TOL*norm_resid;
00549
00550 #define COVERAGE_IGNORE // not going to have tests in cts for everything
00551 if(tol > MAX_NEWTON_ABS_TOL)
00552 {
00553 tol = MAX_NEWTON_ABS_TOL;
00554 }
00555 if(tol < MIN_NEWTON_ABS_TOL)
00556 {
00557 tol = MIN_NEWTON_ABS_TOL;
00558 }
00559 #undef COVERAGE_IGNORE
00560 }
00561
00562 std::cout << "Solving with tolerance " << tol << "\n";
00563
00564 while (norm_resid > tol && counter<=maxNumNewtonIterations)
00565 {
00566 std::cout << "\n-------------------\n"
00567 << "Newton iteration " << counter
00568 << ":\n-------------------\n";
00569
00570
00571 norm_resid = TakeNewtonStep();
00572
00573 std::cout << "Norm of residual is " << norm_resid << "\n";
00574 if(mWriteOutput)
00575 {
00576 WriteOutput(counter+offset);
00577 }
00578
00579 mNumNewtonIterations = counter;
00580
00581 PostNewtonStep(counter,norm_resid);
00582
00583 counter++;
00584 if (counter==20)
00585 {
00586 #define COVERAGE_IGNORE
00587 EXCEPTION("Not converged after 20 newton iterations, quitting");
00588 #undef COVERAGE_IGNORE
00589 }
00590 }
00591
00592 if ((norm_resid > tol) && quitIfNoConvergence)
00593 {
00594 #define COVERAGE_IGNORE
00595 EXCEPTION("Failed to converge");
00596 #undef COVERAGE_IGNORE
00597 }
00598
00599
00600
00601 }
00602
00603
00604
00608 void WriteOutput(unsigned counter)
00609 {
00610
00611 if (!mWriteOutput)
00612 {
00613 return;
00614 }
00615
00616 OutputFileHandler output_file_handler(mOutputDirectory, (counter==0));
00617 std::stringstream file_name;
00618 file_name << "/solution_" << counter << ".nodes";
00619
00620 out_stream p_file = output_file_handler.OpenOutputFile(file_name.str());
00621
00622 std::vector<c_vector<double,DIM> >& r_deformed_position = rGetDeformedPosition();
00623 for(unsigned i=0; i<r_deformed_position.size(); i++)
00624 {
00625 for(unsigned j=0; j<DIM; j++)
00626 {
00627 *p_file << r_deformed_position[i](j) << " ";
00628 }
00629 *p_file << "\n";
00630 }
00631 p_file->close();
00632 }
00633
00634 unsigned GetNumNewtonIterations()
00635 {
00636 return mNumNewtonIterations;
00637 }
00638
00643 void SetFunctionalBodyForce(c_vector<double,DIM> (*pFunction)(c_vector<double,DIM>&))
00644 {
00645 mUsingBodyForceFunction = true;
00646 mpBodyForceFunction = pFunction;
00647 }
00648
00649 void SetWriteOutput(bool writeOutput = true)
00650 {
00651 if(writeOutput && (mOutputDirectory==""))
00652 {
00653 EXCEPTION("Can't write output if no output directory was given in constructor");
00654 }
00655 mWriteOutput = writeOutput;
00656 }
00657 };
00658
00659 #endif