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