Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, 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 // Work-around for newer Boost versions 00037 #include "CheckpointArchiveTypesIfNeeded.hpp" 00038 00039 #include "UblasCustomFunctions.hpp" 00040 00041 #include "HeartConfig.hpp" 00042 #include "OutputFileHandler.hpp" 00043 #include "Exception.hpp" 00044 #include "ChastePoint.hpp" 00045 #include "Version.hpp" 00046 #include "AbstractChasteRegion.hpp" 00047 #include "HeartFileFinder.hpp" 00048 #include "Warnings.hpp" 00049 00050 #include "HeartRegionCodes.hpp" 00051 00052 #include "SimpleStimulus.hpp" 00053 #include "RegularStimulus.hpp" 00054 00055 #include <string> 00056 #include <istream> 00057 #include <fstream> 00058 #include <cassert> 00059 #include <map> 00060 00061 #include "XmlTools.hpp" 00062 #include <xsd/cxx/tree/exceptions.hxx> 00063 using namespace xsd::cxx::tree; 00064 00065 // Coping with changes to XSD interface 00066 #if (XSD_INT_VERSION >= 3000000L) 00067 #define XSD_SEQUENCE_TYPE(base) base##_sequence 00068 #define XSD_ITERATOR_TYPE(base) base##_iterator 00069 #define XSD_NESTED_TYPE(t) t##_type 00070 #define XSD_ANON_TYPE(t1, t2) \ 00071 t1::t2##_type 00072 #else 00073 #define XSD_SEQUENCE_TYPE(base) base::container 00074 #define XSD_ITERATOR_TYPE(base) base::iterator 00075 #define XSD_NESTED_TYPE(t) t::type 00076 #define XSD_ANON_TYPE(t1, t2) \ 00077 t1::t2::_xsd_##t2##_::t2 00078 #endif 00079 00080 // These are for convenience 00081 #define XSD_ANON_SEQUENCE_TYPE(t1, t2, t3) \ 00082 XSD_SEQUENCE_TYPE(XSD_ANON_TYPE(t1, t2)::t3) 00083 #define XSD_ANON_ITERATOR_TYPE(t1, t2, t3) \ 00084 XSD_ITERATOR_TYPE(XSD_ANON_TYPE(t1, t2)::t3) 00085 00086 // Newer versions don't allow you to set fixed attributes 00087 #if (XSD_INT_VERSION >= 3020000L) 00088 #define XSD_CREATE_WITH_FIXED_ATTR(type, name, attr) \ 00089 type name 00090 #define XSD_CREATE_WITH_FIXED_ATTR1(type, name, arg1, attr) \ 00091 type name(arg1) 00092 #define XSD_CREATE_WITH_FIXED_ATTR2(type, name, arg1, arg2, attr) \ 00093 type name(arg1, arg2) 00094 #define XSD_CREATE_WITH_FIXED_ATTR3(type, name, arg1, arg2, arg3, attr) \ 00095 type name(arg1, arg2, arg3) 00096 #else 00097 #define XSD_CREATE_WITH_FIXED_ATTR(type, name, attr) \ 00098 type name(attr) 00099 #define XSD_CREATE_WITH_FIXED_ATTR1(type, name, arg1, attr) \ 00100 type name(arg1, attr) 00101 #define XSD_CREATE_WITH_FIXED_ATTR2(type, name, arg1, arg2, attr) \ 00102 type name(arg1, arg2, attr) 00103 #define XSD_CREATE_WITH_FIXED_ATTR3(type, name, arg1, arg2, arg3, attr) \ 00104 type name(arg1, arg2, arg3, attr) 00105 #endif 00106 00110 #define ENSURE_SECTION_PRESENT(location, type) \ 00111 if (!location.present()) \ 00112 { \ 00113 type empty_item; \ 00114 location.set(empty_item); \ 00115 } 00116 00117 #include <boost/current_function.hpp> 00125 #define CHECK_EXISTS(test, path) \ 00126 do { \ 00127 if (!test) { \ 00128 EXCEPTION("No XML element " << path << " found in parameters when calling '" \ 00129 << BOOST_CURRENT_FUNCTION << "'"); \ 00130 }} while (false) 00131 00132 00137 class XmlTransforms 00138 { 00139 public: 00147 static void TransformIonicModelDefinitions(xercesc::DOMDocument* pDocument, 00148 xercesc::DOMElement* pRootElement); 00149 00158 static void TransformArchiveDirectory(xercesc::DOMDocument* pDocument, 00159 xercesc::DOMElement* pRootElement); 00160 00168 static void CheckForIluPreconditioner(xercesc::DOMDocument* pDocument, 00169 xercesc::DOMElement* pRootElement); 00170 00178 static void MoveConductivityHeterogeneities(xercesc::DOMDocument* pDocument, 00179 xercesc::DOMElement* pRootElement); 00180 }; 00181 00182 // 00183 // Default settings 00184 // 00185 #include "HeartConfigDefaults.hpp" 00186 00187 // 00188 // Definition of static member variables 00189 // 00190 std::auto_ptr<HeartConfig> HeartConfig::mpInstance; 00191 00192 // 00193 // Methods 00194 // 00195 00196 HeartConfig* HeartConfig::Instance() 00197 { 00198 if (mpInstance.get() == NULL) 00199 { 00200 mpInstance.reset(new HeartConfig); 00201 } 00202 return mpInstance.get(); 00203 } 00204 00205 HeartConfig::HeartConfig() 00206 : mUseMassLumping(false), 00207 mUseMassLumpingForPrecond(false), 00208 mUseFixedNumberIterations(false), 00209 mEvaluateNumItsEveryNSolves(UINT_MAX) 00210 { 00211 assert(mpInstance.get() == NULL); 00212 mUseFixedSchemaLocation = true; 00213 SetDefaultSchemaLocations(); 00214 00215 mpParameters = CreateDefaultParameters(); 00216 //CheckTimeSteps(); // necessity of this line of code is not tested -- remove with caution! 00217 00218 //initialise the member variable of the layers 00219 mEpiFraction = -1.0; 00220 mEndoFraction = -1.0; 00221 mMidFraction = -1.0; 00222 mUserAskedForCellularTransmuralHeterogeneities = false; 00223 // initialise to senseless values (these should be only 0, 1 and 2) 00224 // note: the 'minus 3' is for checking purposes as we need to add 0, 1 or 2 to this initial value 00225 // and UINT_MAX+1 seems to be 0 00226 mIndexMid = UINT_MAX-3u; 00227 mIndexEpi = UINT_MAX-3u; 00228 mIndexEndo = UINT_MAX-3u; 00229 00230 mUseReactionDiffusionOperatorSplitting = false; 00231 00233 mTissueIdentifiers.insert(0); 00234 mBathIdentifiers.insert(1); 00235 } 00236 00237 HeartConfig::~HeartConfig() 00238 { 00239 } 00240 00241 00242 void HeartConfig::Write(bool useArchiveLocationInfo, std::string subfolderName) 00243 { 00244 //Output file 00245 std::string output_dirname; 00246 if (useArchiveLocationInfo) 00247 { 00248 output_dirname = ArchiveLocationInfo::GetArchiveDirectory(); 00249 } 00250 else 00251 { 00252 OutputFileHandler handler(GetOutputDirectory() + "/" + subfolderName, false); 00253 output_dirname = handler.GetOutputDirectoryFullPath(); 00254 } 00255 if (!PetscTools::AmMaster()) 00256 { 00257 //Only the master process is writing the configuration files 00258 return; 00259 } 00260 out_stream p_parameters_file( new std::ofstream( (output_dirname+"ChasteParameters.xml").c_str() ) ); 00261 00262 if (!p_parameters_file->is_open()) 00263 { 00264 EXCEPTION("Could not open XML file in HeartConfig"); 00265 } 00266 00267 //Schema map 00268 //Note - this location is relative to where we are storing the xml 00269 ::xml_schema::namespace_infomap map; 00270 // Release 1.1 (and earlier) didn't use a namespace 00271 map[""].schema = "ChasteParameters_1_1.xsd"; 00272 // Later releases use namespaces of the form https://chaste.comlab.ox.ac.uk/nss/parameters/N_M 00273 map["cp20"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_0"; 00274 map["cp20"].schema = "ChasteParameters_2_0.xsd"; 00275 map["cp21"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_1"; 00276 map["cp21"].schema = "ChasteParameters_2_1.xsd"; 00277 map["cp22"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_2"; 00278 map["cp22"].schema = "ChasteParameters_2_2.xsd"; 00279 map["cp23"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_3"; 00280 map["cp23"].schema = "ChasteParameters_2_3.xsd"; 00281 map["cp30"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_0"; 00282 map["cp30"].schema = "ChasteParameters_3_0.xsd"; 00283 // We use 'cp' as prefix for the latest version to avoid having to change saved 00284 // versions for comparison at every release. 00285 map["cp"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_1"; 00286 map["cp"].schema = "ChasteParameters_3_1.xsd"; 00287 00288 cp::ChasteParameters(*p_parameters_file, *mpParameters, map); 00289 00290 // If we're archiving, try to save a copy of the latest schema too 00291 if (useArchiveLocationInfo) 00292 { 00293 CopySchema(output_dirname); 00294 } 00295 } 00296 00297 void HeartConfig::LoadFromCheckpoint() 00298 { 00299 /* 00300 * This method implements the logic required by HeartConfig to be able to handle resuming a simulation via the executable. 00301 * 00302 * When the control reaches the method mpParameters points to the file specified as resuming parameters. 00303 * However SetParametersFile() will set this variable to point to the archived parameters. 00304 * 00305 * We make a temporary copy of mpParameters so we don't lose its content. 00306 * At the end of the method we update the new mpParameters with the resuming parameters. 00307 */ 00308 assert(mpParameters.use_count() > 0); 00309 boost::shared_ptr<cp::chaste_parameters_type> p_new_parameters = mpParameters; 00310 00311 /* 00312 * When we unarchive a simulation, we load the old parameters file in order to inherit things such 00313 * as default cell model, stimuli, heterogeneities, ... This has the side effect of inheriting the 00314 * <CheckpointSimulation> element (if defined). 00315 * 00316 * We disable checkpointing definition coming from the unarchived config file. We will enable it again 00317 * if defined in the resume config file. 00318 */ 00319 std::string parameters_filename_xml = ArchiveLocationInfo::GetArchiveDirectory() + "ChasteParameters.xml"; 00320 mpParameters = ReadFile(parameters_filename_xml); 00321 mParametersFilePath.SetPath(parameters_filename_xml, RelativeTo::AbsoluteOrCwd); 00322 00323 // Release 3.0 and earlier wrote a separate defaults file in the checkpoint 00324 std::string defaults_filename_xml = ArchiveLocationInfo::GetArchiveDirectory() + "ChasteDefaults.xml"; 00325 if (FileFinder(defaults_filename_xml).Exists()) 00326 { 00327 boost::shared_ptr<cp::chaste_parameters_type> p_defaults = ReadFile(defaults_filename_xml); 00328 MergeDefaults(mpParameters, p_defaults); 00329 } 00330 00331 HeartConfig::Instance()->SetCheckpointSimulation(false); 00332 00333 // If we are resuming a simulation, some parameters can be altered at this point. 00334 if (p_new_parameters->ResumeSimulation().present()) 00335 { 00336 UpdateParametersFromResumeSimulation(p_new_parameters); 00337 } 00338 00339 CheckTimeSteps(); // For consistency with SetParametersFile 00340 } 00341 00342 void HeartConfig::CopySchema(const std::string& rToDirectory) 00343 { 00344 if (PetscTools::AmMaster()) 00345 { 00346 std::string schema_name("ChasteParameters_3_1.xsd"); 00347 FileFinder schema_location("heart/src/io/" + schema_name, RelativeTo::ChasteSourceRoot); 00348 if (!schema_location.Exists()) 00349 { 00350 // Try a relative path instead 00351 schema_location.SetPath(schema_name, RelativeTo::CWD); 00352 if (!schema_location.Exists()) 00353 { 00354 // Warn the user 00355 std::string message("Unable to locate schema file " + schema_name + 00356 ". You will need to ensure it is available when resuming from the checkpoint."); 00357 WARN_ONCE_ONLY(message); 00358 } 00359 } 00360 if (schema_location.Exists()) 00361 { 00362 // Called by master only so use this instead of EXPECT0 00363 ABORT_IF_NON0(system,("cp " + schema_location.GetAbsolutePath() + " " + rToDirectory).c_str()); 00364 } 00365 } 00366 } 00367 00368 void HeartConfig::SetDefaultSchemaLocations() 00369 { 00370 mSchemaLocations.clear(); 00371 // Location of schemas in the source tree 00372 std::string root_dir = std::string(ChasteBuildInfo::GetRootDir()) + "/heart/src/io/"; 00373 // Release 1.1 (and earlier) didn't use a namespace 00374 mSchemaLocations[""] = root_dir + "ChasteParameters_1_1.xsd"; 00375 // Later releases use namespaces of the form https://chaste.comlab.ox.ac.uk/nss/parameters/N_M 00376 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_0"] = root_dir + "ChasteParameters_2_0.xsd"; 00377 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_1"] = root_dir + "ChasteParameters_2_1.xsd"; 00378 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_2"] = root_dir + "ChasteParameters_2_2.xsd"; 00379 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_3"] = root_dir + "ChasteParameters_2_3.xsd"; 00380 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_0"] = root_dir + "ChasteParameters_3_0.xsd"; 00381 mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_1"] = root_dir + "ChasteParameters_3_1.xsd"; 00382 } 00383 00384 unsigned HeartConfig::GetVersionFromNamespace(const std::string& rNamespaceUri) 00385 { 00386 unsigned version_major = 0; 00387 unsigned version_minor = 0; 00388 if (rNamespaceUri == "") 00389 { 00390 version_major = 1; 00391 version_minor = 1; 00392 } 00393 else 00394 { 00395 std::string uri_base("https://chaste.comlab.ox.ac.uk/nss/parameters/"); 00396 if (rNamespaceUri.substr(0, uri_base.length()) == uri_base) 00397 { 00398 std::istringstream version_string(rNamespaceUri.substr(uri_base.length())); 00399 version_string >> version_major; 00400 version_string.ignore(1); 00401 version_string >> version_minor; 00402 if (version_string.fail()) 00403 { 00404 version_major = 0; 00405 version_minor = 0; 00406 } 00407 } 00408 } 00409 00410 unsigned version = version_major * 1000 + version_minor; 00411 if (version == 0) 00412 { 00413 EXCEPTION(rNamespaceUri + " is not a recognised Chaste parameters namespace."); 00414 } 00415 return version; 00416 } 00417 00418 void HeartConfig::SetFixedSchemaLocations(const SchemaLocationsMap& rSchemaLocations) 00419 { 00420 mSchemaLocations = rSchemaLocations; 00421 SetUseFixedSchemaLocation(true); 00422 } 00423 00424 void HeartConfig::SetUseFixedSchemaLocation(bool useFixedSchemaLocation) 00425 { 00426 mUseFixedSchemaLocation = useFixedSchemaLocation; 00427 } 00428 00429 boost::shared_ptr<cp::chaste_parameters_type> HeartConfig::ReadFile(const std::string& rFileName) 00430 { 00431 // Determine whether to use the schema path given in the input XML, or our own schema 00432 ::xml_schema::properties props; 00433 if (mUseFixedSchemaLocation) 00434 { 00435 for (SchemaLocationsMap::iterator it = mSchemaLocations.begin(); 00436 it != mSchemaLocations.end(); 00437 ++it) 00438 { 00439 if (it->first == "") 00440 { 00441 props.no_namespace_schema_location(XmlTools::EscapeSpaces(it->second)); 00442 } 00443 else 00444 { 00445 props.schema_location(it->first, XmlTools::EscapeSpaces(it->second)); 00446 } 00447 } 00448 } 00449 00450 // Get the parameters using the method 'ChasteParameters(rFileName)', 00451 // which returns a std::auto_ptr. We convert to a shared_ptr for easier semantics. 00452 try 00453 { 00454 // Make sure Xerces finalization happens 00455 XmlTools::Finalizer finalizer(false); 00456 // Parse XML to DOM 00457 xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> p_doc = XmlTools::ReadXmlFile(rFileName, props); 00458 // Test the namespace on the root element 00459 xercesc::DOMElement* p_root_elt = p_doc->getDocumentElement(); 00460 std::string namespace_uri(X2C(p_root_elt->getNamespaceURI())); 00461 const unsigned version = GetVersionFromNamespace(namespace_uri); 00462 if (version < 2000) // Changes made in release 2.0 00463 { 00464 XmlTransforms::TransformIonicModelDefinitions(p_doc.get(), p_root_elt); 00465 } 00466 if (version < 2001) // Changes made in release 2.1 00467 { 00468 XmlTransforms::TransformArchiveDirectory(p_doc.get(), p_root_elt); 00469 XmlTransforms::CheckForIluPreconditioner(p_doc.get(), p_root_elt); 00470 } 00471 if (version < 3001) // Changes made in release 3.1 00472 { 00473 XmlTransforms::MoveConductivityHeterogeneities(p_doc.get(), p_root_elt); 00474 } 00475 if (version < 3001) // Not the latest release 00476 { 00477 XmlTools::SetNamespace(p_doc.get(), p_root_elt, "https://chaste.comlab.ox.ac.uk/nss/parameters/3_1"); 00478 } 00479 // Parse DOM to object model 00480 std::auto_ptr<cp::chaste_parameters_type> p_params(cp::ChasteParameters(*p_doc, ::xml_schema::flags::dont_initialize, props)); 00481 // Get rid of the DOM stuff 00482 p_doc.reset(); 00483 00484 return boost::shared_ptr<cp::chaste_parameters_type>(p_params); 00485 } 00486 catch (const xml_schema::exception& e) 00487 { 00488 std::cerr << e << std::endl; 00489 // Make sure we don't store invalid parameters 00490 mpParameters.reset(); 00491 EXCEPTION("XML parsing error in configuration file: " + rFileName); 00492 } 00493 catch (...) 00494 { 00495 // Make sure we don't store invalid parameters 00496 mpParameters.reset(); 00497 throw; 00498 } 00499 } 00500 00501 #include "Debug.hpp" 00502 void HeartConfig::SetParametersFile(const std::string& rFileName) 00503 { 00504 mpParameters = ReadFile(rFileName); 00505 MergeDefaults(mpParameters, CreateDefaultParameters()); 00506 mParametersFilePath.SetPath(rFileName, RelativeTo::AbsoluteOrCwd); 00507 00508 if (IsSimulationDefined()) 00509 { 00510 CheckTimeSteps(); // Resume files might not have time steps defined 00511 } 00512 } 00513 00514 FileFinder HeartConfig::GetParametersFilePath() 00515 { 00516 return mParametersFilePath; 00517 } 00518 00519 void HeartConfig::UpdateParametersFromResumeSimulation(boost::shared_ptr<cp::chaste_parameters_type> pResumeParameters) 00520 { 00521 // Check for user foolishness 00522 if ( (pResumeParameters->ResumeSimulation()->SpaceDimension() != HeartConfig::Instance()->GetSpaceDimension()) 00523 ||(pResumeParameters->ResumeSimulation()->Domain() != HeartConfig::Instance()->GetDomain())) 00524 { 00525 EXCEPTION("Problem type and space dimension should match when restarting a simulation."); 00526 } 00527 00528 // New simulation duration 00529 HeartConfig::Instance()->SetSimulationDuration(pResumeParameters->ResumeSimulation()->SimulationDuration()); 00530 00531 // Stimulus definition. For these we always replace any previous definitions (at least for now...) 00532 if (pResumeParameters->ResumeSimulation()->Stimuli().present()) 00533 { 00534 mpParameters->Simulation()->Stimuli().set(pResumeParameters->ResumeSimulation()->Stimuli().get()); 00535 } 00536 00537 // Cell heterogeneities. Note that while we copy the elements here, other code in CardiacSimulation actually updates 00538 // the loaded simulation to take account of the new settings. 00539 if (pResumeParameters->ResumeSimulation()->CellHeterogeneities().present()) 00540 { 00541 if (!mpParameters->Simulation()->CellHeterogeneities().present()) 00542 { 00543 // Original parameters had no heterogeneities, so just copy the whole element 00544 mpParameters->Simulation()->CellHeterogeneities().set(pResumeParameters->ResumeSimulation()->CellHeterogeneities().get()); 00545 } 00546 else 00547 { 00548 // Need to append the new heterogeneity defitions to the original sequence 00549 XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity)& 00550 new_seq = pResumeParameters->ResumeSimulation()->CellHeterogeneities()->CellHeterogeneity(); 00551 XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity)& 00552 orig_seq = mpParameters->Simulation()->CellHeterogeneities()->CellHeterogeneity(); 00553 for (XSD_ITERATOR_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) i = new_seq.begin(); 00554 i != new_seq.end(); 00555 ++i) 00556 { 00557 orig_seq.push_back(*i); 00558 } 00559 } 00560 } 00561 00562 // Whether to checkpoint the resumed simulation 00563 if (pResumeParameters->ResumeSimulation()->CheckpointSimulation().present()) 00564 { 00565 HeartConfig::Instance()->SetCheckpointSimulation(true, 00566 pResumeParameters->ResumeSimulation()->CheckpointSimulation()->timestep(), 00567 pResumeParameters->ResumeSimulation()->CheckpointSimulation()->max_checkpoints_on_disk()); 00568 } 00569 00570 //Visualization parameters are compulsory 00571 HeartConfig::Instance()->SetVisualizeWithParallelVtk(pResumeParameters->ResumeSimulation()->OutputVisualizer().parallel_vtk() == cp::yesno_type::yes); 00572 HeartConfig::Instance()->SetVisualizeWithVtk(pResumeParameters->ResumeSimulation()->OutputVisualizer().vtk() == cp::yesno_type::yes); 00573 HeartConfig::Instance()->SetVisualizeWithCmgui(pResumeParameters->ResumeSimulation()->OutputVisualizer().cmgui() == cp::yesno_type::yes); 00574 HeartConfig::Instance()->SetVisualizeWithMeshalyzer(pResumeParameters->ResumeSimulation()->OutputVisualizer().meshalyzer() == cp::yesno_type::yes); 00575 00576 // Numerical parameters may be overridden 00577 { 00578 cp::numerical_type& r_resume = pResumeParameters->Numerical(); 00579 cp::numerical_type& r_user = mpParameters->Numerical(); 00580 if (r_resume.TimeSteps().present()) 00581 { 00582 r_user.TimeSteps().set(r_resume.TimeSteps().get()); 00583 } 00584 if (r_resume.KSPTolerances().present()) 00585 { 00586 r_user.KSPTolerances().set(r_resume.KSPTolerances().get()); 00587 } 00588 if (r_resume.KSPSolver().present()) 00589 { 00590 r_user.KSPSolver().set(r_resume.KSPSolver().get()); 00591 } 00592 if (r_resume.KSPPreconditioner().present()) 00593 { 00594 r_user.KSPPreconditioner().set(r_resume.KSPPreconditioner().get()); 00595 } 00596 if (r_resume.AdaptivityParameters().present()) 00597 { 00598 r_user.AdaptivityParameters().set(r_resume.AdaptivityParameters().get()); 00599 } 00600 } 00601 00602 // Post-processing parameters may be overridden 00603 if (pResumeParameters->PostProcessing().present()) 00604 { 00605 EnsurePostProcessingSectionPresent(); 00606 cp::postprocessing_type& r_resume = pResumeParameters->PostProcessing().get(); 00607 cp::postprocessing_type& r_user = mpParameters->PostProcessing().get(); 00608 if (!r_resume.ActionPotentialDurationMap().empty()) 00609 { 00610 r_user.ActionPotentialDurationMap() = r_resume.ActionPotentialDurationMap(); 00611 } 00612 if (!r_resume.UpstrokeTimeMap().empty()) 00613 { 00614 r_user.UpstrokeTimeMap() = r_resume.UpstrokeTimeMap(); 00615 } 00616 if (!r_resume.MaxUpstrokeVelocityMap().empty()) 00617 { 00618 r_user.MaxUpstrokeVelocityMap() = r_resume.MaxUpstrokeVelocityMap(); 00619 } 00620 if (!r_resume.ConductionVelocityMap().empty()) 00621 { 00622 r_user.ConductionVelocityMap() = r_resume.ConductionVelocityMap(); 00623 } 00624 } 00625 } 00626 00627 00628 void HeartConfig::Reset() 00629 { 00630 // Throw it away first, so that mpInstance is NULL when we... 00631 mpInstance.reset(); 00632 // ...make a new one 00633 mpInstance.reset(new HeartConfig); 00634 } 00635 00636 bool HeartConfig::IsSimulationDefined() const 00637 { 00638 return mpParameters->Simulation().present(); 00639 } 00640 00641 bool HeartConfig::IsSimulationResumed() const 00642 { 00643 return mpParameters->ResumeSimulation().present(); 00644 } 00645 00646 00647 void HeartConfig::CheckSimulationIsDefined(std::string callingMethod) const 00648 { 00649 if (IsSimulationResumed()) 00650 { 00651 EXCEPTION(callingMethod + " information is not available in a resumed simulation."); 00652 } 00653 } 00654 00655 void HeartConfig::CheckResumeSimulationIsDefined(std::string callingMethod) const 00656 { 00657 if (IsSimulationDefined()) 00658 { 00659 EXCEPTION(callingMethod + " information is not available in a standard (non-resumed) simulation."); 00660 } 00661 } 00662 00663 unsigned HeartConfig::GetSpaceDimension() const 00664 { 00665 if (IsSimulationDefined()) 00666 { 00667 CHECK_EXISTS(mpParameters->Simulation()->SpaceDimension().present(), "Simulation/SpaceDimension"); 00668 return mpParameters->Simulation()->SpaceDimension().get(); 00669 } 00670 else 00671 { 00672 return mpParameters->ResumeSimulation()->SpaceDimension(); 00673 } 00674 } 00675 00676 double HeartConfig::GetSimulationDuration() const 00677 { 00678 if (IsSimulationDefined()) 00679 { 00680 CHECK_EXISTS(mpParameters->Simulation()->SimulationDuration().present(), "Simulation/SimulationDuration"); 00681 return mpParameters->Simulation()->SimulationDuration().get(); 00682 } 00683 else // IsSimulationResumed 00684 { 00685 return mpParameters->ResumeSimulation()->SimulationDuration(); 00686 } 00687 } 00688 00689 cp::domain_type HeartConfig::GetDomain() const 00690 { 00691 if (IsSimulationDefined()) 00692 { 00693 CHECK_EXISTS(mpParameters->Simulation()->Domain().present(), "Simulation/Domain"); 00694 return mpParameters->Simulation()->Domain().get(); 00695 } 00696 else 00697 { 00698 return mpParameters->ResumeSimulation()->Domain(); 00699 } 00700 } 00701 00702 cp::ionic_model_selection_type HeartConfig::GetDefaultIonicModel() const 00703 { 00704 CheckSimulationIsDefined("DefaultIonicModel"); 00705 00706 return mpParameters->Simulation()->IonicModels()->Default(); 00707 } 00708 00709 template<unsigned DIM> 00710 void HeartConfig::GetIonicModelRegions(std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& definedRegions, 00711 std::vector<cp::ionic_model_selection_type>& ionicModels) const 00712 { 00713 CheckSimulationIsDefined("IonicModelRegions"); 00714 definedRegions.clear(); 00715 ionicModels.clear(); 00716 00717 XSD_SEQUENCE_TYPE(cp::ionic_models_type::Region)& 00718 regions = mpParameters->Simulation()->IonicModels()->Region(); 00719 00720 for (XSD_ITERATOR_TYPE(cp::ionic_models_type::Region) i = regions.begin(); 00721 i != regions.end(); 00722 ++i) 00723 { 00724 cp::ionic_model_region_type ionic_model_region(*i); 00725 00726 if (ionic_model_region.Location().Cuboid().present() || ionic_model_region.Location().Ellipsoid().present()) 00727 { 00728 if (ionic_model_region.Location().Cuboid().present()) 00729 { 00730 cp::point_type point_a = ionic_model_region.Location().Cuboid()->LowerCoordinates(); 00731 cp::point_type point_b = ionic_model_region.Location().Cuboid()->UpperCoordinates(); 00732 00733 switch (DIM) 00734 { 00735 case 1: 00736 { 00737 ChastePoint<DIM> chaste_point_a ( point_a.x() ); 00738 ChastePoint<DIM> chaste_point_b ( point_b.x() ); 00739 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ))); 00740 break; 00741 } 00742 case 2: 00743 { 00744 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y() ); 00745 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y() ); 00746 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ))); 00747 break; 00748 } 00749 case 3: 00750 { 00751 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() ); 00752 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() ); 00753 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b )) ); 00754 break; 00755 } 00756 default: 00757 NEVER_REACHED; 00758 break; 00759 } 00760 } 00761 else if (ionic_model_region.Location().Ellipsoid().present()) 00762 { 00763 cp::point_type centre = ionic_model_region.Location().Ellipsoid()->Centre(); 00764 cp::point_type radii = ionic_model_region.Location().Ellipsoid()->Radii(); 00765 switch (DIM) 00766 { 00767 case 1: 00768 { 00769 ChastePoint<DIM> chaste_point_a ( centre.x() ); 00770 ChastePoint<DIM> chaste_point_b ( radii.x() ); 00771 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) ); 00772 break; 00773 } 00774 case 2: 00775 { 00776 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y() ); 00777 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y() ); 00778 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) ); 00779 break; 00780 } 00781 case 3: 00782 { 00783 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() ); 00784 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() ); 00785 definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) ); 00786 break; 00787 } 00788 default: 00789 { 00790 NEVER_REACHED; 00791 break; 00792 } 00793 } 00794 } 00795 else 00796 { 00797 NEVER_REACHED; 00798 } 00799 00800 ionicModels.push_back(ionic_model_region.IonicModel()); 00801 } 00802 else if(ionic_model_region.Location().EpiLayer().present() || ionic_model_region.Location().MidLayer().present() || ionic_model_region.Location().EndoLayer().present() ) 00803 { 00805 EXCEPTION("Definition of transmural layers is not yet supported for defining different ionic models, please use cuboids instead"); 00806 } 00807 else 00808 { 00809 EXCEPTION("Invalid region type for ionic model definition"); 00810 } 00811 } 00812 } 00813 00814 00815 bool HeartConfig::IsMeshProvided() const 00816 { 00817 CheckSimulationIsDefined("Mesh"); 00818 return mpParameters->Simulation()->Mesh().present(); 00819 } 00820 00821 bool HeartConfig::GetCreateMesh() const 00822 { 00823 CheckSimulationIsDefined("Mesh"); 00824 CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh"); 00825 cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get(); 00826 return (mesh.Slab().present() || mesh.Sheet().present() || mesh.Fibre().present()); 00827 } 00828 00829 bool HeartConfig::GetCreateSlab() const 00830 { 00831 CheckSimulationIsDefined("Mesh"); 00832 CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh"); 00833 cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get(); 00834 return (mesh.Slab().present()); 00835 } 00836 00837 bool HeartConfig::GetCreateSheet() const 00838 { 00839 CheckSimulationIsDefined("Mesh"); 00840 CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh"); 00841 cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get(); 00842 return (mesh.Sheet().present()); 00843 } 00844 00845 bool HeartConfig::GetCreateFibre() const 00846 { 00847 CheckSimulationIsDefined("Mesh"); 00848 CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh"); 00849 cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get(); 00850 return (mesh.Fibre().present()); 00851 } 00852 00853 00854 bool HeartConfig::GetLoadMesh() const 00855 { 00856 CheckSimulationIsDefined("Mesh"); 00857 CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh"); 00858 return (mpParameters->Simulation()->Mesh()->LoadMesh().present()); 00859 } 00860 00861 void HeartConfig::GetSlabDimensions(c_vector<double, 3>& slabDimensions) const 00862 { 00863 CheckSimulationIsDefined("Slab"); 00864 00865 if (GetSpaceDimension()!=3 || !GetCreateSlab()) 00866 { 00867 EXCEPTION("Tissue slabs can only be defined in 3D"); 00868 } 00869 00870 optional<cp::slab_type, false> slab_dimensions = mpParameters->Simulation()->Mesh()->Slab(); 00871 00872 slabDimensions[0] = slab_dimensions->x(); 00873 slabDimensions[1] = slab_dimensions->y(); 00874 slabDimensions[2] = slab_dimensions->z(); 00875 } 00876 00877 void HeartConfig::GetSheetDimensions(c_vector<double, 2>& sheetDimensions) const 00878 { 00879 CheckSimulationIsDefined("Sheet"); 00880 00881 if (GetSpaceDimension()!=2 || !GetCreateSheet()) 00882 { 00883 EXCEPTION("Tissue sheets can only be defined in 2D"); 00884 } 00885 00886 optional<cp::sheet_type, false> sheet_dimensions = mpParameters->Simulation()->Mesh()->Sheet(); 00887 00888 sheetDimensions[0] = sheet_dimensions->x(); 00889 sheetDimensions[1] = sheet_dimensions->y(); 00890 } 00891 00892 void HeartConfig::GetFibreLength(c_vector<double, 1>& fibreLength) const 00893 { 00894 CheckSimulationIsDefined("Fibre"); 00895 00896 if (GetSpaceDimension()!=1 || !GetCreateFibre()) 00897 { 00898 EXCEPTION("Tissue fibres can only be defined in 1D"); 00899 } 00900 00901 optional<cp::fibre_type, false> fibre_length = mpParameters->Simulation()->Mesh()->Fibre(); 00902 00903 fibreLength[0] = fibre_length->x(); 00904 } 00905 00906 double HeartConfig::GetInterNodeSpace() const 00907 { 00908 CheckSimulationIsDefined("InterNodeSpace"); 00909 00910 switch (GetSpaceDimension()) 00911 { 00912 case 3: 00913 CHECK_EXISTS(GetCreateSlab(), "Simulation/Mesh/Slab"); 00914 return mpParameters->Simulation()->Mesh()->Slab()->inter_node_space(); 00915 break; 00916 case 2: 00917 CHECK_EXISTS(GetCreateSheet(), "Simulation/Mesh/Sheet"); 00918 return mpParameters->Simulation()->Mesh()->Sheet()->inter_node_space(); 00919 break; 00920 case 1: 00921 CHECK_EXISTS(GetCreateFibre(), "Simulation/Mesh/Fibre"); 00922 return mpParameters->Simulation()->Mesh()->Fibre()->inter_node_space(); 00923 break; 00924 default: 00925 NEVER_REACHED; 00926 #define COVERAGE_IGNORE 00927 return 0.0; //To fool the compiler 00928 #undef COVERAGE_IGNORE 00929 } 00930 } 00931 00932 std::string HeartConfig::GetMeshName() const 00933 { 00934 CheckSimulationIsDefined("LoadMesh"); 00935 CHECK_EXISTS(GetLoadMesh(), "Mesh/LoadMesh"); 00936 00937 return mpParameters->Simulation()->Mesh()->LoadMesh()->name(); 00938 } 00939 00940 cp::media_type HeartConfig::GetConductivityMedia() const 00941 { 00942 CheckSimulationIsDefined("LoadMesh"); 00943 CHECK_EXISTS(GetLoadMesh(), "Mesh/LoadMesh"); 00944 00945 return mpParameters->Simulation()->Mesh()->LoadMesh()->conductivity_media(); 00946 } 00947 00948 template <unsigned DIM> 00949 void HeartConfig::GetStimuli(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& rStimuliApplied, 00950 std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rStimulatedAreas) const 00951 { 00952 CheckSimulationIsDefined("Stimuli"); 00953 00954 if (!mpParameters->Simulation()->Stimuli().present()) 00955 { 00956 // Finding no stimuli defined is allowed (although HeartConfigRelatedFactory does 00957 // throw an exception is no stimuli and no electrodes) 00958 return; 00959 } 00960 00961 XSD_SEQUENCE_TYPE(cp::stimuli_type::Stimulus) stimuli = mpParameters->Simulation()->Stimuli()->Stimulus(); 00962 00963 for (XSD_ITERATOR_TYPE(cp::stimuli_type::Stimulus) i = stimuli.begin(); 00964 i != stimuli.end(); 00965 ++i) 00966 { 00967 cp::stimulus_type stimulus(*i); 00968 if (stimulus.Location().Cuboid().present() || stimulus.Location().Ellipsoid().present()) 00969 { 00970 boost::shared_ptr<AbstractChasteRegion<DIM> > area_ptr; 00971 if (stimulus.Location().Cuboid().present() ) 00972 { 00973 cp::point_type point_a = stimulus.Location().Cuboid()->LowerCoordinates(); 00974 cp::point_type point_b = stimulus.Location().Cuboid()->UpperCoordinates(); 00975 switch (DIM) 00976 { 00977 case 1: 00978 { 00979 ChastePoint<DIM> chaste_point_a ( point_a.x() ); 00980 ChastePoint<DIM> chaste_point_b ( point_b.x() ); 00981 area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) ); 00982 break; 00983 } 00984 case 2: 00985 { 00986 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y() ); 00987 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y() ); 00988 area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) ); 00989 break; 00990 } 00991 case 3: 00992 { 00993 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() ); 00994 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() ); 00995 area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) ); 00996 break; 00997 } 00998 default: 00999 NEVER_REACHED; 01000 break; 01001 } 01002 } 01003 else if (stimulus.Location().Ellipsoid().present()) 01004 { 01005 cp::point_type centre = stimulus.Location().Ellipsoid()->Centre(); 01006 cp::point_type radii = stimulus.Location().Ellipsoid()->Radii(); 01007 switch (DIM) 01008 { 01009 case 1: 01010 { 01011 ChastePoint<DIM> chaste_point_a ( centre.x() ); 01012 ChastePoint<DIM> chaste_point_b ( radii.x() ); 01013 area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) ); 01014 break; 01015 } 01016 case 2: 01017 { 01018 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y() ); 01019 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y() ); 01020 area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) ); 01021 break; 01022 } 01023 case 3: 01024 { 01025 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() ); 01026 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() ); 01027 area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) ); 01028 break; 01029 } 01030 default: 01031 { 01032 NEVER_REACHED; 01033 break; 01034 } 01035 } 01036 } 01037 rStimulatedAreas.push_back(area_ptr); 01038 01039 boost::shared_ptr<AbstractStimulusFunction> stim; 01040 01041 if (stimulus.Period().present()) 01042 { 01043 if (stimulus.StopTime().present()) 01044 { 01045 stim.reset(new RegularStimulus(stimulus.Strength(), 01046 stimulus.Duration(), 01047 stimulus.Period().get(), 01048 stimulus.Delay(), 01049 stimulus.StopTime().get())); 01050 } 01051 else 01052 { 01053 stim.reset(new RegularStimulus(stimulus.Strength(), 01054 stimulus.Duration(), 01055 stimulus.Period().get(), 01056 stimulus.Delay())); 01057 } 01058 01059 } 01060 else 01061 { 01062 if (stimulus.StopTime().present()) 01063 { 01064 EXCEPTION("Stop time can not be defined for SimpleStimulus. Use Duration instead."); 01065 } 01066 01067 stim.reset(new SimpleStimulus(stimulus.Strength(), 01068 stimulus.Duration(), 01069 stimulus.Delay())); 01070 } 01071 rStimuliApplied.push_back( stim ); 01072 } 01073 else if(stimulus.Location().EpiLayer().present() || stimulus.Location().MidLayer().present() || stimulus.Location().EndoLayer().present() ) 01074 { 01075 EXCEPTION("Definition of transmural layers is not yet supported for specifying stimulated areas, please use cuboids instead"); 01076 } 01077 else 01078 { 01079 EXCEPTION("Invalid region type for stimulus definition"); 01080 } 01081 } 01082 } 01083 01084 01085 template<unsigned DIM> 01086 void HeartConfig::GetCellHeterogeneities(std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rCellHeterogeneityRegions, 01087 std::vector<double>& rScaleFactorGks, 01088 std::vector<double>& rScaleFactorIto, 01089 std::vector<double>& rScaleFactorGkr, 01090 std::vector<std::map<std::string, double> >* pParameterSettings) 01091 { 01092 CheckSimulationIsDefined("CellHeterogeneities"); 01093 01094 if (!mpParameters->Simulation()->CellHeterogeneities().present()) 01095 { 01096 // finding no heterogeneities defined is allowed 01097 return; 01098 } 01099 XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) cell_heterogeneity 01100 = mpParameters->Simulation()->CellHeterogeneities()->CellHeterogeneity(); 01101 01102 bool user_supplied_negative_value = false; 01103 bool user_asking_for_transmural_layers = false; 01104 bool user_asked_for_cuboids_or_ellipsoids = false; 01105 unsigned counter_of_heterogeneities = 0; 01106 01107 for (XSD_ITERATOR_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) i = cell_heterogeneity.begin(); 01108 i != cell_heterogeneity.end(); 01109 ++i) 01110 { 01111 cp::cell_heterogeneity_type ht(*i); 01112 01113 if (ht.Location().Cuboid().present()) 01114 { 01115 user_asked_for_cuboids_or_ellipsoids = true; 01116 cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates(); 01117 cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates(); 01118 01119 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() ); 01120 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() ); 01121 01122 rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM> ( chaste_point_a, chaste_point_b )) ); 01123 } 01124 else if (ht.Location().Ellipsoid().present()) 01125 { 01126 user_asked_for_cuboids_or_ellipsoids = true; 01127 cp::point_type centre = ht.Location().Ellipsoid()->Centre(); 01128 cp::point_type radii = ht.Location().Ellipsoid()->Radii(); 01129 01130 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() ); 01131 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() ); 01132 rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) ); 01133 } 01134 else if (ht.Location().EpiLayer().present()) 01135 { 01136 mEpiFraction = ht.Location().EpiLayer().get(); 01137 01138 user_asking_for_transmural_layers = true; 01139 if (mEpiFraction <0) 01140 { 01141 user_supplied_negative_value=true; 01142 } 01143 mIndexEpi = counter_of_heterogeneities; 01144 } 01145 else if (ht.Location().EndoLayer().present()) 01146 { 01147 mEndoFraction = ht.Location().EndoLayer().get(); 01148 01149 user_asking_for_transmural_layers = true; 01150 if (mEndoFraction <0) 01151 { 01152 user_supplied_negative_value=true; 01153 } 01154 mIndexEndo = counter_of_heterogeneities; 01155 } 01156 else if (ht.Location().MidLayer().present()) 01157 { 01158 mMidFraction = ht.Location().MidLayer().get(); 01159 01160 user_asking_for_transmural_layers = true; 01161 if (mMidFraction <0) 01162 { 01163 user_supplied_negative_value=true; 01164 } 01165 mIndexMid = counter_of_heterogeneities; 01166 } 01167 else 01168 { 01169 EXCEPTION("Invalid region type for cell heterogeneity definition"); 01170 } 01171 01172 // Old scale factors 01173 rScaleFactorGks.push_back(ht.ScaleFactorGks().present() ? (double)ht.ScaleFactorGks().get() : 1.0); 01174 rScaleFactorIto.push_back(ht.ScaleFactorIto().present() ? (double)ht.ScaleFactorIto().get() : 1.0); 01175 rScaleFactorGkr.push_back(ht.ScaleFactorGkr().present() ? (double)ht.ScaleFactorGkr().get() : 1.0); 01176 01177 // Named parameters 01178 if (pParameterSettings) 01179 { 01180 std::map<std::string, double> param_settings; 01181 XSD_SEQUENCE_TYPE(cp::cell_heterogeneity_type::SetParameter)& params = ht.SetParameter(); 01182 for (XSD_ITERATOR_TYPE(cp::cell_heterogeneity_type::SetParameter) param_it = params.begin(); 01183 param_it != params.end(); 01184 ++param_it) 01185 { 01186 cp::set_parameter_type param(*param_it); 01187 param_settings[param.name()] = param.value(); 01188 } 01189 pParameterSettings->push_back(param_settings); 01190 } 01191 01192 counter_of_heterogeneities++; 01193 } 01194 01195 //set the flag for request of transmural layers 01196 mUserAskedForCellularTransmuralHeterogeneities = user_asking_for_transmural_layers; 01197 01198 if ( mUserAskedForCellularTransmuralHeterogeneities ) 01199 { 01200 // cuboids/ellipsoids and layers at the same time are not yet supported 01201 if (user_asked_for_cuboids_or_ellipsoids ) 01202 { 01203 EXCEPTION ("Specification of cellular heterogeneities by cuboids/ellipsoids and layers at the same time is not yet supported"); 01204 } 01205 01206 //check that the user supplied all three layers, the indexes should be 0, 1 and 2. 01207 // As they are initialised to a higher value, if their summation is higher than 3, 01208 // one (or more) is missing 01209 if ((mIndexMid+mIndexEndo+mIndexEpi) > 3) 01210 { 01211 EXCEPTION ("Three specifications of layers must be supplied"); 01212 } 01213 if (fabs((mEndoFraction+mMidFraction+mEpiFraction)-1)>1e-2) 01214 { 01215 EXCEPTION ("Summation of epicardial, midmyocardial and endocardial fractions should be 1"); 01216 } 01217 if (user_supplied_negative_value) 01218 { 01219 EXCEPTION ("Fractions must be positive"); 01220 } 01221 } 01222 } 01223 01224 bool HeartConfig::AreCellularTransmuralHeterogeneitiesRequested() 01225 { 01226 return mUserAskedForCellularTransmuralHeterogeneities; 01227 } 01228 01229 double HeartConfig::GetEpiLayerFraction() 01230 { 01231 return mEpiFraction; 01232 } 01233 01234 double HeartConfig::GetEndoLayerFraction() 01235 { 01236 return mEndoFraction; 01237 } 01238 01239 double HeartConfig::GetMidLayerFraction() 01240 { 01241 return mMidFraction; 01242 } 01243 01244 unsigned HeartConfig::GetEpiLayerIndex() 01245 { 01246 return mIndexEpi; 01247 } 01248 01249 unsigned HeartConfig::GetEndoLayerIndex() 01250 { 01251 return mIndexEndo; 01252 } 01253 01254 unsigned HeartConfig::GetMidLayerIndex() 01255 { 01256 return mIndexMid; 01257 } 01258 01259 bool HeartConfig::GetConductivityHeterogeneitiesProvided() const 01260 { 01261 CheckSimulationIsDefined("ConductivityHeterogeneities"); 01262 return mpParameters->Physiological().ConductivityHeterogeneities().present(); 01263 } 01264 01265 template<unsigned DIM> 01266 void HeartConfig::GetConductivityHeterogeneities( 01267 std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& conductivitiesHeterogeneityAreas, 01268 std::vector< c_vector<double,3> >& intraConductivities, 01269 std::vector< c_vector<double,3> >& extraConductivities) const 01270 { 01271 CheckSimulationIsDefined("ConductivityHeterogeneities"); 01272 CHECK_EXISTS(GetConductivityHeterogeneitiesProvided(), "Physiological/ConductivityHeterogeneities"); 01273 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity)& 01274 conductivity_heterogeneity = mpParameters->Physiological().ConductivityHeterogeneities()->ConductivityHeterogeneity(); 01275 01276 for (XSD_ANON_ITERATOR_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) i = conductivity_heterogeneity.begin(); 01277 i != conductivity_heterogeneity.end(); 01278 ++i) 01279 { 01280 cp::conductivity_heterogeneity_type ht(*i); 01281 01282 if (ht.Location().Cuboid().present()) 01283 { 01284 cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates(); 01285 cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates(); 01286 ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() ); 01287 ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() ); 01288 conductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> > ( new ChasteCuboid<DIM> ( chaste_point_a, chaste_point_b )) ); 01289 } 01290 else if (ht.Location().Ellipsoid().present()) 01291 { 01292 cp::point_type centre = ht.Location().Ellipsoid()->Centre(); 01293 cp::point_type radii = ht.Location().Ellipsoid()->Radii(); 01294 ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() ); 01295 ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() ); 01296 conductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> > ( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) ); 01297 } 01298 else if (ht.Location().EpiLayer().present() || ht.Location().MidLayer().present() || ht.Location().EndoLayer().present() ) 01299 { 01301 EXCEPTION("Definition of transmural layers is not allowed for conductivities heterogeneities, you may use fibre orientation support instead"); 01302 } 01303 else 01304 { 01305 EXCEPTION("Invalid region type for conductivity definition"); 01306 } 01307 01308 if (ht.IntracellularConductivities().present()) 01309 { 01310 double intra_x = ht.IntracellularConductivities()->longi(); 01311 double intra_y = ht.IntracellularConductivities()->trans(); 01312 double intra_z = ht.IntracellularConductivities()->normal(); 01313 01314 intraConductivities.push_back( Create_c_vector(intra_x, intra_y, intra_z) ); 01315 } 01316 else 01317 { 01318 c_vector<double, 3> intra_conductivities; 01319 GetIntracellularConductivities(intra_conductivities); 01320 intraConductivities.push_back(intra_conductivities); 01321 } 01322 01323 if (ht.ExtracellularConductivities().present()) 01324 { 01325 double extra_x = ht.ExtracellularConductivities()->longi(); 01326 double extra_y = ht.ExtracellularConductivities()->trans(); 01327 double extra_z = ht.ExtracellularConductivities()->normal(); 01328 01329 extraConductivities.push_back( Create_c_vector(extra_x, extra_y, extra_z) ); 01330 } 01331 else 01332 { 01333 c_vector<double, 3> extra_conductivities; 01334 GetExtracellularConductivities(extra_conductivities); 01335 extraConductivities.push_back(extra_conductivities); 01336 } 01337 01338 } 01339 } 01340 01341 std::string HeartConfig::GetOutputDirectory() const 01342 { 01343 CheckSimulationIsDefined("Simulation/OutputDirectory"); 01344 CHECK_EXISTS(mpParameters->Simulation()->OutputDirectory().present(), "Simulation/OutputDirectory"); 01345 return mpParameters->Simulation()->OutputDirectory().get(); 01346 } 01347 01348 std::string HeartConfig::GetOutputFilenamePrefix() const 01349 { 01350 CheckSimulationIsDefined("Simulation/OutputFilenamePrefix"); 01351 CHECK_EXISTS(mpParameters->Simulation()->OutputFilenamePrefix().present(), "Simulation/OutputFilenamePrefix"); 01352 return mpParameters->Simulation()->OutputFilenamePrefix().get(); 01353 } 01354 01355 bool HeartConfig::GetOutputVariablesProvided() const 01356 { 01357 CheckSimulationIsDefined("OutputVariables"); 01358 return mpParameters->Simulation()->OutputVariables().present(); 01359 } 01360 01361 void HeartConfig::GetOutputVariables(std::vector<std::string>& rOutputVariables) const 01362 { 01363 CHECK_EXISTS(GetOutputVariablesProvided(), "Simulation/OutputVariables"); 01364 XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)& 01365 output_variables = mpParameters->Simulation()->OutputVariables()->Var(); 01366 rOutputVariables.clear(); 01367 01368 for (XSD_ITERATOR_TYPE(cp::output_variables_type::Var) i = output_variables.begin(); 01369 i != output_variables.end(); 01370 ++i) 01371 { 01372 cp::var_type& r_var(*i); 01373 01374 // Add to outputVariables the string returned by var.name() 01375 rOutputVariables.push_back(r_var.name()); 01376 } 01377 } 01378 bool HeartConfig::GetOutputUsingOriginalNodeOrdering() 01379 { 01380 CheckSimulationIsDefined("OutputUsingOriginalNodeOrdering"); 01381 bool result = false; 01382 if (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().present()) 01383 { 01384 result = (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().get() == cp::yesno_type::yes); 01385 } 01386 return result; 01387 } 01388 01389 bool HeartConfig::GetCheckpointSimulation() const 01390 { 01391 return IsSimulationDefined() && mpParameters->Simulation()->CheckpointSimulation().present(); 01392 } 01393 01394 double HeartConfig::GetCheckpointTimestep() const 01395 { 01396 CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation"); 01397 return mpParameters->Simulation()->CheckpointSimulation()->timestep(); 01398 } 01399 01400 unsigned HeartConfig::GetMaxCheckpointsOnDisk() const 01401 { 01402 CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation"); 01403 return mpParameters->Simulation()->CheckpointSimulation()->max_checkpoints_on_disk(); 01404 } 01405 01406 01407 HeartFileFinder HeartConfig::GetArchivedSimulationDir() const 01408 { 01409 CheckResumeSimulationIsDefined("GetArchivedSimulationDir"); 01410 01411 return HeartFileFinder(mpParameters->ResumeSimulation()->ArchiveDirectory()); 01412 } 01413 01414 01415 void HeartConfig::GetIntracellularConductivities(c_vector<double, 3>& intraConductivities) const 01416 { 01417 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities"); 01418 cp::conductivities_type intra_conductivities 01419 = mpParameters->Physiological().IntracellularConductivities().get(); 01420 double intra_x_cond = intra_conductivities.longi(); 01421 double intra_y_cond = intra_conductivities.trans(); 01422 double intra_z_cond = intra_conductivities.normal();; 01423 01424 assert(intra_y_cond != DBL_MAX); 01425 assert(intra_z_cond != DBL_MAX); 01426 01427 intraConductivities[0] = intra_x_cond; 01428 intraConductivities[1] = intra_y_cond; 01429 intraConductivities[2] = intra_z_cond; 01430 } 01431 01432 void HeartConfig::GetIntracellularConductivities(c_vector<double, 2>& intraConductivities) const 01433 { 01434 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities"); 01435 cp::conductivities_type intra_conductivities 01436 = mpParameters->Physiological().IntracellularConductivities().get(); 01437 double intra_x_cond = intra_conductivities.longi(); 01438 double intra_y_cond = intra_conductivities.trans(); 01439 01440 assert(intra_y_cond != DBL_MAX); 01441 01442 intraConductivities[0] = intra_x_cond; 01443 intraConductivities[1] = intra_y_cond; 01444 } 01445 01446 void HeartConfig::GetIntracellularConductivities(c_vector<double, 1>& intraConductivities) const 01447 { 01448 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities"); 01449 cp::conductivities_type intra_conductivities 01450 = mpParameters->Physiological().IntracellularConductivities().get(); 01451 double intra_x_cond = intra_conductivities.longi(); 01452 01453 intraConductivities[0] = intra_x_cond; 01454 } 01455 01456 void HeartConfig::GetExtracellularConductivities(c_vector<double, 3>& extraConductivities) const 01457 { 01458 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities"); 01459 cp::conductivities_type extra_conductivities 01460 = mpParameters->Physiological().ExtracellularConductivities().get(); 01461 double extra_x_cond = extra_conductivities.longi(); 01462 double extra_y_cond = extra_conductivities.trans(); 01463 double extra_z_cond = extra_conductivities.normal();; 01464 01465 assert(extra_y_cond != DBL_MAX); 01466 assert(extra_z_cond != DBL_MAX); 01467 01468 extraConductivities[0] = extra_x_cond; 01469 extraConductivities[1] = extra_y_cond; 01470 extraConductivities[2] = extra_z_cond; 01471 } 01472 01473 void HeartConfig::GetExtracellularConductivities(c_vector<double, 2>& extraConductivities) const 01474 { 01475 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities"); 01476 cp::conductivities_type extra_conductivities 01477 = mpParameters->Physiological().ExtracellularConductivities().get(); 01478 double extra_x_cond = extra_conductivities.longi(); 01479 double extra_y_cond = extra_conductivities.trans(); 01480 01481 assert(extra_y_cond != DBL_MAX); 01482 01483 extraConductivities[0] = extra_x_cond; 01484 extraConductivities[1] = extra_y_cond; 01485 } 01486 01487 void HeartConfig::GetExtracellularConductivities(c_vector<double, 1>& extraConductivities) const 01488 { 01489 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities"); 01490 cp::conductivities_type extra_conductivities 01491 = mpParameters->Physiological().ExtracellularConductivities().get(); 01492 double extra_x_cond = extra_conductivities.longi(); 01493 01494 extraConductivities[0] = extra_x_cond; 01495 } 01496 01497 double HeartConfig::GetBathConductivity(unsigned bathRegion) const 01498 { 01499 /* 01500 * We have to consider three cases: The user asks for ... 01501 * a) ... the default conductivity (bathRegion=UINT_MAX) 01502 * b) ... the conductivity of region defined to be heterogeneous 01503 * c) ... the conductivity of region NOT defined to be heterogeneous 01504 * 01505 * a) and c) should return the same 01506 */ 01507 01508 if (bathRegion == UINT_MAX) 01509 { 01510 /*bath conductivity mS/cm*/ 01511 CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity"); 01512 return mpParameters->Physiological().BathConductivity().get(); 01513 } 01514 else 01515 { 01516 assert(HeartRegionCode::IsRegionBath(bathRegion)); 01517 01518 std::map<unsigned, double>::const_iterator map_entry = mBathConductivities.find(bathRegion); 01519 01520 if (map_entry != mBathConductivities.end()) 01521 { 01522 return map_entry->second; 01523 } 01524 else 01525 { 01526 /*bath conductivity mS/cm*/ 01527 CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity"); 01528 return mpParameters->Physiological().BathConductivity().get(); 01529 } 01530 } 01531 } 01532 const std::set<unsigned>& HeartConfig::rGetTissueIdentifiers() 01533 { 01534 return mTissueIdentifiers; 01535 } 01536 01537 const std::set<unsigned>& HeartConfig::rGetBathIdentifiers() 01538 { 01539 return mBathIdentifiers; 01540 } 01541 01542 double HeartConfig::GetSurfaceAreaToVolumeRatio() const 01543 { 01544 CHECK_EXISTS(mpParameters->Physiological().SurfaceAreaToVolumeRatio().present(), "Physiological/SurfaceAreaToVolumeRatio"); 01545 return mpParameters->Physiological().SurfaceAreaToVolumeRatio().get(); 01546 } 01547 01548 double HeartConfig::GetCapacitance() const 01549 { 01550 CHECK_EXISTS(mpParameters->Physiological().Capacitance().present(), "Physiological/Capacitance"); 01551 return mpParameters->Physiological().Capacitance().get(); 01552 } 01553 01554 double HeartConfig::GetOdeTimeStep() const 01555 { 01556 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps"); 01557 return mpParameters->Numerical().TimeSteps()->ode(); 01558 } 01559 01560 double HeartConfig::GetPdeTimeStep() const 01561 { 01562 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps"); 01563 return mpParameters->Numerical().TimeSteps()->pde(); 01564 } 01565 01566 double HeartConfig::GetPrintingTimeStep() const 01567 { 01568 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps"); 01569 return mpParameters->Numerical().TimeSteps()->printing(); 01570 } 01571 01572 bool HeartConfig::GetUseAbsoluteTolerance() const 01573 { 01574 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances"); 01575 return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().present(); 01576 } 01577 01578 double HeartConfig::GetAbsoluteTolerance() const 01579 { 01580 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances"); 01581 if (!GetUseAbsoluteTolerance()) 01582 { 01583 EXCEPTION("Absolute tolerance is not set in Chaste parameters"); 01584 } 01585 return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().get(); 01586 } 01587 01588 bool HeartConfig::GetUseRelativeTolerance() const 01589 { 01590 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances"); 01591 return mpParameters->Numerical().KSPTolerances()->KSPRelative().present(); 01592 } 01593 01594 double HeartConfig::GetRelativeTolerance() const 01595 { 01596 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances"); 01597 if (!GetUseRelativeTolerance()) 01598 { 01599 EXCEPTION("Relative tolerance is not set in Chaste parameters"); 01600 } 01601 return mpParameters->Numerical().KSPTolerances()->KSPRelative().get(); 01602 } 01603 01604 const char* HeartConfig::GetKSPSolver() const 01605 { 01606 CHECK_EXISTS(mpParameters->Numerical().KSPSolver().present(), "Numerical/KSPSolver"); 01607 switch (mpParameters->Numerical().KSPSolver().get()) 01608 { 01609 case cp::ksp_solver_type::gmres : 01610 return "gmres"; 01611 case cp::ksp_solver_type::cg : 01612 return "cg"; 01613 case cp::ksp_solver_type::symmlq : 01614 return "symmlq"; 01615 case cp::ksp_solver_type::chebychev : 01616 return "chebychev"; 01617 } 01618 #define COVERAGE_IGNORE 01619 EXCEPTION("Unknown ksp solver"); 01620 #undef COVERAGE_IGNORE 01621 } 01622 01623 const char* HeartConfig::GetKSPPreconditioner() const 01624 { 01625 CHECK_EXISTS(mpParameters->Numerical().KSPPreconditioner().present(), "Numerical/KSPPreconditioner"); 01626 switch ( mpParameters->Numerical().KSPPreconditioner().get() ) 01627 { 01628 case cp::ksp_preconditioner_type::jacobi : 01629 return "jacobi"; 01630 case cp::ksp_preconditioner_type::bjacobi : 01631 return "bjacobi"; 01632 case cp::ksp_preconditioner_type::hypre : 01633 return "hypre"; 01634 case cp::ksp_preconditioner_type::ml : 01635 return "ml"; 01636 case cp::ksp_preconditioner_type::spai : 01637 return "spai"; 01638 case cp::ksp_preconditioner_type::blockdiagonal : 01639 return "blockdiagonal"; 01640 case cp::ksp_preconditioner_type::ldufactorisation : 01641 return "ldufactorisation"; 01642 case cp::ksp_preconditioner_type::twolevelsblockdiagonal : 01643 return "twolevelsblockdiagonal"; 01644 case cp::ksp_preconditioner_type::none : 01645 return "none"; 01646 01647 } 01648 #define COVERAGE_IGNORE 01649 EXCEPTION("Unknown ksp preconditioner"); 01650 #undef COVERAGE_IGNORE 01651 } 01652 01653 DistributedTetrahedralMeshPartitionType::type HeartConfig::GetMeshPartitioning() const 01654 { 01655 CHECK_EXISTS(mpParameters->Numerical().MeshPartitioning().present(), "Numerical/MeshPartitioning"); 01656 switch ( mpParameters->Numerical().MeshPartitioning().get() ) 01657 { 01658 case cp::mesh_partitioning_type::dumb : 01659 return DistributedTetrahedralMeshPartitionType::DUMB; 01660 case cp::mesh_partitioning_type::metis : 01661 return DistributedTetrahedralMeshPartitionType::METIS_LIBRARY; 01662 case cp::mesh_partitioning_type::parmetis : 01663 return DistributedTetrahedralMeshPartitionType::PARMETIS_LIBRARY; 01664 case cp::mesh_partitioning_type::petsc : 01665 return DistributedTetrahedralMeshPartitionType::PETSC_MAT_PARTITION; 01666 } 01667 #define COVERAGE_IGNORE 01668 EXCEPTION("Unknown mesh partitioning type"); 01669 #undef COVERAGE_IGNORE 01670 } 01671 01672 bool HeartConfig::IsAdaptivityParametersPresent() const 01673 { 01674 return mpParameters->Numerical().AdaptivityParameters().present(); 01675 } 01676 01677 double HeartConfig::GetTargetErrorForAdaptivity() const 01678 { 01679 if ( IsAdaptivityParametersPresent() ) 01680 { 01681 return mpParameters->Numerical().AdaptivityParameters()->target_error(); 01682 } 01683 else 01684 { 01685 EXCEPTION("Adaptivity parameters have not been set"); 01686 } 01687 } 01688 01689 double HeartConfig::GetSigmaForAdaptivity() const 01690 { 01691 if ( IsAdaptivityParametersPresent() ) 01692 { 01693 return mpParameters->Numerical().AdaptivityParameters()->sigma(); 01694 } 01695 else 01696 { 01697 EXCEPTION("Adaptivity parameters have not been set"); 01698 } 01699 } 01700 01701 double HeartConfig::GetMaxEdgeLengthForAdaptivity() const 01702 { 01703 if ( IsAdaptivityParametersPresent() ) 01704 { 01705 return mpParameters->Numerical().AdaptivityParameters()->max_edge_length(); 01706 } 01707 else 01708 { 01709 EXCEPTION("Adaptivity parameters have not been set"); 01710 } 01711 } 01712 01713 double HeartConfig::GetMinEdgeLengthForAdaptivity() const 01714 { 01715 if ( IsAdaptivityParametersPresent() ) 01716 { 01717 return mpParameters->Numerical().AdaptivityParameters()->min_edge_length(); 01718 } 01719 else 01720 { 01721 EXCEPTION("Adaptivity parameters have not been set"); 01722 } 01723 } 01724 01725 double HeartConfig::GetGradationForAdaptivity() const 01726 { 01727 if ( IsAdaptivityParametersPresent() ) 01728 { 01729 return mpParameters->Numerical().AdaptivityParameters()->gradation(); 01730 } 01731 else 01732 { 01733 EXCEPTION("Adaptivity parameters have not been set"); 01734 } 01735 } 01736 01737 unsigned HeartConfig::GetMaxNodesForAdaptivity() const 01738 { 01739 if ( IsAdaptivityParametersPresent() ) 01740 { 01741 return mpParameters->Numerical().AdaptivityParameters()->max_nodes(); 01742 } 01743 else 01744 { 01745 EXCEPTION("Adaptivity parameters have not been set"); 01746 } 01747 } 01748 01749 unsigned HeartConfig::GetNumberOfAdaptiveSweeps() const 01750 { 01751 if ( IsAdaptivityParametersPresent() ) 01752 { 01753 return mpParameters->Numerical().AdaptivityParameters()->num_sweeps(); 01754 } 01755 else 01756 { 01757 EXCEPTION("Adaptivity parameters have not been set"); 01758 } 01759 } 01760 01761 /* 01762 * PostProcessing 01763 */ 01764 01765 bool HeartConfig::IsPostProcessingSectionPresent() const 01766 { 01767 return mpParameters->PostProcessing().present(); 01768 } 01769 01770 void HeartConfig::EnsurePostProcessingSectionPresent() 01771 { 01772 ENSURE_SECTION_PRESENT(mpParameters->PostProcessing(), cp::postprocessing_type); 01773 } 01774 01775 bool HeartConfig::IsPostProcessingRequested() const 01776 { 01777 if (IsPostProcessingSectionPresent() == false) 01778 { 01779 return false; 01780 } 01781 else 01782 { 01783 return(IsApdMapsRequested() || 01784 IsUpstrokeTimeMapsRequested() || 01785 IsMaxUpstrokeVelocityMapRequested() || 01786 IsConductionVelocityMapsRequested() || 01787 IsAnyNodalTimeTraceRequested()|| 01788 IsPseudoEcgCalculationRequested()); 01789 } 01790 } 01791 bool HeartConfig::IsApdMapsRequested() const 01792 { 01793 bool result = false; 01794 if (IsPostProcessingSectionPresent()) 01795 { 01796 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)& 01797 apd_maps = mpParameters->PostProcessing()->ActionPotentialDurationMap(); 01798 result = (apd_maps.begin() != apd_maps.end()); 01799 } 01800 return result; 01801 } 01802 01803 void HeartConfig::GetApdMaps(std::vector<std::pair<double,double> >& apd_maps) const 01804 { 01805 CHECK_EXISTS(IsApdMapsRequested(), "PostProcessing/ActionPotentialDurationMap"); 01806 apd_maps.clear(); 01807 01808 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)& 01809 apd_maps_sequence = mpParameters->PostProcessing()->ActionPotentialDurationMap(); 01810 01811 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ActionPotentialDurationMap) i = apd_maps_sequence.begin(); 01812 i != apd_maps_sequence.end(); 01813 ++i) 01814 { 01815 std::pair<double,double> map(i->repolarisation_percentage(),i->threshold()); 01816 01817 apd_maps.push_back(map); 01818 } 01819 } 01820 01821 bool HeartConfig::IsUpstrokeTimeMapsRequested() const 01822 { 01823 bool result = false; 01824 if (IsPostProcessingSectionPresent()) 01825 { 01826 XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)& 01827 upstroke_map = mpParameters->PostProcessing()->UpstrokeTimeMap(); 01828 result = (upstroke_map.begin() != upstroke_map.end()); 01829 } 01830 return result; 01831 } 01832 void HeartConfig::GetUpstrokeTimeMaps (std::vector<double>& upstroke_time_maps) const 01833 { 01834 CHECK_EXISTS(IsUpstrokeTimeMapsRequested(), "PostProcessing/UpstrokeTimeMap"); 01835 assert(upstroke_time_maps.size() == 0); 01836 01837 XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)& 01838 upstroke_maps_sequence = mpParameters->PostProcessing()->UpstrokeTimeMap(); 01839 01840 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::UpstrokeTimeMap) i = upstroke_maps_sequence.begin(); 01841 i != upstroke_maps_sequence.end(); 01842 ++i) 01843 { 01844 upstroke_time_maps.push_back(i->threshold()); 01845 } 01846 } 01847 01848 bool HeartConfig::IsMaxUpstrokeVelocityMapRequested() const 01849 { 01850 bool result = false; 01851 if (IsPostProcessingSectionPresent()) 01852 { 01853 XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)& 01854 max_upstroke_velocity_map = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap(); 01855 result = (max_upstroke_velocity_map.begin() != max_upstroke_velocity_map.end()); 01856 } 01857 return result; 01858 } 01859 01860 void HeartConfig::GetMaxUpstrokeVelocityMaps(std::vector<double>& upstroke_velocity_maps) const 01861 { 01862 CHECK_EXISTS(IsMaxUpstrokeVelocityMapRequested(), "PostProcessing/MaxUpstrokeVelocityMap"); 01863 assert(upstroke_velocity_maps.size() == 0); 01864 01865 XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)& 01866 max_upstroke_velocity_maps_sequence = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap(); 01867 01868 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap) i = max_upstroke_velocity_maps_sequence.begin(); 01869 i != max_upstroke_velocity_maps_sequence.end(); 01870 ++i) 01871 { 01872 upstroke_velocity_maps.push_back(i->threshold()); 01873 } 01874 } 01875 01876 bool HeartConfig::IsConductionVelocityMapsRequested() const 01877 { 01878 bool result = false; 01879 if (IsPostProcessingSectionPresent()) 01880 { 01881 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)& 01882 cond_vel_maps = mpParameters->PostProcessing()->ConductionVelocityMap(); 01883 result = (cond_vel_maps.begin() != cond_vel_maps.end()); 01884 } 01885 return result; 01886 } 01887 01888 void HeartConfig::GetConductionVelocityMaps(std::vector<unsigned>& conduction_velocity_maps) const 01889 { 01890 CHECK_EXISTS(IsConductionVelocityMapsRequested(), "PostProcessing/ConductionVelocityMap"); 01891 assert(conduction_velocity_maps.size() == 0); 01892 01893 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)& 01894 cond_vel_maps_sequence = mpParameters->PostProcessing()->ConductionVelocityMap(); 01895 01896 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ConductionVelocityMap) i = cond_vel_maps_sequence.begin(); 01897 i != cond_vel_maps_sequence.end(); 01898 ++i) 01899 { 01900 conduction_velocity_maps.push_back(i->origin_node()); 01901 } 01902 } 01903 01904 bool HeartConfig::IsAnyNodalTimeTraceRequested() const 01905 { 01906 bool result = false; 01907 if (IsPostProcessingSectionPresent()) 01908 { 01909 XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)& 01910 requested_nodes = mpParameters->PostProcessing()->TimeTraceAtNode(); 01911 result = (requested_nodes.begin() != requested_nodes.end()); 01912 } 01913 return result; 01914 } 01915 01916 void HeartConfig::GetNodalTimeTraceRequested(std::vector<unsigned>& rRequestedNodes) const 01917 { 01918 CHECK_EXISTS(IsAnyNodalTimeTraceRequested(), "PostProcessing/TimeTraceAtNode"); 01919 assert(rRequestedNodes.size() == 0); 01920 01921 XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)& 01922 req_nodes = mpParameters->PostProcessing()->TimeTraceAtNode(); 01923 01924 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::TimeTraceAtNode) i = req_nodes.begin(); 01925 i != req_nodes.end(); 01926 ++i) 01927 { 01928 rRequestedNodes.push_back(i->node_number()); 01929 } 01930 } 01931 01932 01933 bool HeartConfig::IsPseudoEcgCalculationRequested() const 01934 { 01935 bool result = false; 01936 if (IsPostProcessingSectionPresent()) 01937 { 01938 XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)& 01939 electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition(); 01940 result = (electrodes.begin() != electrodes.end()); 01941 } 01942 return result; 01943 } 01944 01945 template<unsigned SPACE_DIM> 01946 void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions) const 01947 { 01948 rPseudoEcgElectrodePositions.clear(); 01949 XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)& 01950 electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition(); 01951 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition) i = electrodes.begin(); 01952 i != electrodes.end(); 01953 ++i) 01954 { 01955 rPseudoEcgElectrodePositions.push_back(ChastePoint<SPACE_DIM>(i->x(), i->y(), i->z())); 01956 } 01957 } 01958 01959 01960 /* 01961 * Output visualization 01962 */ 01963 01964 bool HeartConfig::IsOutputVisualizerPresent() const 01965 { 01966 CheckSimulationIsDefined("OutputVisualizer"); 01967 01968 return mpParameters->Simulation()->OutputVisualizer().present(); 01969 } 01970 01971 bool HeartConfig::GetVisualizeWithMeshalyzer() const 01972 { 01973 if (!IsOutputVisualizerPresent()) 01974 { 01975 return true; 01976 } 01977 else 01978 { 01979 return mpParameters->Simulation()->OutputVisualizer()->meshalyzer() == cp::yesno_type::yes; 01980 } 01981 } 01982 01983 bool HeartConfig::GetVisualizeWithCmgui() const 01984 { 01985 if (!IsOutputVisualizerPresent()) 01986 { 01987 return false; 01988 } 01989 else 01990 { 01991 return mpParameters->Simulation()->OutputVisualizer()->cmgui() == cp::yesno_type::yes; 01992 } 01993 } 01994 01995 bool HeartConfig::GetVisualizeWithParallelVtk() const 01996 { 01997 if (!IsOutputVisualizerPresent()) 01998 { 01999 return false; 02000 } 02001 else 02002 { 02003 return mpParameters->Simulation()->OutputVisualizer()->parallel_vtk() == cp::yesno_type::yes; 02004 } 02005 } 02006 02007 bool HeartConfig::GetVisualizeWithVtk() const 02008 { 02009 if (!IsOutputVisualizerPresent()) 02010 { 02011 return false; 02012 } 02013 else 02014 { 02015 return mpParameters->Simulation()->OutputVisualizer()->vtk() == cp::yesno_type::yes; 02016 } 02017 } 02018 02019 unsigned HeartConfig::GetVisualizerOutputPrecision() 02020 { 02021 if (!IsOutputVisualizerPresent()) 02022 { 02023 return 0u; 02024 } 02025 else 02026 { 02027 return mpParameters->Simulation()->OutputVisualizer()->precision(); 02028 } 02029 } 02030 02031 02032 bool HeartConfig::IsElectrodesPresent() const 02033 { 02034 return mpParameters->Simulation()->Electrodes().present(); 02035 } 02036 02037 /* 02038 * Set methods 02039 */ 02040 void HeartConfig::SetSpaceDimension(unsigned spaceDimension) 02041 { 02042 mpParameters->Simulation()->SpaceDimension().set(spaceDimension); 02043 } 02044 02045 void HeartConfig::SetSimulationDuration(double simulationDuration) 02046 { 02047 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, time, simulationDuration, "ms"); 02048 mpParameters->Simulation()->SimulationDuration().set(time); 02049 } 02050 02051 void HeartConfig::SetDomain(const cp::domain_type& rDomain) 02052 { 02053 mpParameters->Simulation()->Domain().set(rDomain); 02054 } 02055 02056 void HeartConfig::SetDefaultIonicModel(const cp::ionic_models_available_type& rIonicModel) 02057 { 02058 cp::ionic_model_selection_type ionic_model; 02059 ionic_model.Hardcoded(rIonicModel); 02060 cp::ionic_models_type container(ionic_model); 02061 mpParameters->Simulation()->IonicModels().set(container); 02062 } 02063 02064 void HeartConfig::SetSlabDimensions(double x, double y, double z, double inter_node_space) 02065 { 02066 if ( ! mpParameters->Simulation()->Mesh().present()) 02067 { 02068 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm"); 02069 mpParameters->Simulation()->Mesh().set(mesh_to_load); 02070 } 02071 02072 cp::slab_type slab_definition(x, y, z, inter_node_space); 02073 mpParameters->Simulation()->Mesh()->Slab().set(slab_definition); 02074 } 02075 02076 void HeartConfig::SetSheetDimensions(double x, double y, double inter_node_space) 02077 { 02078 if ( ! mpParameters->Simulation()->Mesh().present()) 02079 { 02080 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm"); 02081 mpParameters->Simulation()->Mesh().set(mesh_to_load); 02082 } 02083 02084 cp::sheet_type sheet_definition(x, y, inter_node_space); 02085 mpParameters->Simulation()->Mesh()->Sheet().set(sheet_definition); 02086 } 02087 02088 void HeartConfig::SetFibreLength(double x, double inter_node_space) 02089 { 02090 if ( ! mpParameters->Simulation()->Mesh().present()) 02091 { 02092 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm"); 02093 mpParameters->Simulation()->Mesh().set(mesh_to_load); 02094 } 02095 02096 cp::fibre_type fibre_definition(x, inter_node_space); 02097 mpParameters->Simulation()->Mesh()->Fibre().set(fibre_definition); 02098 } 02099 02100 void HeartConfig::SetMeshFileName(std::string meshPrefix, cp::media_type fibreDefinition) 02101 { 02102 if ( ! mpParameters->Simulation()->Mesh().present()) 02103 { 02104 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm"); 02105 mpParameters->Simulation()->Mesh().set(mesh_to_load); 02106 } 02107 02108 XSD_NESTED_TYPE(cp::mesh_type::LoadMesh) mesh_prefix(meshPrefix, fibreDefinition); 02109 mpParameters->Simulation()->Mesh()->LoadMesh().set(mesh_prefix); 02110 } 02111 02112 void HeartConfig::SetIonicModelRegions(std::vector<ChasteCuboid<3> >& rDefinedRegions, 02113 std::vector<cp::ionic_model_selection_type>& rIonicModels) const 02114 { 02115 assert(rDefinedRegions.size() == rIonicModels.size()); 02116 // You need to have defined a default model first... 02117 assert(mpParameters->Simulation()->IonicModels().present()); 02118 XSD_SEQUENCE_TYPE(cp::ionic_models_type::Region)& 02119 regions = mpParameters->Simulation()->IonicModels()->Region(); 02120 regions.clear(); 02121 for (unsigned region_index=0; region_index<rDefinedRegions.size(); region_index++) 02122 { 02123 cp::point_type point_a(rDefinedRegions[region_index].rGetLowerCorner()[0], 02124 rDefinedRegions[region_index].rGetLowerCorner()[1], 02125 rDefinedRegions[region_index].rGetLowerCorner()[2]); 02126 02127 cp::point_type point_b(rDefinedRegions[region_index].rGetUpperCorner()[0], 02128 rDefinedRegions[region_index].rGetUpperCorner()[1], 02129 rDefinedRegions[region_index].rGetUpperCorner()[2]); 02130 02131 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm"); 02132 locn.Cuboid().set(cp::box_type(point_a, point_b)); 02133 02134 cp::ionic_model_region_type region(rIonicModels[region_index], locn); 02135 regions.push_back(region); 02136 } 02137 } 02138 02139 void HeartConfig::SetConductivityHeterogeneities(std::vector<ChasteCuboid<3> >& conductivityAreas, 02140 std::vector< c_vector<double,3> >& intraConductivities, 02141 std::vector< c_vector<double,3> >& extraConductivities) 02142 { 02143 assert ( conductivityAreas.size() == intraConductivities.size() ); 02144 assert ( intraConductivities.size() == extraConductivities.size()); 02145 02146 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) heterogeneities_container; 02147 02148 for (unsigned region_index=0; region_index<conductivityAreas.size(); region_index++) 02149 { 02150 cp::point_type point_a(conductivityAreas[region_index].rGetLowerCorner()[0], 02151 conductivityAreas[region_index].rGetLowerCorner()[1], 02152 conductivityAreas[region_index].rGetLowerCorner()[2]); 02153 02154 cp::point_type point_b(conductivityAreas[region_index].rGetUpperCorner()[0], 02155 conductivityAreas[region_index].rGetUpperCorner()[1], 02156 conductivityAreas[region_index].rGetUpperCorner()[2]); 02157 02158 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm"); 02159 locn.Cuboid().set(cp::box_type(point_a, point_b)); 02160 cp::conductivity_heterogeneity_type ht(locn); 02161 02162 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra, 02163 intraConductivities[region_index][0], 02164 intraConductivities[region_index][1], 02165 intraConductivities[region_index][2], 02166 "mS/cm"); 02167 02168 ht.IntracellularConductivities(intra); 02169 02170 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra, 02171 extraConductivities[region_index][0], 02172 extraConductivities[region_index][1], 02173 extraConductivities[region_index][2], 02174 "mS/cm"); 02175 02176 ht.ExtracellularConductivities(extra); 02177 02178 heterogeneities_container.push_back(ht); 02179 } 02180 02181 XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities) heterogeneities_object; 02182 heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container); 02183 02184 mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object); 02185 } 02186 02187 void HeartConfig::SetConductivityHeterogeneitiesEllipsoid(std::vector<ChasteEllipsoid<3> >& conductivityAreas, 02188 std::vector< c_vector<double,3> >& intraConductivities, 02189 std::vector< c_vector<double,3> >& extraConductivities) 02190 { 02191 assert ( conductivityAreas.size() == intraConductivities.size() ); 02192 assert ( intraConductivities.size() == extraConductivities.size()); 02193 02194 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) heterogeneities_container; 02195 02196 for (unsigned region_index=0; region_index<conductivityAreas.size(); region_index++) 02197 { 02198 cp::point_type centre(conductivityAreas[region_index].rGetCentre()[0], 02199 conductivityAreas[region_index].rGetCentre()[1], 02200 conductivityAreas[region_index].rGetCentre()[2]); 02201 02202 cp::point_type radii(conductivityAreas[region_index].rGetRadii()[0], 02203 conductivityAreas[region_index].rGetRadii()[1], 02204 conductivityAreas[region_index].rGetRadii()[2]); 02205 02206 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm"); 02207 locn.Ellipsoid().set(cp::ellipsoid_type(centre, radii)); 02208 cp::conductivity_heterogeneity_type ht(locn); 02209 02210 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra, 02211 intraConductivities[region_index][0], 02212 intraConductivities[region_index][1], 02213 intraConductivities[region_index][2], 02214 "mS/cm"); 02215 02216 ht.IntracellularConductivities(intra); 02217 02218 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra, 02219 extraConductivities[region_index][0], 02220 extraConductivities[region_index][1], 02221 extraConductivities[region_index][2], 02222 "mS/cm"); 02223 02224 ht.ExtracellularConductivities(extra); 02225 02226 heterogeneities_container.push_back(ht); 02227 } 02228 02229 XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities) heterogeneities_object; 02230 heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container); 02231 02232 mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object); 02233 } 02234 02235 void HeartConfig::SetOutputDirectory(const std::string& rOutputDirectory) 02236 { 02237 mpParameters->Simulation()->OutputDirectory().set(rOutputDirectory); 02238 } 02239 02240 void HeartConfig::SetOutputFilenamePrefix(const std::string& rOutputFilenamePrefix) 02241 { 02242 mpParameters->Simulation()->OutputFilenamePrefix().set(rOutputFilenamePrefix); 02243 } 02244 02245 void HeartConfig::SetOutputVariables(const std::vector<std::string>& rOutputVariables) 02246 { 02247 if ( ! mpParameters->Simulation()->OutputVariables().present()) 02248 { 02249 cp::output_variables_type variables_requested; 02250 mpParameters->Simulation()->OutputVariables().set(variables_requested); 02251 } 02252 02253 XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)& 02254 var_type_sequence = mpParameters->Simulation()->OutputVariables()->Var(); 02255 //Erase or create a sequence 02256 var_type_sequence.clear(); 02257 02258 for (unsigned i=0; i<rOutputVariables.size(); i++) 02259 { 02260 cp::var_type temp(rOutputVariables[i]); 02261 var_type_sequence.push_back(temp); 02262 } 02263 } 02264 02265 void HeartConfig::SetOutputUsingOriginalNodeOrdering(bool useOriginal) 02266 { 02267 //What if it doesn't exist? 02268 mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().set(useOriginal? cp::yesno_type::yes : cp::yesno_type::no); 02269 } 02270 02271 void HeartConfig::SetCheckpointSimulation(bool saveSimulation, double checkpointTimestep, unsigned maxCheckpointsOnDisk) 02272 { 02273 if (saveSimulation) 02274 { 02275 // Make sure values for the optional parameters have been provided 02276 assert(checkpointTimestep!=-1.0 && maxCheckpointsOnDisk!=UINT_MAX); 02277 02278 XSD_CREATE_WITH_FIXED_ATTR2(cp::simulation_type::XSD_NESTED_TYPE(CheckpointSimulation), 02279 cs, 02280 checkpointTimestep, 02281 maxCheckpointsOnDisk, 02282 "ms"); 02283 mpParameters->Simulation()->CheckpointSimulation().set(cs); 02284 } 02285 else 02286 { 02287 mpParameters->Simulation()->CheckpointSimulation().reset(); 02288 } 02289 02290 CheckTimeSteps(); 02291 } 02292 02293 // Physiological 02294 02295 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 3>& intraConductivities) 02296 { 02297 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra, 02298 intraConductivities[0], 02299 intraConductivities[1], 02300 intraConductivities[2], 02301 "mS/cm"); 02302 02303 mpParameters->Physiological().IntracellularConductivities().set(intra); 02304 } 02305 02306 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 2>& intraConductivities) 02307 { 02308 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra, 02309 intraConductivities[0], 02310 intraConductivities[1], 02311 0.0, "mS/cm"); 02312 02313 mpParameters->Physiological().IntracellularConductivities().set(intra); 02314 } 02315 02316 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 1>& intraConductivities) 02317 { 02318 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra, 02319 intraConductivities[0], 02320 0.0, 0.0, "mS/cm"); 02321 02322 mpParameters->Physiological().IntracellularConductivities().set(intra); 02323 } 02324 02325 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 3>& extraConductivities) 02326 { 02327 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra, 02328 extraConductivities[0], 02329 extraConductivities[1], 02330 extraConductivities[2], 02331 "mS/cm"); 02332 02333 mpParameters->Physiological().ExtracellularConductivities().set(extra); 02334 } 02335 02336 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 2>& extraConductivities) 02337 { 02338 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra, 02339 extraConductivities[0], 02340 extraConductivities[1], 02341 0.0, "mS/cm"); 02342 02343 mpParameters->Physiological().ExtracellularConductivities().set(extra); 02344 } 02345 02346 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 1>& extraConductivities) 02347 { 02348 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra, 02349 extraConductivities[0], 02350 0.0, 0.0, "mS/cm"); 02351 02352 mpParameters->Physiological().ExtracellularConductivities().set(extra); 02353 } 02354 02355 void HeartConfig::SetBathConductivity(double bathConductivity) 02356 { 02357 XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, cond, bathConductivity, "mS/cm"); 02358 mpParameters->Physiological().BathConductivity().set(cond); 02359 } 02360 02361 void HeartConfig::SetBathMultipleConductivities(std::map<unsigned, double> bathConductivities) 02362 { 02364 mBathConductivities = bathConductivities; 02365 } 02366 02367 //void HeartConfig::SetTissueIdentifiers(const std::set<unsigned>& tissueIds) 02368 //{ 02369 // std::set<unsigned> empty_bath_identifiers; //Too dangerous (see GetValidBathId) 02370 // SetTissueAndBathIdentifiers(tissueIds, mBathIdentifiers); 02371 //} 02372 02373 void HeartConfig::SetTissueAndBathIdentifiers(const std::set<unsigned>& tissueIds, const std::set<unsigned>& bathIds) 02374 { 02375 if (tissueIds.empty() || bathIds.empty() ) 02376 { 02377 EXCEPTION("Identifying set must be non-empty"); 02378 } 02379 std::set<unsigned> shared_identifiers; 02380 std::set_intersection(tissueIds.begin(), 02381 tissueIds.end(), 02382 bathIds.begin(), 02383 bathIds.end(), 02384 std::inserter(shared_identifiers, shared_identifiers.begin())); 02385 02386 if (!shared_identifiers.empty()) 02387 { 02388 EXCEPTION("Tissue identifiers and bath identifiers overlap"); 02389 } 02390 mTissueIdentifiers=tissueIds; 02391 mBathIdentifiers=bathIds; 02392 } 02393 02394 void HeartConfig::SetSurfaceAreaToVolumeRatio(double ratio) 02395 { 02396 XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, ratio_object, ratio, "1/cm"); 02397 mpParameters->Physiological().SurfaceAreaToVolumeRatio().set(ratio_object); 02398 } 02399 02400 void HeartConfig::SetCapacitance(double capacitance) 02401 { 02402 XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, capacitance_object, capacitance, "uF/cm^2"); 02403 mpParameters->Physiological().Capacitance().set(capacitance_object); 02404 } 02405 02406 02407 // Numerical 02408 void HeartConfig::SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep) 02409 { 02410 XSD_CREATE_WITH_FIXED_ATTR3(cp::time_steps_type, time_steps, 02411 odeTimeStep, pdeTimeStep, printingTimeStep, "ms"); 02412 mpParameters->Numerical().TimeSteps().set(time_steps); 02413 CheckTimeSteps(); 02414 } 02415 02416 void HeartConfig::SetOdeTimeStep(double odeTimeStep) 02417 { 02418 SetOdePdeAndPrintingTimeSteps(odeTimeStep, GetPdeTimeStep(), GetPrintingTimeStep()); 02419 } 02420 02421 void HeartConfig::SetPdeTimeStep(double pdeTimeStep) 02422 { 02423 SetOdePdeAndPrintingTimeSteps(GetOdeTimeStep(), pdeTimeStep, GetPrintingTimeStep()); 02424 } 02425 02426 void HeartConfig::SetPrintingTimeStep(double printingTimeStep) 02427 { 02428 SetOdePdeAndPrintingTimeSteps(GetOdeTimeStep(), GetPdeTimeStep(), printingTimeStep); 02429 } 02430 02431 void HeartConfig::CheckTimeSteps() const 02432 { 02433 if (GetOdeTimeStep() <= 0) 02434 { 02435 EXCEPTION("Ode time-step should be positive"); 02436 } 02437 if (GetPdeTimeStep() <= 0) 02438 { 02439 EXCEPTION("Pde time-step should be positive"); 02440 } 02441 if (GetPrintingTimeStep() <= 0.0) 02442 { 02443 EXCEPTION("Printing time-step should be positive"); 02444 } 02445 02446 if (GetPdeTimeStep()>GetPrintingTimeStep()) 02447 { 02448 EXCEPTION("Printing time-step should not be smaller than PDE time-step"); 02449 } 02450 02451 if ( !Divides(GetPdeTimeStep(), GetPrintingTimeStep()) ) 02452 { 02453 EXCEPTION("Printing time-step should be a multiple of PDE time step"); 02454 } 02455 02456 if ( GetOdeTimeStep() > GetPdeTimeStep() ) 02457 { 02458 EXCEPTION("Ode time-step should not be greater than PDE time-step"); 02459 } 02460 02461 if (GetCheckpointSimulation()) 02462 { 02463 if (GetCheckpointTimestep() <= 0.0) 02464 { 02465 EXCEPTION("Checkpoint time-step should be positive"); 02466 } 02467 02468 if ( !Divides(GetPrintingTimeStep(), GetCheckpointTimestep()) ) 02469 { 02470 EXCEPTION("Checkpoint time-step should be a multiple of printing time-step"); 02471 } 02472 } 02473 } 02474 02475 02476 void HeartConfig::SetUseRelativeTolerance(double relativeTolerance) 02477 { 02478 ENSURE_SECTION_PRESENT(mpParameters->Numerical().KSPTolerances(), cp::ksp_tolerances_type); 02479 //Remove any reference to tolerances is user parameters 02480 mpParameters->Numerical().KSPTolerances()->KSPAbsolute().reset(); 02481 mpParameters->Numerical().KSPTolerances()->KSPRelative().set(relativeTolerance); 02482 } 02483 02484 void HeartConfig::SetUseAbsoluteTolerance(double absoluteTolerance) 02485 { 02486 ENSURE_SECTION_PRESENT(mpParameters->Numerical().KSPTolerances(), cp::ksp_tolerances_type); 02487 //Remove any reference to tolerances is user parameters 02488 mpParameters->Numerical().KSPTolerances()->KSPRelative().reset(); 02489 mpParameters->Numerical().KSPTolerances()->KSPAbsolute().set(absoluteTolerance); 02490 } 02491 02492 void HeartConfig::SetKSPSolver(const char* kspSolver) 02493 { 02494 /* Note that changes in these conditions need to be reflected in the Doxygen*/ 02495 if ( strcmp(kspSolver, "gmres") == 0) 02496 { 02497 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::gmres); 02498 return; 02499 } 02500 if ( strcmp(kspSolver, "cg") == 0) 02501 { 02502 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::cg); 02503 return; 02504 } 02505 if ( strcmp(kspSolver, "symmlq") == 0) 02506 { 02507 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::symmlq); 02508 return; 02509 } 02510 if ( strcmp(kspSolver, "chebychev") == 0) 02511 { 02512 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::chebychev); 02513 return; 02514 } 02515 02516 EXCEPTION("Unknown solver type provided"); 02517 } 02518 02519 void HeartConfig::SetKSPPreconditioner(const char* kspPreconditioner) 02520 { 02521 /* Note that changes in these conditions need to be reflected in the Doxygen*/ 02522 if ( strcmp(kspPreconditioner, "jacobi") == 0) 02523 { 02524 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::jacobi); 02525 return; 02526 } 02527 if ( strcmp(kspPreconditioner, "bjacobi") == 0) 02528 { 02529 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::bjacobi); 02530 return; 02531 } 02532 if ( strcmp(kspPreconditioner, "hypre") == 0) 02533 { 02534 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::hypre); 02535 return; 02536 } 02537 if ( strcmp(kspPreconditioner, "ml") == 0) 02538 { 02539 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ml); 02540 return; 02541 } 02542 if ( strcmp(kspPreconditioner, "spai") == 0) 02543 { 02544 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::spai); 02545 return; 02546 } 02547 if ( strcmp(kspPreconditioner, "twolevelsblockdiagonal") == 0) 02548 { 02549 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::twolevelsblockdiagonal); 02550 return; 02551 } 02552 if ( strcmp(kspPreconditioner, "blockdiagonal") == 0) 02553 { 02554 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::blockdiagonal); 02555 return; 02556 } 02557 if ( strcmp(kspPreconditioner, "ldufactorisation") == 0) 02558 { 02559 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ldufactorisation); 02560 return; 02561 } 02562 if ( strcmp(kspPreconditioner, "none") == 0) 02563 { 02564 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::none); 02565 return; 02566 } 02567 02568 EXCEPTION("Unknown preconditioner type provided"); 02569 } 02570 02571 void HeartConfig::SetMeshPartitioning(const char* meshPartioningMethod) 02572 { 02573 /* Note that changes in these conditions need to be reflected in the Doxygen*/ 02574 if ( strcmp(meshPartioningMethod, "dumb") == 0) 02575 { 02576 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::dumb); 02577 return; 02578 } 02579 if ( strcmp(meshPartioningMethod, "metis") == 0) 02580 { 02581 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::metis); 02582 return; 02583 } 02584 if ( strcmp(meshPartioningMethod, "parmetis") == 0) 02585 { 02586 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::parmetis); 02587 return; 02588 } 02589 if ( strcmp(meshPartioningMethod, "petsc") == 0) 02590 { 02591 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::petsc); 02592 return; 02593 } 02594 02595 EXCEPTION("Unknown mesh partitioning method provided"); 02596 } 02597 02598 void HeartConfig::SetAdaptivityParameters(double targetError, 02599 double sigma, 02600 double maxEdgeLength, 02601 double minEdgeLength, 02602 double gradation, 02603 unsigned maxNodes, 02604 unsigned numSweeps ) 02605 { 02606 if ( maxEdgeLength < minEdgeLength ) 02607 { 02608 EXCEPTION("AdaptivityParameters: maxEdgeLength must be greater than minEdgeLength."); 02609 } 02610 02611 cp::adaptivity_parameters_type element(targetError, 02612 sigma, 02613 maxEdgeLength, 02614 minEdgeLength, 02615 gradation, 02616 maxNodes, 02617 numSweeps ); 02618 mpParameters->Numerical().AdaptivityParameters().set(element); 02619 02620 if (IsAdaptivityParametersPresent()) 02621 { 02622 mpParameters->Numerical().AdaptivityParameters()->target_error(targetError); 02623 mpParameters->Numerical().AdaptivityParameters()->sigma(sigma); 02624 mpParameters->Numerical().AdaptivityParameters()->max_edge_length(maxEdgeLength); 02625 mpParameters->Numerical().AdaptivityParameters()->min_edge_length(minEdgeLength); 02626 mpParameters->Numerical().AdaptivityParameters()->gradation(gradation); 02627 mpParameters->Numerical().AdaptivityParameters()->max_nodes(maxNodes); 02628 mpParameters->Numerical().AdaptivityParameters()->num_sweeps(numSweeps); 02629 } 02630 } 02631 02632 void HeartConfig::SetTargetErrorForAdaptivity(double targetError) 02633 { 02634 SetAdaptivityParameters( targetError, 02635 GetSigmaForAdaptivity(), 02636 GetMaxEdgeLengthForAdaptivity(), 02637 GetMinEdgeLengthForAdaptivity(), 02638 GetGradationForAdaptivity(), 02639 GetMaxNodesForAdaptivity(), 02640 GetNumberOfAdaptiveSweeps() ); 02641 } 02642 02643 void HeartConfig::SetSigmaForAdaptivity(double sigma) 02644 { 02645 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02646 sigma, 02647 GetMaxEdgeLengthForAdaptivity(), 02648 GetMinEdgeLengthForAdaptivity(), 02649 GetGradationForAdaptivity(), 02650 GetMaxNodesForAdaptivity(), 02651 GetNumberOfAdaptiveSweeps() ); 02652 } 02653 02654 void HeartConfig::SetMaxEdgeLengthForAdaptivity(double maxEdgeLength) 02655 { 02656 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02657 GetSigmaForAdaptivity(), 02658 maxEdgeLength, 02659 GetMinEdgeLengthForAdaptivity(), 02660 GetGradationForAdaptivity(), 02661 GetMaxNodesForAdaptivity(), 02662 GetNumberOfAdaptiveSweeps() ); 02663 } 02664 02665 void HeartConfig::SetMinEdgeLengthForAdaptivity(double minEdgeLength) 02666 { 02667 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02668 GetSigmaForAdaptivity(), 02669 GetMaxEdgeLengthForAdaptivity(), 02670 minEdgeLength, 02671 GetGradationForAdaptivity(), 02672 GetMaxNodesForAdaptivity(), 02673 GetNumberOfAdaptiveSweeps() ); 02674 } 02675 02676 void HeartConfig::SetGradationForAdaptivity(double gradation) 02677 { 02678 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02679 GetSigmaForAdaptivity(), 02680 GetMaxEdgeLengthForAdaptivity(), 02681 GetMinEdgeLengthForAdaptivity(), 02682 gradation, 02683 GetMaxNodesForAdaptivity(), 02684 GetNumberOfAdaptiveSweeps() ); 02685 } 02686 02687 void HeartConfig::SetMaxNodesForAdaptivity(unsigned maxNodes) 02688 { 02689 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02690 GetSigmaForAdaptivity(), 02691 GetMaxEdgeLengthForAdaptivity(), 02692 GetMinEdgeLengthForAdaptivity(), 02693 GetGradationForAdaptivity(), 02694 maxNodes, 02695 GetNumberOfAdaptiveSweeps() ); 02696 } 02697 02698 void HeartConfig::SetNumberOfAdaptiveSweeps(unsigned numSweeps) 02699 { 02700 SetAdaptivityParameters( GetTargetErrorForAdaptivity(), 02701 GetSigmaForAdaptivity(), 02702 GetMaxEdgeLengthForAdaptivity(), 02703 GetMinEdgeLengthForAdaptivity(), 02704 GetGradationForAdaptivity(), 02705 GetMaxNodesForAdaptivity(), 02706 numSweeps ); 02707 } 02708 02709 void HeartConfig::SetApdMaps(const std::vector<std::pair<double,double> >& apdMaps) 02710 { 02711 EnsurePostProcessingSectionPresent(); 02712 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)& apd_maps_sequence 02713 = mpParameters->PostProcessing()->ActionPotentialDurationMap(); 02714 //Erase or create a sequence 02715 apd_maps_sequence.clear(); 02716 02717 for (unsigned i=0; i<apdMaps.size(); i++) 02718 { 02719 XSD_CREATE_WITH_FIXED_ATTR2(cp::apd_map_type, temp, 02720 apdMaps[i].first, apdMaps[i].second, 02721 "mV"); 02722 apd_maps_sequence.push_back( temp); 02723 } 02724 } 02725 02726 02727 void HeartConfig::SetUpstrokeTimeMaps (std::vector<double>& upstrokeTimeMaps) 02728 { 02729 EnsurePostProcessingSectionPresent(); 02730 XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)& var_type_sequence 02731 = mpParameters->PostProcessing()->UpstrokeTimeMap(); 02732 02733 //Erase or create a sequence 02734 var_type_sequence.clear(); 02735 02736 for (unsigned i=0; i<upstrokeTimeMaps.size(); i++) 02737 { 02738 XSD_CREATE_WITH_FIXED_ATTR1(cp::upstrokes_map_type, temp, 02739 upstrokeTimeMaps[i], 02740 "mV"); 02741 var_type_sequence.push_back(temp); 02742 } 02743 } 02744 02745 void HeartConfig::SetMaxUpstrokeVelocityMaps (std::vector<double>& maxUpstrokeVelocityMaps) 02746 { 02747 EnsurePostProcessingSectionPresent(); 02748 XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)& max_upstroke_velocity_maps_sequence 02749 = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap(); 02750 02751 //Erase or create a sequence 02752 max_upstroke_velocity_maps_sequence.clear(); 02753 02754 for (unsigned i=0; i<maxUpstrokeVelocityMaps.size(); i++) 02755 { 02756 XSD_CREATE_WITH_FIXED_ATTR1(cp::max_upstrokes_velocity_map_type, temp, 02757 maxUpstrokeVelocityMaps[i], 02758 "mV"); 02759 02760 02761 max_upstroke_velocity_maps_sequence.push_back(temp); 02762 } 02763 02764 } 02765 02766 void HeartConfig::SetConductionVelocityMaps (std::vector<unsigned>& conductionVelocityMaps) 02767 { 02768 EnsurePostProcessingSectionPresent(); 02769 XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)& conduction_velocity_maps_sequence 02770 = mpParameters->PostProcessing()->ConductionVelocityMap(); 02771 02772 //Erase or create a sequence 02773 conduction_velocity_maps_sequence.clear(); 02774 02775 for (unsigned i=0; i<conductionVelocityMaps.size(); i++) 02776 { 02777 cp::conduction_velocity_map_type temp(conductionVelocityMaps[i]); 02778 conduction_velocity_maps_sequence.push_back(temp); 02779 } 02780 } 02781 02782 void HeartConfig::SetRequestedNodalTimeTraces (std::vector<unsigned>& requestedNodes) 02783 { 02784 EnsurePostProcessingSectionPresent(); 02785 XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)& requested_nodes_sequence 02786 = mpParameters->PostProcessing()->TimeTraceAtNode(); 02787 02788 //Erase or create a sequence 02789 requested_nodes_sequence.clear(); 02790 02791 for (unsigned i=0; i<requestedNodes.size(); i++) 02792 { 02793 cp::node_number_type temp(requestedNodes[i]); 02794 requested_nodes_sequence.push_back(temp); 02795 } 02796 } 02797 02798 template<unsigned SPACE_DIM> 02799 void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions) 02800 { 02801 EnsurePostProcessingSectionPresent(); 02802 XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)& electrodes_sequence 02803 = mpParameters->PostProcessing()->PseudoEcgElectrodePosition(); 02804 02805 //Erase or create a sequence 02806 electrodes_sequence.clear(); 02807 02808 for (unsigned i=0; i<rPseudoEcgElectrodePositions.size(); i++) 02809 { 02810 cp::point_type temp(rPseudoEcgElectrodePositions[i].GetWithDefault(0), 02811 rPseudoEcgElectrodePositions[i].GetWithDefault(1), 02812 rPseudoEcgElectrodePositions[i].GetWithDefault(2)); 02813 electrodes_sequence.push_back(temp); 02814 } 02815 } 02816 02817 02818 /* 02819 * Output visualizer 02820 */ 02821 02822 void HeartConfig::EnsureOutputVisualizerExists() 02823 { 02824 ENSURE_SECTION_PRESENT(mpParameters->Simulation()->OutputVisualizer(), cp::output_visualizer_type); 02825 } 02826 02827 void HeartConfig::SetVisualizeWithMeshalyzer(bool useMeshalyzer) 02828 { 02829 EnsureOutputVisualizerExists(); 02830 02831 mpParameters->Simulation()->OutputVisualizer()->meshalyzer( 02832 useMeshalyzer ? cp::yesno_type::yes : cp::yesno_type::no); 02833 } 02834 02835 void HeartConfig::SetVisualizeWithCmgui(bool useCmgui) 02836 { 02837 EnsureOutputVisualizerExists(); 02838 02839 mpParameters->Simulation()->OutputVisualizer()->cmgui( 02840 useCmgui ? cp::yesno_type::yes : cp::yesno_type::no); 02841 } 02842 02843 void HeartConfig::SetVisualizeWithVtk(bool useVtk) 02844 { 02845 EnsureOutputVisualizerExists(); 02846 02847 mpParameters->Simulation()->OutputVisualizer()->vtk( 02848 useVtk ? cp::yesno_type::yes : cp::yesno_type::no); 02849 } 02850 02851 void HeartConfig::SetVisualizeWithParallelVtk(bool useParallelVtk) 02852 { 02853 EnsureOutputVisualizerExists(); 02854 02855 mpParameters->Simulation()->OutputVisualizer()->parallel_vtk( 02856 useParallelVtk ? cp::yesno_type::yes : cp::yesno_type::no); 02857 } 02858 02859 void HeartConfig::SetVisualizerOutputPrecision(unsigned numberOfDigits) 02860 { 02861 EnsureOutputVisualizerExists(); 02862 02863 mpParameters->Simulation()->OutputVisualizer()->precision(numberOfDigits); 02864 } 02865 02866 02867 void HeartConfig::SetElectrodeParameters(bool groundSecondElectrode, 02868 unsigned index, double magnitude, 02869 double startTime, double duration ) 02870 { 02871 assert(index < 3); 02872 02873 cp::axis_type axis = cp::axis_type::x; 02874 if (index==1) 02875 { 02876 axis = cp::axis_type::y; 02877 } 02878 else if (index==2) 02879 { 02880 axis = cp::axis_type::z; 02881 } 02882 02883 XSD_CREATE_WITH_FIXED_ATTR1(cp::surface_stimulus_strength_type, strength, magnitude, "uA/cm^2"); 02884 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, start_time, startTime, "ms"); 02885 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, duration_time, duration, "ms"); 02886 02887 if (!IsElectrodesPresent()) 02888 { 02889 cp::electrodes_type element( groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no, 02890 axis, 02891 strength, 02892 start_time, 02893 duration_time ); 02894 mpParameters->Simulation()->Electrodes().set(element); 02895 } 02896 else 02897 { 02898 mpParameters->Simulation()->Electrodes()->GroundSecondElectrode(groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no); 02899 mpParameters->Simulation()->Electrodes()->PerpendicularToAxis(axis); 02900 mpParameters->Simulation()->Electrodes()->Strength(strength); 02901 mpParameters->Simulation()->Electrodes()->StartTime(start_time); 02902 mpParameters->Simulation()->Electrodes()->Duration(duration_time); 02903 } 02904 } 02905 02906 void HeartConfig::GetElectrodeParameters(bool& rGroundSecondElectrode, 02907 unsigned& rIndex, double& rMagnitude, 02908 double& rStartTime, double& rDuration ) 02909 { 02910 if (!IsElectrodesPresent()) 02911 { 02912 EXCEPTION("Attempted to get electrodes that have not been defined."); 02913 } 02914 else 02915 { 02916 rGroundSecondElectrode = (mpParameters->Simulation()->Electrodes()->GroundSecondElectrode()==cp::yesno_type::yes); 02917 02918 cp::axis_type axis = mpParameters->Simulation()->Electrodes()->PerpendicularToAxis(); 02919 if (axis==cp::axis_type::x) 02920 { 02921 rIndex = 0; 02922 } 02923 else if (axis==cp::axis_type::y) 02924 { 02925 rIndex = 1; 02926 } 02927 else 02928 { 02929 rIndex = 2; 02930 } 02931 02932 rMagnitude = mpParameters->Simulation()->Electrodes()->Strength(); 02933 rStartTime = mpParameters->Simulation()->Electrodes()->StartTime(); 02934 rDuration = mpParameters->Simulation()->Electrodes()->Duration(); 02935 } 02936 02937 } 02938 02939 bool HeartConfig::GetUseStateVariableInterpolation() const 02940 { 02941 // If it's an older version parameters & defaults (we're loading a checkpoint) say 'no' 02942 bool result = false; 02943 if (mpParameters->Numerical().UseStateVariableInterpolation().present()) 02944 { 02945 result = mpParameters->Numerical().UseStateVariableInterpolation().get() == cp::yesno_type::yes; 02946 } 02947 return result; 02948 } 02949 02950 void HeartConfig::SetUseStateVariableInterpolation(bool useStateVariableInterpolation) 02951 { 02952 if (useStateVariableInterpolation) 02953 { 02954 mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::yes); 02955 } 02956 else 02957 { 02958 mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::no); 02959 } 02960 } 02961 02962 02963 02964 bool HeartConfig::HasDrugDose() const 02965 { 02966 return mpParameters->Physiological().ApplyDrug().present(); 02967 } 02968 02969 double HeartConfig::GetDrugDose() const 02970 { 02971 CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug"); 02972 return mpParameters->Physiological().ApplyDrug()->concentration(); 02973 } 02974 02975 void HeartConfig::SetDrugDose(double drugDose) 02976 { 02977 if (!mpParameters->Physiological().ApplyDrug().present()) 02978 { 02979 cp::apply_drug_type drug(drugDose); 02980 mpParameters->Physiological().ApplyDrug().set(drug); 02981 } 02982 else 02983 { 02984 mpParameters->Physiological().ApplyDrug()->concentration(drugDose); 02985 } 02986 } 02987 02988 std::map<std::string, std::pair<double, double> > HeartConfig::GetIc50Values() 02989 { 02990 CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug"); 02991 std::map<std::string, std::pair<double, double> > ic50s; 02992 02993 XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)& 02994 ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50(); 02995 02996 for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin(); 02997 i != ic50_seq.end(); 02998 ++i) 02999 { 03000 std::pair<double, double> ic50_hill(*i, i->hill()); 03001 std::string current = i->current(); 03002 ic50s[current] = ic50_hill; 03003 } 03004 03005 return ic50s; 03006 } 03007 03008 void HeartConfig::SetIc50Value(const std::string& rCurrentName, double ic50, double hill) 03009 { 03010 if (!mpParameters->Physiological().ApplyDrug().present()) 03011 { 03012 SetDrugDose(0.0); 03013 } 03014 XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)& ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50(); 03015 if (ic50_seq.empty()) 03016 { 03017 // Erase or create a sequence 03018 ic50_seq.clear(); 03019 } 03020 bool entry_exists = false; 03021 cp::ic50_type ic50_elt(ic50, rCurrentName); 03022 ic50_elt.hill(hill); 03023 for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin(); 03024 i != ic50_seq.end(); 03025 ++i) 03026 { 03027 if (i->current() == rCurrentName) 03028 { 03029 entry_exists = true; 03030 *i = ic50_elt; 03031 break; 03032 } 03033 } 03034 if (!entry_exists) 03035 { 03036 ic50_seq.push_back(ic50_elt); 03037 } 03038 } 03039 03040 03041 03042 void HeartConfig::SetUseMassLumping(bool useMassLumping) 03043 { 03044 mUseMassLumping = useMassLumping; 03045 } 03046 03047 bool HeartConfig::GetUseMassLumping() 03048 { 03049 return mUseMassLumping; 03050 } 03051 03052 void HeartConfig::SetUseMassLumpingForPrecond(bool useMassLumping) 03053 { 03054 mUseMassLumpingForPrecond = useMassLumping; 03055 } 03056 03057 bool HeartConfig::GetUseMassLumpingForPrecond() 03058 { 03059 return mUseMassLumpingForPrecond; 03060 } 03061 03062 void HeartConfig::SetUseReactionDiffusionOperatorSplitting(bool useOperatorSplitting) 03063 { 03064 mUseReactionDiffusionOperatorSplitting = useOperatorSplitting; 03065 } 03066 03067 bool HeartConfig::GetUseReactionDiffusionOperatorSplitting() 03068 { 03069 return mUseReactionDiffusionOperatorSplitting; 03070 } 03071 03072 void HeartConfig::SetUseFixedNumberIterationsLinearSolver(bool useFixedNumberIterations, unsigned evaluateNumItsEveryNSolves) 03073 { 03074 mUseFixedNumberIterations = useFixedNumberIterations; 03075 mEvaluateNumItsEveryNSolves = evaluateNumItsEveryNSolves; 03076 } 03077 03078 bool HeartConfig::GetUseFixedNumberIterationsLinearSolver() 03079 { 03080 return mUseFixedNumberIterations; 03081 } 03082 03083 unsigned HeartConfig::GetEvaluateNumItsEveryNSolves() 03084 { 03085 return mEvaluateNumItsEveryNSolves; 03086 } 03087 03088 // 03089 // Purkinje methods 03090 // 03091 03092 bool HeartConfig::HasPurkinje() 03093 { 03094 CheckSimulationIsDefined("Purkinje"); 03095 return mpParameters->Simulation()->Purkinje().present(); 03096 } 03097 03098 double HeartConfig::GetPurkinjeCapacitance() 03099 { 03100 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje"); 03101 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Capacitance().present(), 03102 "Physiological/Purkinje/Capacitance"); 03103 return mpParameters->Physiological().Purkinje()->Capacitance().get(); 03104 } 03105 03106 void HeartConfig::SetPurkinjeCapacitance(double capacitance) 03107 { 03108 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type); 03109 XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, purk_Cm, capacitance, "uF/cm^2"); 03110 mpParameters->Physiological().Purkinje()->Capacitance().set(purk_Cm); 03111 } 03112 03113 03114 double HeartConfig::GetPurkinjeSurfaceAreaToVolumeRatio() 03115 { 03116 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje"); 03117 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().present(), 03118 "Physiological/Purkinje/SurfaceAreaToVolumeRatio"); 03119 return mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().get(); 03120 } 03121 03122 void HeartConfig::SetPurkinjeSurfaceAreaToVolumeRatio(double ratio) 03123 { 03124 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type); 03125 XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, purk_Am, ratio, "1/cm"); 03126 mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().set(purk_Am); 03127 } 03128 03129 double HeartConfig::GetPurkinjeConductivity() 03130 { 03131 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje"); 03132 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Conductivity().present(), 03133 "Physiological/Purkinje/Conductivity"); 03134 return mpParameters->Physiological().Purkinje()->Conductivity().get(); 03135 } 03136 03137 void HeartConfig::SetPurkinjeConductivity(double conductivity) 03138 { 03139 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type); 03140 XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, purkinje_conductivity, conductivity, "mS/cm"); 03141 mpParameters->Physiological().Purkinje()->Conductivity().set(purkinje_conductivity); 03142 } 03143 03144 /********************************************************************** 03145 * * 03146 * * 03147 * Utility methods for reading/transforming XML * 03148 * * 03149 * * 03150 **********************************************************************/ 03151 03152 03153 void XmlTransforms::TransformArchiveDirectory(xercesc::DOMDocument* pDocument, 03154 xercesc::DOMElement* pRootElement) 03155 { 03156 using namespace xercesc; 03157 std::vector<xercesc::DOMElement*> elts = XmlTools::FindElements( 03158 pRootElement, 03159 "ResumeSimulation/ArchiveDirectory"); 03160 if (elts.size() > 0) 03161 { 03162 // We have an ArchiveDirectory element, so add the relative_to='chaste_test_output' attribute 03163 DOMElement* p_dir_elt = elts[0]; 03164 p_dir_elt->setAttribute(X("relative_to"), X("chaste_test_output")); 03165 } 03166 } 03167 03168 void XmlTransforms::TransformIonicModelDefinitions(xercesc::DOMDocument* pDocument, 03169 xercesc::DOMElement* pRootElement) 03170 { 03171 // Default ionic model 03172 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements( 03173 pRootElement, 03174 "Simulation/IonicModels/Default"); 03175 if (p_elt_list.size() > 0) 03176 { 03177 assert(p_elt_list.size() == 1); // Asserted by schema 03178 XmlTools::WrapContentInElement(pDocument, p_elt_list[0], X("Hardcoded")); 03179 // Now do any region-specific definitions 03180 p_elt_list = XmlTools::FindElements(pRootElement, "Simulation/IonicModels/Region/IonicModel"); 03181 for (unsigned i=0; i<p_elt_list.size(); i++) 03182 { 03183 XmlTools::WrapContentInElement(pDocument, p_elt_list[i], X("Hardcoded")); 03184 } 03185 } 03186 } 03187 03188 void XmlTransforms::CheckForIluPreconditioner(xercesc::DOMDocument* pDocument, 03189 xercesc::DOMElement* pRootElement) 03190 { 03191 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements( 03192 pRootElement, 03193 "Numerical/KSPPreconditioner"); 03194 if (p_elt_list.size() > 0) 03195 { 03196 assert(p_elt_list.size() == 1); // Asserted by schema 03197 std::string text_value = X2C(p_elt_list[0]->getTextContent()); 03198 if (text_value == "ilu") 03199 { 03200 EXCEPTION("PETSc does not have a parallel implementation of ilu, so we no longer allow it as an option. Use bjacobi instead."); 03201 } 03202 } 03203 } 03204 03205 void XmlTransforms::MoveConductivityHeterogeneities(xercesc::DOMDocument* pDocument, 03206 xercesc::DOMElement* pRootElement) 03207 { 03208 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements( 03209 pRootElement, 03210 "Simulation/ConductivityHeterogeneities"); 03211 if (p_elt_list.size() > 0) 03212 { 03213 assert(p_elt_list.size() == 1); // Asserted by schema 03214 xercesc::DOMNode* p_parent = p_elt_list[0]->getParentNode(); 03215 xercesc::DOMNode* p_child = p_parent->removeChild(p_elt_list[0]); 03216 std::vector<xercesc::DOMElement*> p_phys_list = XmlTools::FindElements(pRootElement, "Physiological"); 03217 assert(p_phys_list.size() == 1); // Asserted by schema 03218 p_phys_list[0]->appendChild(p_child); 03219 } 03220 } 03221 03223 // Explicit instantiation of the templated functions 03225 #define COVERAGE_IGNORE //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously 03226 03230 template void HeartConfig::GetIonicModelRegions<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& , std::vector<cp::ionic_model_selection_type>&) const; 03231 template void HeartConfig::GetStimuli<3u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& ) const; 03232 template void HeartConfig::GetCellHeterogeneities<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& ,std::vector<double>& ,std::vector<double>& ,std::vector<double>& ,std::vector<std::map<std::string, double> >*) ; 03233 template void HeartConfig::GetConductivityHeterogeneities<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& ,std::vector< c_vector<double,3> >& ,std::vector< c_vector<double,3> >& ) const; 03234 03235 template void HeartConfig::GetIonicModelRegions<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& , std::vector<cp::ionic_model_selection_type>&) const; 03236 template void HeartConfig::GetStimuli<2u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& ) const; 03237 template void HeartConfig::GetCellHeterogeneities<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& ,std::vector<double>& ,std::vector<double>& ,std::vector<double>& ,std::vector<std::map<std::string, double> >*) ; 03238 template void HeartConfig::GetConductivityHeterogeneities<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& ,std::vector< c_vector<double,3> >& ,std::vector< c_vector<double,3> >& ) const; 03239 03240 template void HeartConfig::GetIonicModelRegions<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& , std::vector<cp::ionic_model_selection_type>&) const; 03241 template void HeartConfig::GetStimuli<1u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& ) const; 03242 template void HeartConfig::GetCellHeterogeneities<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& ,std::vector<double>& ,std::vector<double>& ,std::vector<double>& ,std::vector<std::map<std::string, double> >*); 03243 template void HeartConfig::GetConductivityHeterogeneities<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& ,std::vector< c_vector<double,3> >& ,std::vector< c_vector<double,3> >& ) const; 03244 03245 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions) const; 03246 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions) const; 03247 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions) const; 03248 03249 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions); 03250 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions); 03251 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions); 03256 #undef COVERAGE_IGNORE //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously 03257 03258 03259 // Serialization for Boost >= 1.36 03260 #include "SerializationExportWrapperForCpp.hpp" 03261 CHASTE_CLASS_EXPORT(HeartConfig)