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
00030
00031
00032
00033
00034
00035
00036 #include "CardiacElectroMechanicsProblem.hpp"
00037
00038 #include "OutputFileHandler.hpp"
00039 #include "ReplicatableVector.hpp"
00040 #include "HeartConfig.hpp"
00041 #include "LogFile.hpp"
00042 #include "ChastePoint.hpp"
00043 #include "Element.hpp"
00044 #include "BoundaryConditionsContainer.hpp"
00045 #include "AbstractDynamicLinearPdeSolver.hpp"
00046 #include "TimeStepper.hpp"
00047 #include "TrianglesMeshWriter.hpp"
00048 #include "Hdf5ToMeshalyzerConverter.hpp"
00049 #include "Hdf5ToCmguiConverter.hpp"
00050 #include "MeshalyzerMeshWriter.hpp"
00051 #include "PetscTools.hpp"
00052 #include "ImplicitCardiacMechanicsSolver.hpp"
00053 #include "ExplicitCardiacMechanicsSolver.hpp"
00054 #include "CmguiDeformedSolutionsWriter.hpp"
00055 #include "VoltageInterpolaterOntoMechanicsMesh.hpp"
00056 #include "BidomainProblem.hpp"
00057
00058
00059 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00060 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::DetermineWatchedNodes()
00061 {
00062 assert(mIsWatchedLocation);
00063
00064
00065 double min_dist = DBL_MAX;
00066 unsigned node_index = UNSIGNED_UNSET;
00067 for(unsigned i=0; i<mpElectricsMesh->GetNumNodes(); i++)
00068 {
00069 double dist = norm_2(mWatchedLocation - mpElectricsMesh->GetNode(i)->rGetLocation());
00070 if(dist < min_dist)
00071 {
00072 min_dist = dist;
00073 node_index = i;
00074 }
00075 }
00076
00077
00078 assert(node_index != UNSIGNED_UNSET);
00079 c_vector<double,DIM> pos = mpElectricsMesh->GetNode(node_index)->rGetLocation();
00080
00081 if(min_dist > 1e-8)
00082 {
00083 #define COVERAGE_IGNORE
00084 std::cout << "ERROR: Could not find an electrics node very close to requested watched location - "
00085 << "min distance was " << min_dist << " for node " << node_index
00086 << " at location " << pos << std::flush;;
00087
00089
00090 NEVER_REACHED;
00091 #undef COVERAGE_IGNORE
00092 }
00093 else
00094 {
00095 LOG(2,"Chosen electrics node "<<node_index<<" at location " << pos << " to be watched");
00096 mWatchedElectricsNodeIndex = node_index;
00097 }
00098
00099
00100 min_dist = DBL_MAX;
00101 node_index = UNSIGNED_UNSET;
00102 c_vector<double,DIM> pos_at_min;
00103
00104 for(unsigned i=0; i<mpMechanicsMesh->GetNumNodes(); i++)
00105 {
00106 c_vector<double,DIM> position = mpMechanicsMesh->GetNode(i)->rGetLocation();
00107
00108 double dist = norm_2(position-mWatchedLocation);
00109
00110 if(dist < min_dist)
00111 {
00112 min_dist = dist;
00113 node_index = i;
00114 pos_at_min = position;
00115 }
00116 }
00117
00118
00119 assert(node_index != UNSIGNED_UNSET);
00120
00121 if(min_dist > 1e-8)
00122 {
00123 #define COVERAGE_IGNORE
00124 std::cout << "ERROR: Could not find a mechanics node very close to requested watched location - "
00125 << "min distance was " << min_dist << " for node " << node_index
00126 << " at location " << pos_at_min;
00127
00129
00130 NEVER_REACHED;
00131 #undef COVERAGE_IGNORE
00132 }
00133 else
00134 {
00135 LOG(2,"Chosen mechanics node "<<node_index<<" at location " << pos << " to be watched");
00136 mWatchedMechanicsNodeIndex = node_index;
00137 }
00138
00139 OutputFileHandler handler(mOutputDirectory,false);
00140 mpWatchedLocationFile = handler.OpenOutputFile("watched.txt");
00141 }
00142
00143 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00144 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::WriteWatchedLocationData(double time, Vec voltage)
00145 {
00146 assert(mIsWatchedLocation);
00147
00148 std::vector<c_vector<double,DIM> >& deformed_position = mpMechanicsSolver->rGetDeformedPosition();
00149
00151 ReplicatableVector voltage_replicated(voltage);
00152 double V = voltage_replicated[mWatchedElectricsNodeIndex];
00153
00156
00157
00158
00159 *mpWatchedLocationFile << time << " ";
00160 for(unsigned i=0; i<DIM; i++)
00161 {
00162 *mpWatchedLocationFile << deformed_position[mWatchedMechanicsNodeIndex](i) << " ";
00163 }
00164 *mpWatchedLocationFile << V << "\n";
00165 mpWatchedLocationFile->flush();
00166 }
00167
00168 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00169 c_matrix<double,DIM,DIM>& CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::rCalculateModifiedConductivityTensor(unsigned elementIndex, const c_matrix<double,DIM,DIM>& rOriginalConductivity, unsigned domainIndex)
00170 {
00171
00172
00173 unsigned containing_mechanics_elem = mpMeshPair->rGetCoarseElementsForFineElementCentroids()[elementIndex];
00174 c_matrix<double,DIM,DIM>& r_deformation_gradient = mDeformationGradientsForEachMechanicsElement[containing_mechanics_elem];
00175
00176
00177 c_matrix<double,DIM,DIM> inv_F = Inverse(r_deformation_gradient);
00178 mModifiedConductivityTensor = prod(inv_F, rOriginalConductivity);
00179 mModifiedConductivityTensor = prod(mModifiedConductivityTensor, trans(inv_F));
00180
00181 return mModifiedConductivityTensor;
00182 }
00183
00184
00188 template<unsigned DIM, unsigned PROBLEM_DIM>
00189 class CreateElectricsProblem
00190 {
00191 public:
00198 static AbstractCardiacProblem<DIM, DIM, PROBLEM_DIM>* Create(ElectricsProblemType problemType,
00199 AbstractCardiacCellFactory<DIM>* pCellFactory);
00200 };
00201
00205 template<unsigned DIM>
00206 class CreateElectricsProblem<DIM, 1u>
00207 {
00208 public:
00215 static AbstractCardiacProblem<DIM, DIM, 1u>* Create(ElectricsProblemType problemType,
00216 AbstractCardiacCellFactory<DIM>* pCellFactory)
00217 {
00218 if (problemType == MONODOMAIN)
00219 {
00220 return new MonodomainProblem<DIM>(pCellFactory);
00221 }
00222 EXCEPTION("The second template parameter should be 2 when a bidomain problem is chosen");
00223 }
00224 };
00225
00229 template<unsigned DIM>
00230 class CreateElectricsProblem<DIM, 2u>
00231 {
00232 public:
00239 static AbstractCardiacProblem<DIM, DIM, 2u>* Create(ElectricsProblemType problemType,
00240 AbstractCardiacCellFactory<DIM>* pCellFactory)
00241 {
00242 if (problemType == BIDOMAIN)
00243 {
00244 return new BidomainProblem<DIM>(pCellFactory, false);
00245 }
00246 if (problemType == BIDOMAIN_WITH_BATH)
00247 {
00248 return new BidomainProblem<DIM>(pCellFactory, true);
00249 }
00250 EXCEPTION("The second template parameter should be 1 when a monodomain problem is chosen");
00251 }
00252 };
00253
00254
00255 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00256 CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::CardiacElectroMechanicsProblem(
00257 CompressibilityType compressibilityType,
00258 ElectricsProblemType electricsProblemType,
00259 TetrahedralMesh<DIM,DIM>* pElectricsMesh,
00260 QuadraticMesh<DIM>* pMechanicsMesh,
00261 AbstractCardiacCellFactory<DIM>* pCellFactory,
00262 ElectroMechanicsProblemDefinition<DIM>* pProblemDefinition,
00263 std::string outputDirectory)
00264 : mCompressibilityType(compressibilityType),
00265 mpCardiacMechSolver(NULL),
00266 mpMechanicsSolver(NULL),
00267 mpElectricsMesh(pElectricsMesh),
00268 mpMechanicsMesh(pMechanicsMesh),
00269 mpProblemDefinition(pProblemDefinition),
00270 mHasBath(false),
00271 mpMeshPair(NULL),
00272 mNoElectricsOutput(false),
00273 mIsWatchedLocation(false),
00274 mWatchedElectricsNodeIndex(UNSIGNED_UNSET),
00275 mWatchedMechanicsNodeIndex(UNSIGNED_UNSET),
00276 mNumTimestepsToOutputDeformationGradientsAndStress(UNSIGNED_UNSET)
00277 {
00278
00279
00280
00281
00282
00283
00284
00285
00286 MechanicsEventHandler::Reset();
00287 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ALL);
00288
00289
00290
00291
00292 HeartEventHandler::Disable();
00293
00294 assert(HeartConfig::Instance()->GetSimulationDuration()>0.0);
00295 assert(HeartConfig::Instance()->GetPdeTimeStep()>0.0);
00296
00297
00298
00299
00300 assert(pCellFactory != NULL);
00301 mpElectricsProblem = CreateElectricsProblem<DIM,ELEC_PROB_DIM>::Create(electricsProblemType, pCellFactory);
00302
00303 if (electricsProblemType == BIDOMAIN_WITH_BATH)
00304 {
00305 mHasBath = true;
00306 }
00307
00308 mWriteOutput = (outputDirectory!="");
00309 if(mWriteOutput)
00310 {
00311 mOutputDirectory = outputDirectory;
00312
00313 OutputFileHandler handler(mOutputDirectory);
00314 mDeformationOutputDirectory = mOutputDirectory + "/deformation";
00315 HeartConfig::Instance()->SetOutputDirectory(mOutputDirectory + "/electrics");
00316 HeartConfig::Instance()->SetOutputFilenamePrefix("voltage");
00317 }
00318 else
00319 {
00320 mDeformationOutputDirectory = "";
00321 }
00322
00323
00324 }
00325
00326 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00327 CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::~CardiacElectroMechanicsProblem()
00328 {
00329
00330
00331
00332 if(mIsWatchedLocation && mpMechanicsMesh)
00333 {
00334 mpWatchedLocationFile->close();
00335 }
00336
00337 delete mpElectricsProblem;
00338 delete mpCardiacMechSolver;
00339 delete mpMeshPair;
00340
00341 LogFile::Close();
00342 }
00343
00344 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00345 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::Initialise()
00346 {
00347 assert(mpElectricsMesh!=NULL);
00348 assert(mpMechanicsMesh!=NULL);
00349 assert(mpProblemDefinition!=NULL);
00350 assert(mpCardiacMechSolver==NULL);
00351
00354 mNumElecTimestepsPerMechTimestep = (unsigned) floor((mpProblemDefinition->GetMechanicsSolveTimestep()/HeartConfig::Instance()->GetPdeTimeStep())+0.5);
00355 if(fabs(mNumElecTimestepsPerMechTimestep*HeartConfig::Instance()->GetPdeTimeStep() - mpProblemDefinition->GetMechanicsSolveTimestep()) > 1e-6)
00356 {
00357 EXCEPTION("Electrics PDE timestep does not divide mechanics solve timestep");
00358 }
00359
00360
00361
00362 std::string log_dir = mOutputDirectory;
00363 LogFile::Instance()->Set(2, mOutputDirectory);
00364 LogFile::Instance()->WriteHeader("Electromechanics");
00365 LOG(2, DIM << "d Implicit CardiacElectroMechanics Simulation:");
00366 LOG(2, "End time = " << HeartConfig::Instance()->GetSimulationDuration() << ", electrics time step = " << HeartConfig::Instance()->GetPdeTimeStep() << ", mechanics timestep = " << mpProblemDefinition->GetMechanicsSolveTimestep() << "\n");
00367 LOG(2, "Contraction model ode timestep " << mpProblemDefinition->GetContractionModelOdeTimestep());
00368 LOG(2, "Output is written to " << mOutputDirectory << "/[deformation/electrics]");
00369
00370 LOG(2, "Electrics mesh has " << mpElectricsMesh->GetNumNodes() << " nodes");
00371 LOG(2, "Mechanics mesh has " << mpMechanicsMesh->GetNumNodes() << " nodes");
00372
00373 LOG(2, "Initialising..");
00374
00375
00376 if(mIsWatchedLocation)
00377 {
00378 DetermineWatchedNodes();
00379 }
00380
00381
00382 mpElectricsProblem->SetMesh(mpElectricsMesh);
00383 mpElectricsProblem->Initialise();
00384
00385 if(mCompressibilityType==INCOMPRESSIBLE)
00386 {
00387 switch(mpProblemDefinition->GetSolverType())
00388 {
00389 case EXPLICIT:
00390 mpCardiacMechSolver = new ExplicitCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<DIM>,DIM>(
00391 *mpMechanicsMesh,*mpProblemDefinition,mDeformationOutputDirectory);
00392 break;
00393 case IMPLICIT:
00394 mpCardiacMechSolver = new ImplicitCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<DIM>,DIM>(
00395 *mpMechanicsMesh,*mpProblemDefinition,mDeformationOutputDirectory);
00396 break;
00397 default:
00398 NEVER_REACHED;
00399 }
00400 }
00401 else
00402 {
00403
00404
00405 switch(mpProblemDefinition->GetSolverType())
00406 {
00407 case EXPLICIT:
00408 mpCardiacMechSolver = new ExplicitCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<DIM>,DIM>(
00409 *mpMechanicsMesh,*mpProblemDefinition,mDeformationOutputDirectory);
00410 break;
00411 case IMPLICIT:
00412 mpCardiacMechSolver = new ImplicitCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<DIM>,DIM>(
00413 *mpMechanicsMesh,*mpProblemDefinition,mDeformationOutputDirectory);
00414 break;
00415 default:
00416 NEVER_REACHED;
00417 }
00418 }
00419
00420
00421 mpMechanicsSolver = dynamic_cast<AbstractNonlinearElasticitySolver<DIM>*>(mpCardiacMechSolver);
00422 assert(mpMechanicsSolver);
00423
00424
00425
00426 mpMeshPair = new FineCoarseMeshPair<DIM>(*mpElectricsMesh, *mpMechanicsMesh);
00427 mpMeshPair->SetUpBoxesOnFineMesh();
00428 mpMeshPair->ComputeFineElementsAndWeightsForCoarseQuadPoints(*(mpCardiacMechSolver->GetQuadratureRule()), false);
00429 mpMeshPair->DeleteFineBoxCollection();
00430
00431 mpCardiacMechSolver->SetFineCoarseMeshPair(mpMeshPair);
00432 mpCardiacMechSolver->Initialise();
00433
00434 unsigned num_quad_points = mpCardiacMechSolver->GetTotalNumQuadPoints();
00435 mInterpolatedCalciumConcs.assign(num_quad_points, 0.0);
00436 mInterpolatedVoltages.assign(num_quad_points, 0.0);
00437
00438 if(mpProblemDefinition->ReadFibreSheetDirectionsFromFile())
00439 {
00440 mpCardiacMechSolver->SetVariableFibreSheetDirections(mpProblemDefinition->GetFibreSheetDirectionsFile(),
00441 mpProblemDefinition->GetFibreSheetDirectionsDefinedPerQuadraturePoint());
00442 }
00443
00444
00445 if(mpProblemDefinition->GetDeformationAffectsConductivity() || mpProblemDefinition->GetDeformationAffectsCellModels())
00446 {
00447 mpMeshPair->SetUpBoxesOnCoarseMesh();
00448 }
00449
00450
00451 if(mpProblemDefinition->GetDeformationAffectsCellModels() || mpProblemDefinition->GetDeformationAffectsConductivity())
00452 {
00453
00454 mStretchesForEachMechanicsElement.resize(mpMechanicsMesh->GetNumElements(), 1.0);
00455
00456
00457 mDeformationGradientsForEachMechanicsElement.resize(mpMechanicsMesh->GetNumElements(),identity_matrix<double>(DIM));
00458 }
00459
00460
00461 if(mpProblemDefinition->GetDeformationAffectsCellModels())
00462 {
00463
00464
00465 mpMeshPair->ComputeCoarseElementsForFineNodes(false);
00466
00467 }
00468
00469 if(mpProblemDefinition->GetDeformationAffectsConductivity())
00470 {
00471
00472
00473 mpMeshPair->ComputeCoarseElementsForFineElementCentroids(false);
00474
00475
00476
00477 mpElectricsProblem->GetTissue()->SetConductivityModifier(this);
00478 }
00479
00480 if(mWriteOutput)
00481 {
00482 TrianglesMeshWriter<DIM,DIM> mesh_writer(mOutputDirectory,"electrics_mesh",false);
00483 mesh_writer.WriteFilesUsingMesh(*mpElectricsMesh);
00484 }
00485 }
00486
00487 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00488 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::Solve()
00489 {
00490
00491 if(mpCardiacMechSolver==NULL)
00492 {
00493 Initialise();
00494 }
00495
00496 bool verbose_during_solve = ( mpProblemDefinition->GetVerboseDuringSolve()
00497 || CommandLineArguments::Instance()->OptionExists("-mech_verbose")
00498 || CommandLineArguments::Instance()->OptionExists("-mech_very_verbose"));
00499
00500
00501 mpProblemDefinition->Validate();
00502
00503 boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,ELEC_PROB_DIM> > p_bcc(new BoundaryConditionsContainer<DIM,DIM,ELEC_PROB_DIM>);
00504 p_bcc->DefineZeroNeumannOnMeshBoundary(mpElectricsMesh, 0);
00505 mpElectricsProblem->SetBoundaryConditionsContainer(p_bcc);
00506
00507
00508
00509 AbstractDynamicLinearPdeSolver<DIM,DIM,ELEC_PROB_DIM>* p_electrics_solver
00510 = mpElectricsProblem->CreateSolver();
00511
00512
00513 Vec electrics_solution=NULL;
00514 Vec calcium_data= mpElectricsMesh->GetDistributedVectorFactory()->CreateVec();
00515 Vec initial_voltage = mpElectricsProblem->CreateInitialCondition();
00516
00517
00518 unsigned counter = 0;
00519
00520 TimeStepper stepper(0.0, HeartConfig::Instance()->GetSimulationDuration(), mpProblemDefinition->GetMechanicsSolveTimestep());
00521
00522 CmguiDeformedSolutionsWriter<DIM>* p_cmgui_writer = NULL;
00523
00524 std::vector<std::string> variable_names;
00525
00526 if (mWriteOutput)
00527 {
00528 mpMechanicsSolver->SetWriteOutput();
00529 mpMechanicsSolver->WriteCurrentSpatialSolution("undeformed","nodes");
00530
00531 p_cmgui_writer = new CmguiDeformedSolutionsWriter<DIM>(mOutputDirectory+"/deformation/cmgui",
00532 "solution",
00533 *(this->mpMechanicsMesh),
00534 WRITE_QUADRATIC_MESH);
00535 variable_names.push_back("V");
00536 if(ELEC_PROB_DIM==2)
00537 {
00538 variable_names.push_back("Phi_e");
00539 if (mHasBath==true)
00540 {
00541 std::vector<std::string> regions;
00542 regions.push_back("tissue");
00543 regions.push_back("bath");
00544 p_cmgui_writer->SetRegionNames(regions);
00545 }
00546 }
00547 p_cmgui_writer->SetAdditionalFieldNames(variable_names);
00548 p_cmgui_writer->WriteInitialMesh("undeformed");
00549 }
00550
00557
00558 LOG(2, "\nSolving for initial deformation");
00559 #define COVERAGE_IGNORE
00560 if(verbose_during_solve)
00561 {
00562 std::cout << "\n\n ** Solving for initial deformation\n";
00563 }
00564 #undef COVERAGE_IGNORE
00565
00566 mpMechanicsSolver->SetWriteOutput(false);
00567
00568 mpMechanicsSolver->SetCurrentTime(0.0);
00569 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ALL_MECH);
00570
00571 mpMechanicsSolver->SetIncludeActiveTension(false);
00572 if(mNumTimestepsToOutputDeformationGradientsAndStress!=UNSIGNED_UNSET)
00573 {
00574 mpMechanicsSolver->SetComputeAverageStressPerElementDuringSolve(true);
00575 }
00576
00577 unsigned total_newton_iters = 0;
00578 for(unsigned index=1; index<=mpProblemDefinition->GetNumIncrementsForInitialDeformation(); index++)
00579 {
00580 #define COVERAGE_IGNORE
00581 if(verbose_during_solve)
00582 {
00583 std::cout << " Increment " << index << " of " << mpProblemDefinition->GetNumIncrementsForInitialDeformation() << "\n";
00584 }
00585 #undef COVERAGE_IGNORE
00586
00587 if(mpProblemDefinition->GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED)
00588 {
00589 mpProblemDefinition->SetPressureScaling(((double)index)/mpProblemDefinition->GetNumIncrementsForInitialDeformation());
00590 }
00591 mpMechanicsSolver->Solve();
00592
00593 total_newton_iters += mpMechanicsSolver->GetNumNewtonIterations();
00594 }
00595
00596 mpMechanicsSolver->SetIncludeActiveTension(true);
00597 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ALL_MECH);
00598 LOG(2, " Number of newton iterations = " << total_newton_iters);
00599
00600
00601 unsigned mech_writer_counter = 0;
00602
00603 if (mWriteOutput)
00604 {
00605 LOG(2, " Writing output");
00606 mpMechanicsSolver->SetWriteOutput();
00607 mpMechanicsSolver->WriteCurrentSpatialSolution("solution","nodes",mech_writer_counter);
00608 p_cmgui_writer->WriteDeformationPositions(rGetDeformedPosition(), mech_writer_counter);
00609
00610 if(!mNoElectricsOutput)
00611 {
00612
00613
00614
00615 HeartConfig::Instance()->SetPrintingTimeStep(mpProblemDefinition->GetMechanicsSolveTimestep());
00616
00617
00618
00619
00620 mpElectricsProblem->InitialiseWriter();
00621 mpElectricsProblem->WriteOneStep(stepper.GetTime(), initial_voltage);
00622 }
00623
00624 if(mIsWatchedLocation)
00625 {
00626 WriteWatchedLocationData(stepper.GetTime(), initial_voltage);
00627 }
00628
00629 if(mNumTimestepsToOutputDeformationGradientsAndStress!=UNSIGNED_UNSET)
00630 {
00631 mpMechanicsSolver->WriteCurrentStrains(DEFORMATION_GRADIENT_F,"deformation_gradient",mech_writer_counter);
00632 mpMechanicsSolver->WriteCurrentAverageElementStresses("second_PK",mech_writer_counter);
00633 }
00634 }
00635
00636
00637 PrepareForSolve();
00638
00642
00643
00644
00645
00646
00647
00648 mpMechanicsSolver->SetComputeAverageStressPerElementDuringSolve(false);
00649
00650 while (!stepper.IsTimeAtEnd())
00651 {
00652 LOG(2, "\nCurrent time = " << stepper.GetTime());
00653 #define COVERAGE_IGNORE
00654 if(verbose_during_solve)
00655 {
00656
00657 std::cout << "\n\n ** Current time = " << stepper.GetTime() << "\n";
00658 }
00659 #undef COVERAGE_IGNORE
00660
00667 if(mpProblemDefinition->GetDeformationAffectsCellModels() || mpProblemDefinition->GetDeformationAffectsConductivity())
00668 {
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 mpCardiacMechSolver->ComputeDeformationGradientAndStretchInEachElement(mDeformationGradientsForEachMechanicsElement, mStretchesForEachMechanicsElement);
00681 }
00682
00683 if( mpProblemDefinition->GetDeformationAffectsCellModels() )
00684 {
00685
00686 for(unsigned global_index = mpElectricsMesh->GetDistributedVectorFactory()->GetLow();
00687 global_index < mpElectricsMesh->GetDistributedVectorFactory()->GetHigh();
00688 global_index++)
00689 {
00690 unsigned containing_elem = mpMeshPair->rGetCoarseElementsForFineNodes()[global_index];
00691 double stretch = mStretchesForEachMechanicsElement[containing_elem];
00692 mpElectricsProblem->GetTissue()->GetCardiacCell(global_index)->SetStretch(stretch);
00693 }
00694 }
00695
00696 p_electrics_solver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00697
00703 LOG(2, " Solving electrics");
00704 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::NON_MECH);
00705 for(unsigned i=0; i<mNumElecTimestepsPerMechTimestep; i++)
00706 {
00707 double current_time = stepper.GetTime() + i*HeartConfig::Instance()->GetPdeTimeStep();
00708 double next_time = stepper.GetTime() + (i+1)*HeartConfig::Instance()->GetPdeTimeStep();
00709
00710
00711 p_electrics_solver->SetTimes(current_time, next_time);
00712 p_electrics_solver->SetInitialCondition( initial_voltage );
00713
00714 electrics_solution = p_electrics_solver->Solve();
00715
00716 PetscReal min_voltage, max_voltage;
00717 VecMax(electrics_solution,PETSC_NULL,&max_voltage);
00718 VecMin(electrics_solution,PETSC_NULL,&min_voltage);
00719 if(i==0)
00720 {
00721 LOG(2, " minimum and maximum voltage is " << min_voltage <<", "<<max_voltage);
00722 }
00723 else if(i==1)
00724 {
00725 LOG(2, " ..");
00726 }
00727
00728 PetscTools::Destroy(initial_voltage);
00729 initial_voltage = electrics_solution;
00730 }
00731
00732 if(mpProblemDefinition->GetDeformationAffectsConductivity())
00733 {
00734 p_electrics_solver->SetMatrixIsNotAssembled();
00735 }
00736
00737
00743
00744
00745
00746 LOG(2, " Interpolating Ca_I and voltage");
00747
00748
00749 for(unsigned node_index = 0; node_index<mpElectricsMesh->GetNumNodes(); node_index++)
00750 {
00751 if (mpElectricsMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index))
00752 {
00753 double calcium_value = mpElectricsProblem->GetTissue()->GetCardiacCell(node_index)->GetIntracellularCalciumConcentration();
00754 VecSetValue(calcium_data, node_index ,calcium_value, INSERT_VALUES);
00755 }
00756 }
00757 PetscTools::Barrier();
00758
00759
00760 ReplicatableVector electrics_solution_repl(electrics_solution);
00761 ReplicatableVector calcium_repl(calcium_data);
00762
00763
00764 for(unsigned i=0; i<mpMeshPair->rGetElementsAndWeights().size(); i++)
00765 {
00766 double interpolated_CaI = 0;
00767 double interpolated_voltage = 0;
00768
00769 Element<DIM,DIM>& element = *(mpElectricsMesh->GetElement(mpMeshPair->rGetElementsAndWeights()[i].ElementNum));
00770
00771 for(unsigned node_index = 0; node_index<element.GetNumNodes(); node_index++)
00772 {
00773 unsigned global_index = element.GetNodeGlobalIndex(node_index);
00774 double CaI_at_node = calcium_repl[global_index];
00775 interpolated_CaI += CaI_at_node*mpMeshPair->rGetElementsAndWeights()[i].Weights(node_index);
00776
00777 interpolated_voltage += electrics_solution_repl[global_index*ELEC_PROB_DIM]*mpMeshPair->rGetElementsAndWeights()[i].Weights(node_index);
00778 }
00779
00780 assert(i<mInterpolatedCalciumConcs.size());
00781 assert(i<mInterpolatedVoltages.size());
00782 mInterpolatedCalciumConcs[i] = interpolated_CaI;
00783 mInterpolatedVoltages[i] = interpolated_voltage;
00784 }
00785
00786 LOG(2, " Setting Ca_I. max value = " << Max(mInterpolatedCalciumConcs));
00787
00788
00789
00790
00791
00792 mpCardiacMechSolver->SetCalciumAndVoltage(mInterpolatedCalciumConcs, mInterpolatedVoltages);
00793 MechanicsEventHandler::EndEvent(MechanicsEventHandler::NON_MECH);
00794
00795
00801 LOG(2, " Solving mechanics ");
00802 mpMechanicsSolver->SetWriteOutput(false);
00803
00804
00805
00806 mpMechanicsSolver->SetCurrentTime(stepper.GetTime());
00807
00808
00809 if( mNumTimestepsToOutputDeformationGradientsAndStress!=UNSIGNED_UNSET
00810 && (counter+1)%mNumTimestepsToOutputDeformationGradientsAndStress == 0 )
00811 {
00812 mpMechanicsSolver->SetComputeAverageStressPerElementDuringSolve(true);
00813 }
00814
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ALL_MECH);
00835 mpCardiacMechSolver->Solve(stepper.GetTime(), stepper.GetNextTime(), mpProblemDefinition->GetContractionModelOdeTimestep());
00836 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ALL_MECH);
00837
00838 LOG(2, " Number of newton iterations = " << mpMechanicsSolver->GetNumNewtonIterations());
00839
00840
00841 stepper.AdvanceOneTimeStep();
00842 counter++;
00843
00844
00850 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::OUTPUT);
00851 if(mWriteOutput && (counter%WRITE_EVERY_NTH_TIME==0))
00852 {
00853 LOG(2, " Writing output");
00854
00855 mech_writer_counter++;
00856 mpMechanicsSolver->SetWriteOutput();
00857 mpMechanicsSolver->WriteCurrentSpatialSolution("solution","nodes",mech_writer_counter);
00858
00859 p_cmgui_writer->WriteDeformationPositions(rGetDeformedPosition(), counter);
00860
00861 if(!mNoElectricsOutput)
00862 {
00863 mpElectricsProblem->mpWriter->AdvanceAlongUnlimitedDimension();
00864 mpElectricsProblem->WriteOneStep(stepper.GetTime(), electrics_solution);
00865 }
00866
00867 if(mIsWatchedLocation)
00868 {
00869 WriteWatchedLocationData(stepper.GetTime(), electrics_solution);
00870 }
00871 OnEndOfTimeStep(counter);
00872
00873 if(mNumTimestepsToOutputDeformationGradientsAndStress!=UNSIGNED_UNSET && counter%mNumTimestepsToOutputDeformationGradientsAndStress==0)
00874 {
00875 mpMechanicsSolver->WriteCurrentStrains(DEFORMATION_GRADIENT_F,"deformation_gradient",mech_writer_counter);
00876 mpMechanicsSolver->WriteCurrentAverageElementStresses("second_PK",mech_writer_counter);
00877 }
00878 mpMechanicsSolver->SetComputeAverageStressPerElementDuringSolve(false);
00879 }
00880 MechanicsEventHandler::EndEvent(MechanicsEventHandler::OUTPUT);
00881
00882
00883 LogFile::Instance()->WriteElapsedTime(" ");
00884 }
00885
00886
00887
00888 if ((mWriteOutput) && (!mNoElectricsOutput))
00889 {
00890 HeartConfig::Instance()->Reset();
00891 mpElectricsProblem->mpWriter->Close();
00892 delete mpElectricsProblem->mpWriter;
00893
00894 std::string input_dir = mOutputDirectory+"/electrics";
00895
00896
00897 std::string config_directory = HeartConfig::Instance()->GetOutputDirectory();
00898 HeartConfig::Instance()->SetOutputDirectory(input_dir);
00899
00900
00901
00902
00903
00904
00905
00906 Hdf5ToCmguiConverter<DIM,DIM> cmgui_converter(FileFinder(input_dir, RelativeTo::ChasteTestOutput),
00907 "voltage", mpElectricsMesh, mHasBath,
00908 HeartConfig::Instance()->GetVisualizerOutputPrecision());
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922 VoltageInterpolaterOntoMechanicsMesh<DIM> converter(*mpElectricsMesh,*mpMechanicsMesh,variable_names,input_dir,"voltage");
00923
00924
00925 HeartConfig::Instance()->SetOutputDirectory(config_directory);
00926 }
00927
00928 if(p_cmgui_writer)
00929 {
00930 if(mNoElectricsOutput)
00931 {
00932 p_cmgui_writer->WriteCmguiScript("","undeformed");
00933 }
00934 else
00935 {
00936 p_cmgui_writer->WriteCmguiScript("../../electrics/cmgui_output/voltage_mechanics_mesh","undeformed");
00937 }
00938 delete p_cmgui_writer;
00939 }
00940 PetscTools::Destroy(electrics_solution);
00941 PetscTools::Destroy(calcium_data);
00942 delete p_electrics_solver;
00943
00944 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ALL);
00945 }
00946
00947
00948
00949 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00950 double CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::Max(std::vector<double>& vec)
00951 {
00952 double max = -1e200;
00953 for(unsigned i=0; i<vec.size(); i++)
00954 {
00955 if(vec[i]>max) max=vec[i];
00956 }
00957 return max;
00958 }
00959
00960 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00961 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::SetNoElectricsOutput()
00962 {
00963 mNoElectricsOutput = true;
00964 }
00965
00966 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00967 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::SetWatchedPosition(c_vector<double,DIM> watchedLocation)
00968 {
00969 mIsWatchedLocation = true;
00970 mWatchedLocation = watchedLocation;
00971 }
00972
00973 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00974 void CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::SetOutputDeformationGradientsAndStress(double timeStep)
00975 {
00976 mNumTimestepsToOutputDeformationGradientsAndStress = (unsigned) floor((timeStep/mpProblemDefinition->GetMechanicsSolveTimestep())+0.5);
00977 if(fabs(mNumTimestepsToOutputDeformationGradientsAndStress*mpProblemDefinition->GetMechanicsSolveTimestep() - timeStep) > 1e-6)
00978 {
00979 EXCEPTION("Timestep provided for SetOutputDeformationGradientsAndStress() is not a multiple of mechanics solve timestep");
00980 }
00981 }
00982
00983
00984 template<unsigned DIM, unsigned ELEC_PROB_DIM>
00985 std::vector<c_vector<double,DIM> >& CardiacElectroMechanicsProblem<DIM,ELEC_PROB_DIM>::rGetDeformedPosition()
00986 {
00987 return mpMechanicsSolver->rGetDeformedPosition();
00988 }
00989
00990
00991
00992
00994
00996
00997
00998 template class CardiacElectroMechanicsProblem<2,1>;
00999 template class CardiacElectroMechanicsProblem<3,1>;
01000 template class CardiacElectroMechanicsProblem<2,2>;
01001 template class CardiacElectroMechanicsProblem<3,2>;