HeartConfig.cpp

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

Generated by  doxygen 1.6.2