HeartConfig.cpp

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

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5