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

Generated on Tue May 31 14:31:41 2011 for Chaste by  doxygen 1.5.5