HeartConfig.cpp

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

Generated on Mon Nov 1 12:35:17 2010 for Chaste by  doxygen 1.5.5