HeartConfig.cpp

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