Chaste  Release::2017.1
HeartConfig.cpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 // Work-around for newer Boost versions
38 
39 #include "UblasCustomFunctions.hpp"
40 
41 #include "HeartConfig.hpp"
42 #include "ArchiveLocationInfo.hpp"
43 #include "OutputFileHandler.hpp"
44 #include "Exception.hpp"
45 #include "ChastePoint.hpp"
46 #include "Version.hpp"
47 #include "AbstractChasteRegion.hpp"
48 #include "HeartFileFinder.hpp"
49 #include "Warnings.hpp"
50 
51 #include "HeartRegionCodes.hpp"
52 
53 #include "SimpleStimulus.hpp"
54 #include "RegularStimulus.hpp"
55 
56 #include <string>
57 #include <istream>
58 #include <fstream>
59 #include <cassert>
60 #include <map>
61 
62 #include "XmlTools.hpp"
63 #include <xsd/cxx/tree/exceptions.hxx>
64 using namespace xsd::cxx::tree;
65 
66 // Coping with changes to XSD interface
67 #if (XSD_INT_VERSION >= 3000000L)
68 #define XSD_SEQUENCE_TYPE(base) base##_sequence
69 #define XSD_ITERATOR_TYPE(base) base##_iterator
70 #define XSD_NESTED_TYPE(t) t##_type
71 #define XSD_ANON_TYPE(t1, t2) \
72  t1::t2##_type
73 #else
74 #define XSD_SEQUENCE_TYPE(base) base::container
75 #define XSD_ITERATOR_TYPE(base) base::iterator
76 #define XSD_NESTED_TYPE(t) t::type
77 #define XSD_ANON_TYPE(t1, t2) \
78  t1::t2::_xsd_##t2##_::t2
79 #endif
80 
81 // These are for convenience
82 #define XSD_ANON_SEQUENCE_TYPE(t1, t2, t3) \
83  XSD_SEQUENCE_TYPE(XSD_ANON_TYPE(t1, t2)::t3)
84 #define XSD_ANON_ITERATOR_TYPE(t1, t2, t3) \
85  XSD_ITERATOR_TYPE(XSD_ANON_TYPE(t1, t2)::t3)
86 
87 // Newer versions don't allow you to set fixed attributes
88 #if (XSD_INT_VERSION >= 3020000L)
89 #define XSD_CREATE_WITH_FIXED_ATTR(type, name, attr) \
90  type name
91 #define XSD_CREATE_WITH_FIXED_ATTR1(type, name, arg1, attr) \
92  type name(arg1)
93 #define XSD_CREATE_WITH_FIXED_ATTR2(type, name, arg1, arg2, attr) \
94  type name(arg1, arg2)
95 #define XSD_CREATE_WITH_FIXED_ATTR3(type, name, arg1, arg2, arg3, attr) \
96  type name(arg1, arg2, arg3)
97 #else
98 #define XSD_CREATE_WITH_FIXED_ATTR(type, name, attr) \
99  type name(attr)
100 #define XSD_CREATE_WITH_FIXED_ATTR1(type, name, arg1, attr) \
101  type name(arg1, attr)
102 #define XSD_CREATE_WITH_FIXED_ATTR2(type, name, arg1, arg2, attr) \
103  type name(arg1, arg2, attr)
104 #define XSD_CREATE_WITH_FIXED_ATTR3(type, name, arg1, arg2, arg3, attr) \
105  type name(arg1, arg2, arg3, attr)
106 #endif
107 
111 #define ENSURE_SECTION_PRESENT(location, type) \
112  if (!location.present()) \
113  { \
114  type empty_item; \
115  location.set(empty_item); \
116  }
117 
118 #include <boost/current_function.hpp>
126 #define CHECK_EXISTS(test, path) \
127  do { \
128  if (!test) { \
129  EXCEPTION("No XML element " << path << " found in parameters when calling '" \
130  << BOOST_CURRENT_FUNCTION << "'"); \
131  }} while (false)
132 
133 
139 {
140 public:
148  static void TransformIonicModelDefinitions(xercesc::DOMDocument* pDocument,
149  xercesc::DOMElement* pRootElement);
150 
159  static void TransformArchiveDirectory(xercesc::DOMDocument* pDocument,
160  xercesc::DOMElement* pRootElement);
161 
169  static void CheckForIluPreconditioner(xercesc::DOMDocument* pDocument,
170  xercesc::DOMElement* pRootElement);
171 
179  static void MoveConductivityHeterogeneities(xercesc::DOMDocument* pDocument,
180  xercesc::DOMElement* pRootElement);
181 
189  static void SetDefaultVisualizer(xercesc::DOMDocument* pDocument,
190  xercesc::DOMElement* pRootElement);
191 };
192 
193 //
194 // Default settings
195 //
196 #include "HeartConfigDefaults.hpp"
197 
198 //
199 // Definition of static member variables
200 //
201 boost::shared_ptr<HeartConfig> HeartConfig::mpInstance;
202 
203 //
204 // Methods
205 //
206 
208 {
209  if (mpInstance.get() == NULL)
210  {
211  mpInstance.reset(new HeartConfig);
212  }
213  return mpInstance.get();
214 }
215 
217  : mUseMassLumping(false),
218  mUseMassLumpingForPrecond(false),
219  mUseFixedNumberIterations(false),
220  mEvaluateNumItsEveryNSolves(UINT_MAX)
221 {
222  assert(mpInstance.get() == NULL);
225 
227  //CheckTimeSteps(); // necessity of this line of code is not tested -- remove with caution!
228 
229  //initialise the member variable of the layers
230  mEpiFraction = -1.0;
231  mEndoFraction = -1.0;
232  mMidFraction = -1.0;
234  // initialise to senseless values (these should be only 0, 1 and 2)
235  // note: the 'minus 3' is for checking purposes as we need to add 0, 1 or 2 to this initial value
236  // and UINT_MAX+1 seems to be 0
237  mIndexMid = UINT_MAX-3u;
238  mIndexEpi = UINT_MAX-3u;
239  mIndexEndo = UINT_MAX-3u;
240 
242 
244  mTissueIdentifiers.insert(0);
245  mBathIdentifiers.insert(1);
246 }
247 
249 {
250 }
251 
252 
253 void HeartConfig::Write(bool useArchiveLocationInfo, std::string subfolderName)
254 {
255  //Output file
256  std::string output_dirname;
257  if (useArchiveLocationInfo)
258  {
259  output_dirname = ArchiveLocationInfo::GetArchiveDirectory();
260  }
261  else
262  {
263  OutputFileHandler handler(GetOutputDirectory() + "/" + subfolderName, false);
264  output_dirname = handler.GetOutputDirectoryFullPath();
265  }
266 
267  // Sometimes this method is called collectively, sometimes not,
268  // in any case the below file operations only want to be performed by
269  // the master - so exit. Caller takes responsibility for nice
270  // exception handling.
271  if (!PetscTools::AmMaster())
272  {
273  return;
274  }
275 
276  out_stream p_parameters_file( new std::ofstream( (output_dirname+"ChasteParameters.xml").c_str() ) );
277 
278  if (!p_parameters_file->is_open())
279  {
280  EXCEPTION("Could not open XML file in HeartConfig");
281  }
282 
283  //Schema map
284  //Note - this location is relative to where we are storing the xml
285  ::xml_schema::namespace_infomap map;
286  // Release 1.1 (and earlier) didn't use a namespace
287  map[""].schema = "ChasteParameters_1_1.xsd";
288  // Later releases use namespaces of the form https://chaste.comlab.ox.ac.uk/nss/parameters/N_M
289  map["cp20"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_0";
290  map["cp20"].schema = "ChasteParameters_2_0.xsd";
291  map["cp21"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_1";
292  map["cp21"].schema = "ChasteParameters_2_1.xsd";
293  map["cp22"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_2";
294  map["cp22"].schema = "ChasteParameters_2_2.xsd";
295  map["cp23"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2_3";
296  map["cp23"].schema = "ChasteParameters_2_3.xsd";
297  map["cp30"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_0";
298  map["cp30"].schema = "ChasteParameters_3_0.xsd";
299  map["cp31"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_1";
300  map["cp31"].schema = "ChasteParameters_3_1.xsd";
301  map["cp33"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_3";
302  map["cp33"].schema = "ChasteParameters_3_3.xsd";
303  map["cp34"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/3_4";
304  map["cp34"].schema = "ChasteParameters_3_4.xsd";
305  // We use 'cp' as prefix for the latest version to avoid having to change saved
306  // versions for comparison at every release.
307  map["cp"].name = "https://chaste.comlab.ox.ac.uk/nss/parameters/2017_1";
308  map["cp"].schema = "ChasteParameters_2017_1.xsd";
309 
310  cp::ChasteParameters(*p_parameters_file, *mpParameters, map);
311 
312  // If we're archiving, try to save a copy of the latest schema too
313  if (useArchiveLocationInfo)
314  {
315  CopySchema(output_dirname);
316  }
317 
318 }
319 
321 {
322  /*
323  * This method implements the logic required by HeartConfig to be able to handle resuming a simulation via the executable.
324  *
325  * When the control reaches the method mpParameters points to the file specified as resuming parameters.
326  * However SetParametersFile() will set this variable to point to the archived parameters.
327  *
328  * We make a temporary copy of mpParameters so we don't lose its content.
329  * At the end of the method we update the new mpParameters with the resuming parameters.
330  */
331  assert(mpParameters.use_count() > 0);
332  boost::shared_ptr<cp::chaste_parameters_type> p_new_parameters = mpParameters;
333 
334  /*
335  * When we unarchive a simulation, we load the old parameters file in order to inherit things such
336  * as default cell model, stimuli, heterogeneities, ... This has the side effect of inheriting the
337  * <CheckpointSimulation> element (if defined).
338  *
339  * We disable checkpointing definition coming from the unarchived config file. We will enable it again
340  * if defined in the resume config file.
341  */
342  std::string parameters_filename_xml = ArchiveLocationInfo::GetArchiveDirectory() + "ChasteParameters.xml";
343  mpParameters = ReadFile(parameters_filename_xml);
344  mParametersFilePath.SetPath(parameters_filename_xml, RelativeTo::AbsoluteOrCwd);
345 
346  // Release 3.0 and earlier wrote a separate defaults file in the checkpoint
347  std::string defaults_filename_xml = ArchiveLocationInfo::GetArchiveDirectory() + "ChasteDefaults.xml";
348  if (FileFinder(defaults_filename_xml).Exists())
349  {
350  boost::shared_ptr<cp::chaste_parameters_type> p_defaults = ReadFile(defaults_filename_xml);
351  MergeDefaults(mpParameters, p_defaults);
352  }
353 
355 
356  // If we are resuming a simulation, some parameters can be altered at this point.
357  if (p_new_parameters->ResumeSimulation().present())
358  {
359  UpdateParametersFromResumeSimulation(p_new_parameters);
360  }
361 
362  CheckTimeSteps(); // For consistency with SetParametersFile
363 }
364 
365 void HeartConfig::CopySchema(const std::string& rToDirectory)
366 {
367  // N.B. This method should only be called by the master process,
368  // in a situation where it can handle EXCEPTION()s nicely, e.g.
369  // TRY_IF_MASTER(CopySchema(...));
370 
371  std::string schema_name("ChasteParameters_2017_1.xsd");
372  FileFinder schema_location("heart/src/io/" + schema_name, RelativeTo::ChasteSourceRoot);
373  if (!schema_location.Exists())
374  {
375  // Try a relative path instead
376  schema_location.SetPath(schema_name, RelativeTo::CWD);
377  if (!schema_location.Exists())
378  {
379  // Warn the user
380  std::string message("Unable to locate schema file " + schema_name +
381  ". You will need to ensure it is available when resuming from the checkpoint.");
382  WARN_ONCE_ONLY(message);
383  }
384  }
385  if (schema_location.Exists())
386  {
387  FileFinder output_directory(rToDirectory, RelativeTo::Absolute);
388  schema_location.CopyTo(output_directory);
389  }
390 }
391 
393 {
394  mSchemaLocations.clear();
395  // Location of schemas in the source tree
396  std::string root_dir = std::string(ChasteBuildInfo::GetRootDir()) + "/heart/src/io/";
397  // Release 1.1 (and earlier) didn't use a namespace
398  mSchemaLocations[""] = root_dir + "ChasteParameters_1_1.xsd";
399  // Later releases use namespaces of the form https://chaste.comlab.ox.ac.uk/nss/parameters/N_M
400  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_0"] = root_dir + "ChasteParameters_2_0.xsd";
401  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_1"] = root_dir + "ChasteParameters_2_1.xsd";
402  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_2"] = root_dir + "ChasteParameters_2_2.xsd";
403  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2_3"] = root_dir + "ChasteParameters_2_3.xsd";
404  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_0"] = root_dir + "ChasteParameters_3_0.xsd";
405  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_1"] = root_dir + "ChasteParameters_3_1.xsd";
406  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_3"] = root_dir + "ChasteParameters_3_3.xsd";
407  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/3_4"] = root_dir + "ChasteParameters_3_4.xsd";
408  mSchemaLocations["https://chaste.comlab.ox.ac.uk/nss/parameters/2017_1"] = root_dir + "ChasteParameters_2017_1.xsd";
409 }
410 
411 unsigned HeartConfig::GetVersionFromNamespace(const std::string& rNamespaceUri)
412 {
413  unsigned version_major = 0;
414  unsigned version_minor = 0;
415  if (rNamespaceUri == "")
416  {
417  version_major = 1;
418  version_minor = 1;
419  }
420  else
421  {
422  std::string uri_base("https://chaste.comlab.ox.ac.uk/nss/parameters/");
423  if (rNamespaceUri.substr(0, uri_base.length()) == uri_base)
424  {
425  std::istringstream version_string(rNamespaceUri.substr(uri_base.length()));
426  version_string >> version_major;
427  version_string.ignore(1);
428  version_string >> version_minor;
429  if (version_string.fail())
430  {
431  version_major = 0;
432  version_minor = 0;
433  }
434  }
435  }
436 
437  unsigned version = version_major * 1000 + version_minor;
438  if (version == 0)
439  {
440  EXCEPTION(rNamespaceUri + " is not a recognised Chaste parameters namespace.");
441  }
442  return version;
443 }
444 
446 {
447  mSchemaLocations = rSchemaLocations;
449 }
450 
451 void HeartConfig::SetUseFixedSchemaLocation(bool useFixedSchemaLocation)
452 {
453  mUseFixedSchemaLocation = useFixedSchemaLocation;
454 }
455 
456 boost::shared_ptr<cp::chaste_parameters_type> HeartConfig::ReadFile(const std::string& rFileName)
457 {
458  // Determine whether to use the schema path given in the input XML, or our own schema
459  ::xml_schema::properties props;
461  {
462  for (SchemaLocationsMap::iterator it = mSchemaLocations.begin();
463  it != mSchemaLocations.end();
464  ++it)
465  {
466  if (it->first == "")
467  {
468  props.no_namespace_schema_location(XmlTools::EscapeSpaces(it->second));
469  }
470  else
471  {
472  props.schema_location(it->first, XmlTools::EscapeSpaces(it->second));
473  }
474  }
475  }
476 
477  // Get the parameters using the method 'ChasteParameters(rFileName)',
478  // which returns a std::auto_ptr. We convert to a shared_ptr for easier semantics.
479  try
480  {
481  // Make sure Xerces finalization happens
482  XmlTools::Finalizer finalizer(false);
483  // Parse XML to DOM
484  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> p_doc = XmlTools::ReadXmlFile(rFileName, props);
485  // Test the namespace on the root element
486  xercesc::DOMElement* p_root_elt = p_doc->getDocumentElement();
487  std::string namespace_uri(X2C(p_root_elt->getNamespaceURI()));
488  const unsigned version = GetVersionFromNamespace(namespace_uri);
489  if (version < 2000) // Changes made in release 2.0
490  {
491  XmlTransforms::TransformIonicModelDefinitions(p_doc.get(), p_root_elt);
492  }
493  if (version < 2001) // Changes made in release 2.1
494  {
495  XmlTransforms::TransformArchiveDirectory(p_doc.get(), p_root_elt);
496  XmlTransforms::CheckForIluPreconditioner(p_doc.get(), p_root_elt);
497  }
498  if (version < 3001) // Changes made in release 3.1
499  {
500  XmlTransforms::MoveConductivityHeterogeneities(p_doc.get(), p_root_elt);
501  }
502  if (version < 3003) // Changes made in release 3.3
503  {
504  XmlTransforms::SetDefaultVisualizer(p_doc.get(), p_root_elt);
505  }
506  if (version < 3004) // Not the latest in release 3.4
507  {
508  XmlTools::SetNamespace(p_doc.get(), p_root_elt, "https://chaste.comlab.ox.ac.uk/nss/parameters/3_4");
509  }
510  if (version < 2017001) // Not the latest release
511  {
512  XmlTools::SetNamespace(p_doc.get(), p_root_elt, "https://chaste.comlab.ox.ac.uk/nss/parameters/2017_1");
513  }
514  // Parse DOM to object model
515  boost::shared_ptr<cp::chaste_parameters_type> p_params(cp::ChasteParameters(*p_doc, ::xml_schema::flags::dont_initialize, props));
516  // Get rid of the DOM stuff
517  p_doc.reset();
518 
519  return boost::shared_ptr<cp::chaste_parameters_type>(p_params);
520  }
521  catch (const xml_schema::exception& e)
522  {
523  std::cerr << e << std::endl;
524  // Make sure we don't store invalid parameters
525  mpParameters.reset();
526  EXCEPTION("XML parsing error in configuration file: " + rFileName);
527  }
528  catch (...)
529  {
530  // Make sure we don't store invalid parameters
531  mpParameters.reset();
532  throw;
533  }
534 }
535 
536 void HeartConfig::SetParametersFile(const std::string& rFileName)
537 {
538  mpParameters = ReadFile(rFileName);
541 
542  if (IsSimulationDefined())
543  {
544  CheckTimeSteps(); // Resume files might not have time steps defined
545  }
546 }
547 
549 {
550  return mParametersFilePath;
551 }
552 
553 void HeartConfig::UpdateParametersFromResumeSimulation(boost::shared_ptr<cp::chaste_parameters_type> pResumeParameters)
554 {
555  // Check for user foolishness
556  if ((pResumeParameters->ResumeSimulation()->SpaceDimension() != HeartConfig::Instance()->GetSpaceDimension())
557  ||(pResumeParameters->ResumeSimulation()->Domain() != HeartConfig::Instance()->GetDomain()))
558  {
559  EXCEPTION("Problem type and space dimension should match when restarting a simulation.");
560  }
561 
562  // New simulation duration
563  HeartConfig::Instance()->SetSimulationDuration(pResumeParameters->ResumeSimulation()->SimulationDuration());
564 
565  // Stimulus definition. For these we always replace any previous definitions (at least for now...)
566  if (pResumeParameters->ResumeSimulation()->Stimuli().present())
567  {
568  mpParameters->Simulation()->Stimuli().set(pResumeParameters->ResumeSimulation()->Stimuli().get());
569  }
570 
571  // Cell heterogeneities. Note that while we copy the elements here, other code in CardiacSimulation actually updates
572  // the loaded simulation to take account of the new settings.
573  if (pResumeParameters->ResumeSimulation()->CellHeterogeneities().present())
574  {
575  if (!mpParameters->Simulation()->CellHeterogeneities().present())
576  {
577  // Original parameters had no heterogeneities, so just copy the whole element
578  mpParameters->Simulation()->CellHeterogeneities().set(pResumeParameters->ResumeSimulation()->CellHeterogeneities().get());
579  }
580  else
581  {
582  // Need to append the new heterogeneity defitions to the original sequence
583  XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity)&
584  new_seq = pResumeParameters->ResumeSimulation()->CellHeterogeneities()->CellHeterogeneity();
585  XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity)&
586  orig_seq = mpParameters->Simulation()->CellHeterogeneities()->CellHeterogeneity();
587  for (XSD_ITERATOR_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) i = new_seq.begin();
588  i != new_seq.end();
589  ++i)
590  {
591  orig_seq.push_back(*i);
592  }
593  }
594  }
595 
596  // Whether to checkpoint the resumed simulation
597  if (pResumeParameters->ResumeSimulation()->CheckpointSimulation().present())
598  {
600  pResumeParameters->ResumeSimulation()->CheckpointSimulation()->timestep(),
601  pResumeParameters->ResumeSimulation()->CheckpointSimulation()->max_checkpoints_on_disk());
602  }
603 
604  //Visualization parameters are no longer compulsory
605  if (pResumeParameters->ResumeSimulation()->OutputVisualizer().present())
606  {
607  HeartConfig::Instance()->SetVisualizeWithParallelVtk(pResumeParameters->ResumeSimulation()->OutputVisualizer()->parallel_vtk() == cp::yesno_type::yes);
608  HeartConfig::Instance()->SetVisualizeWithVtk(pResumeParameters->ResumeSimulation()->OutputVisualizer()->vtk() == cp::yesno_type::yes);
609  HeartConfig::Instance()->SetVisualizeWithCmgui(pResumeParameters->ResumeSimulation()->OutputVisualizer()->cmgui() == cp::yesno_type::yes);
610  HeartConfig::Instance()->SetVisualizeWithMeshalyzer(pResumeParameters->ResumeSimulation()->OutputVisualizer()->meshalyzer() == cp::yesno_type::yes);
611  }
612 
613  // Numerical parameters may be overridden
614  {
615  cp::numerical_type& r_resume = pResumeParameters->Numerical();
616  cp::numerical_type& r_user = mpParameters->Numerical();
617  if (r_resume.TimeSteps().present())
618  {
619  r_user.TimeSteps().set(r_resume.TimeSteps().get());
620  }
621  if (r_resume.KSPTolerances().present())
622  {
623  r_user.KSPTolerances().set(r_resume.KSPTolerances().get());
624  }
625  if (r_resume.KSPSolver().present())
626  {
627  r_user.KSPSolver().set(r_resume.KSPSolver().get());
628  }
629  if (r_resume.KSPPreconditioner().present())
630  {
631  r_user.KSPPreconditioner().set(r_resume.KSPPreconditioner().get());
632  }
633  if (r_resume.AdaptivityParameters().present())
634  {
635  r_user.AdaptivityParameters().set(r_resume.AdaptivityParameters().get());
636  }
637  }
638 
639  // Post-processing parameters may be overridden
640  if (pResumeParameters->PostProcessing().present())
641  {
643  cp::postprocessing_type& r_resume = pResumeParameters->PostProcessing().get();
644  cp::postprocessing_type& r_user = mpParameters->PostProcessing().get();
645  if (!r_resume.ActionPotentialDurationMap().empty())
646  {
647  r_user.ActionPotentialDurationMap() = r_resume.ActionPotentialDurationMap();
648  }
649  if (!r_resume.UpstrokeTimeMap().empty())
650  {
651  r_user.UpstrokeTimeMap() = r_resume.UpstrokeTimeMap();
652  }
653  if (!r_resume.MaxUpstrokeVelocityMap().empty())
654  {
655  r_user.MaxUpstrokeVelocityMap() = r_resume.MaxUpstrokeVelocityMap();
656  }
657  if (!r_resume.ConductionVelocityMap().empty())
658  {
659  r_user.ConductionVelocityMap() = r_resume.ConductionVelocityMap();
660  }
661  }
662 }
663 
664 
666 {
667  // Throw it away first, so that mpInstance is NULL when we...
668  mpInstance.reset();
669  // ...make a new one
670  mpInstance.reset(new HeartConfig);
671 }
672 
674 {
675  return mpParameters->Simulation().present();
676 }
677 
679 {
680  return mpParameters->ResumeSimulation().present();
681 }
682 
683 
684 void HeartConfig::CheckSimulationIsDefined(std::string callingMethod) const
685 {
686  if (IsSimulationResumed())
687  {
688  EXCEPTION(callingMethod + " information is not available in a resumed simulation.");
689  }
690 }
691 
692 void HeartConfig::CheckResumeSimulationIsDefined(std::string callingMethod) const
693 {
694  if (IsSimulationDefined())
695  {
696  EXCEPTION(callingMethod + " information is not available in a standard (non-resumed) simulation.");
697  }
698 }
699 
701 {
702  if (IsSimulationDefined())
703  {
704  CHECK_EXISTS(mpParameters->Simulation()->SpaceDimension().present(), "Simulation/SpaceDimension");
705  return mpParameters->Simulation()->SpaceDimension().get();
706  }
707  else
708  {
709  return mpParameters->ResumeSimulation()->SpaceDimension();
710  }
711 }
712 
714 {
715  if (IsSimulationDefined())
716  {
717  CHECK_EXISTS(mpParameters->Simulation()->SimulationDuration().present(), "Simulation/SimulationDuration");
718  return mpParameters->Simulation()->SimulationDuration().get();
719  }
720  else // IsSimulationResumed
721  {
722  return mpParameters->ResumeSimulation()->SimulationDuration();
723  }
724 }
725 
726 cp::domain_type HeartConfig::GetDomain() const
727 {
728  if (IsSimulationDefined())
729  {
730  CHECK_EXISTS(mpParameters->Simulation()->Domain().present(), "Simulation/Domain");
731  return mpParameters->Simulation()->Domain().get();
732  }
733  else
734  {
735  return mpParameters->ResumeSimulation()->Domain();
736  }
737 }
738 
739 cp::ionic_model_selection_type HeartConfig::GetDefaultIonicModel() const
740 {
741  CheckSimulationIsDefined("DefaultIonicModel");
742 
743  return mpParameters->Simulation()->IonicModels()->Default();
744 }
745 
746 template<unsigned DIM>
747 void HeartConfig::GetIonicModelRegions(std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& definedRegions,
748  std::vector<cp::ionic_model_selection_type>& ionicModels) const
749 {
750  CheckSimulationIsDefined("IonicModelRegions");
751  definedRegions.clear();
752  ionicModels.clear();
753 
754  XSD_SEQUENCE_TYPE(cp::ionic_models_type::Region)&
755  regions = mpParameters->Simulation()->IonicModels()->Region();
756 
757  for (XSD_ITERATOR_TYPE(cp::ionic_models_type::Region) i = regions.begin();
758  i != regions.end();
759  ++i)
760  {
761  cp::ionic_model_region_type ionic_model_region(*i);
762 
763  if (ionic_model_region.Location().Cuboid().present() || ionic_model_region.Location().Ellipsoid().present())
764  {
765  if (ionic_model_region.Location().Cuboid().present())
766  {
767  cp::point_type point_a = ionic_model_region.Location().Cuboid()->LowerCoordinates();
768  cp::point_type point_b = ionic_model_region.Location().Cuboid()->UpperCoordinates();
769 
770  switch (DIM)
771  {
772  case 1:
773  {
774  ChastePoint<DIM> chaste_point_a ( point_a.x() );
775  ChastePoint<DIM> chaste_point_b ( point_b.x() );
776  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b )));
777  break;
778  }
779  case 2:
780  {
781  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y() );
782  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y() );
783  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b )));
784  break;
785  }
786  case 3:
787  {
788  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() );
789  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() );
790  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b )) );
791  break;
792  }
793  default:
795  break;
796  }
797  }
798  else if (ionic_model_region.Location().Ellipsoid().present())
799  {
800  cp::point_type centre = ionic_model_region.Location().Ellipsoid()->Centre();
801  cp::point_type radii = ionic_model_region.Location().Ellipsoid()->Radii();
802  switch (DIM)
803  {
804  case 1:
805  {
806  ChastePoint<DIM> chaste_point_a ( centre.x() );
807  ChastePoint<DIM> chaste_point_b ( radii.x() );
808  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) );
809  break;
810  }
811  case 2:
812  {
813  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y() );
814  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y() );
815  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) );
816  break;
817  }
818  case 3:
819  {
820  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() );
821  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() );
822  definedRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) );
823  break;
824  }
825  default:
826  {
828  break;
829  }
830  }
831  }
832  else
833  {
835  }
836 
837  ionicModels.push_back(ionic_model_region.IonicModel());
838  }
839  else if (ionic_model_region.Location().EpiLayer().present() || ionic_model_region.Location().MidLayer().present() || ionic_model_region.Location().EndoLayer().present() )
840  {
842  EXCEPTION("Definition of transmural layers is not yet supported for defining different ionic models, please use cuboids instead");
843  }
844  else
845  {
846  EXCEPTION("Invalid region type for ionic model definition");
847  }
848  }
849 }
850 
852 {
853  CheckSimulationIsDefined("Mesh");
854  return mpParameters->Simulation()->Mesh().present();
855 }
856 
858 {
859  CheckSimulationIsDefined("Mesh");
860  CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh");
861  cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get();
862  return (mesh.Slab().present() || mesh.Sheet().present() || mesh.Fibre().present());
863 }
864 
866 {
867  CheckSimulationIsDefined("Mesh");
868  CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh");
869  cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get();
870  return (mesh.Slab().present());
871 }
872 
874 {
875  CheckSimulationIsDefined("Mesh");
876  CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh");
877  cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get();
878  return (mesh.Sheet().present());
879 }
880 
882 {
883  CheckSimulationIsDefined("Mesh");
884  CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh");
885  cp::mesh_type mesh = mpParameters->Simulation()->Mesh().get();
886  return (mesh.Fibre().present());
887 }
888 
889 
891 {
892  CheckSimulationIsDefined("Mesh");
893  CHECK_EXISTS(IsMeshProvided(), "Simulation/Mesh");
894  return (mpParameters->Simulation()->Mesh()->LoadMesh().present());
895 }
896 
897 void HeartConfig::GetSlabDimensions(c_vector<double, 3>& slabDimensions) const
898 {
899  CheckSimulationIsDefined("Slab");
900 
901  if (GetSpaceDimension()!=3 || !GetCreateSlab())
902  {
903  EXCEPTION("Tissue slabs can only be defined in 3D");
904  }
905 
906  optional<cp::slab_type, false> slab_dimensions = mpParameters->Simulation()->Mesh()->Slab();
907 
908  slabDimensions[0] = slab_dimensions->x();
909  slabDimensions[1] = slab_dimensions->y();
910  slabDimensions[2] = slab_dimensions->z();
911 }
912 
913 void HeartConfig::GetSheetDimensions(c_vector<double, 2>& sheetDimensions) const
914 {
915  CheckSimulationIsDefined("Sheet");
916 
917  if (GetSpaceDimension()!=2 || !GetCreateSheet())
918  {
919  EXCEPTION("Tissue sheets can only be defined in 2D");
920  }
921 
922  optional<cp::sheet_type, false> sheet_dimensions = mpParameters->Simulation()->Mesh()->Sheet();
923 
924  sheetDimensions[0] = sheet_dimensions->x();
925  sheetDimensions[1] = sheet_dimensions->y();
926 }
927 
928 void HeartConfig::GetFibreLength(c_vector<double, 1>& fibreLength) const
929 {
930  CheckSimulationIsDefined("Fibre");
931 
932  if (GetSpaceDimension()!=1 || !GetCreateFibre())
933  {
934  EXCEPTION("Tissue fibres can only be defined in 1D");
935  }
936 
937  optional<cp::fibre_type, false> fibre_length = mpParameters->Simulation()->Mesh()->Fibre();
938 
939  fibreLength[0] = fibre_length->x();
940 }
941 
943 {
944  CheckSimulationIsDefined("InterNodeSpace");
945 
946  switch (GetSpaceDimension())
947  {
948  case 3:
949  CHECK_EXISTS(GetCreateSlab(), "Simulation/Mesh/Slab");
950  return mpParameters->Simulation()->Mesh()->Slab()->inter_node_space();
951  break;
952  case 2:
953  CHECK_EXISTS(GetCreateSheet(), "Simulation/Mesh/Sheet");
954  return mpParameters->Simulation()->Mesh()->Sheet()->inter_node_space();
955  break;
956  case 1:
957  CHECK_EXISTS(GetCreateFibre(), "Simulation/Mesh/Fibre");
958  return mpParameters->Simulation()->Mesh()->Fibre()->inter_node_space();
959  break;
960  default:
962 // LCOV_EXCL_START
963  return 0.0; //To fool the compiler
964 // LCOV_EXCL_STOP
965  }
966 }
967 
968 std::string HeartConfig::GetMeshName() const
969 {
970  CheckSimulationIsDefined("LoadMesh");
971  CHECK_EXISTS(GetLoadMesh(), "Mesh/LoadMesh");
972 
973  return mpParameters->Simulation()->Mesh()->LoadMesh()->name();
974 }
975 
976 cp::media_type HeartConfig::GetConductivityMedia() const
977 {
978  CheckSimulationIsDefined("LoadMesh");
979  CHECK_EXISTS(GetLoadMesh(), "Mesh/LoadMesh");
980 
981  return mpParameters->Simulation()->Mesh()->LoadMesh()->conductivity_media();
982 }
983 
984 template <unsigned DIM>
985 void HeartConfig::GetStimuli(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& rStimuliApplied,
986  std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rStimulatedAreas) const
987 {
988  CheckSimulationIsDefined("Stimuli");
989 
990  if (!mpParameters->Simulation()->Stimuli().present())
991  {
992  // Finding no stimuli defined is allowed (although HeartConfigRelatedFactory does
993  // throw an exception is no stimuli and no electrodes)
994  return;
995  }
996 
997  XSD_SEQUENCE_TYPE(cp::stimuli_type::Stimulus) stimuli = mpParameters->Simulation()->Stimuli()->Stimulus();
998 
999  for (XSD_ITERATOR_TYPE(cp::stimuli_type::Stimulus) i = stimuli.begin();
1000  i != stimuli.end();
1001  ++i)
1002  {
1003  cp::stimulus_type stimulus(*i);
1004  if (stimulus.Location().Cuboid().present() || stimulus.Location().Ellipsoid().present())
1005  {
1006  boost::shared_ptr<AbstractChasteRegion<DIM> > area_ptr;
1007  if (stimulus.Location().Cuboid().present() )
1008  {
1009  cp::point_type point_a = stimulus.Location().Cuboid()->LowerCoordinates();
1010  cp::point_type point_b = stimulus.Location().Cuboid()->UpperCoordinates();
1011  switch (DIM)
1012  {
1013  case 1:
1014  {
1015  ChastePoint<DIM> chaste_point_a ( point_a.x() );
1016  ChastePoint<DIM> chaste_point_b ( point_b.x() );
1017  area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) );
1018  break;
1019  }
1020  case 2:
1021  {
1022  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y() );
1023  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y() );
1024  area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) );
1025  break;
1026  }
1027  case 3:
1028  {
1029  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() );
1030  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() );
1031  area_ptr.reset(new ChasteCuboid<DIM>( chaste_point_a, chaste_point_b ) );
1032  break;
1033  }
1034  default:
1035  NEVER_REACHED;
1036  break;
1037  }
1038  }
1039  else if (stimulus.Location().Ellipsoid().present())
1040  {
1041  cp::point_type centre = stimulus.Location().Ellipsoid()->Centre();
1042  cp::point_type radii = stimulus.Location().Ellipsoid()->Radii();
1043  switch (DIM)
1044  {
1045  case 1:
1046  {
1047  ChastePoint<DIM> chaste_point_a ( centre.x() );
1048  ChastePoint<DIM> chaste_point_b ( radii.x() );
1049  area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) );
1050  break;
1051  }
1052  case 2:
1053  {
1054  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y() );
1055  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y() );
1056  area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) );
1057  break;
1058  }
1059  case 3:
1060  {
1061  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() );
1062  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() );
1063  area_ptr.reset( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b ) );
1064  break;
1065  }
1066  default:
1067  {
1068  NEVER_REACHED;
1069  break;
1070  }
1071  }
1072  }
1073  rStimulatedAreas.push_back(area_ptr);
1074 
1075  boost::shared_ptr<AbstractStimulusFunction> stim;
1076 
1077  if (stimulus.Period().present())
1078  {
1079  if (stimulus.StopTime().present())
1080  {
1081  stim.reset(new RegularStimulus(stimulus.Strength(),
1082  stimulus.Duration(),
1083  stimulus.Period().get(),
1084  stimulus.Delay(),
1085  stimulus.StopTime().get()));
1086  }
1087  else
1088  {
1089  stim.reset(new RegularStimulus(stimulus.Strength(),
1090  stimulus.Duration(),
1091  stimulus.Period().get(),
1092  stimulus.Delay()));
1093  }
1094 
1095  }
1096  else
1097  {
1098  if (stimulus.StopTime().present())
1099  {
1100  EXCEPTION("Stop time can not be defined for SimpleStimulus. Use Duration instead.");
1101  }
1102 
1103  stim.reset(new SimpleStimulus(stimulus.Strength(),
1104  stimulus.Duration(),
1105  stimulus.Delay()));
1106  }
1107  rStimuliApplied.push_back( stim );
1108  }
1109  else if (stimulus.Location().EpiLayer().present() || stimulus.Location().MidLayer().present() || stimulus.Location().EndoLayer().present() )
1110  {
1111  EXCEPTION("Definition of transmural layers is not yet supported for specifying stimulated areas, please use cuboids instead");
1112  }
1113  else
1114  {
1115  EXCEPTION("Invalid region type for stimulus definition");
1116  }
1117  }
1118 }
1119 
1120 template<unsigned DIM>
1121 void HeartConfig::GetCellHeterogeneities(std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rCellHeterogeneityRegions,
1122  std::vector<double>& rScaleFactorGks,
1123  std::vector<double>& rScaleFactorIto,
1124  std::vector<double>& rScaleFactorGkr,
1125  std::vector<std::map<std::string, double> >* pParameterSettings)
1126 {
1127  CheckSimulationIsDefined("CellHeterogeneities");
1128 
1129  if (!mpParameters->Simulation()->CellHeterogeneities().present())
1130  {
1131  // finding no heterogeneities defined is allowed
1132  return;
1133  }
1134  XSD_SEQUENCE_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) cell_heterogeneity
1135  = mpParameters->Simulation()->CellHeterogeneities()->CellHeterogeneity();
1136 
1137  bool user_supplied_negative_value = false;
1138  mUserAskedForCellularTransmuralHeterogeneities = false; // overwritten with true below if necessary
1139  bool user_asked_for_cuboids_or_ellipsoids = false;
1140  unsigned counter_of_heterogeneities = 0;
1141 
1142  for (XSD_ITERATOR_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) i = cell_heterogeneity.begin();
1143  i != cell_heterogeneity.end();
1144  ++i)
1145  {
1146  cp::cell_heterogeneity_type ht(*i);
1147 
1148  if (ht.Location().Cuboid().present())
1149  {
1150  user_asked_for_cuboids_or_ellipsoids = true;
1151  cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates();
1152  cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates();
1153 
1154  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() );
1155  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() );
1156 
1157  rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM> ( chaste_point_a, chaste_point_b )) );
1158  }
1159  else if (ht.Location().Ellipsoid().present())
1160  {
1161  user_asked_for_cuboids_or_ellipsoids = true;
1162  cp::point_type centre = ht.Location().Ellipsoid()->Centre();
1163  cp::point_type radii = ht.Location().Ellipsoid()->Radii();
1164 
1165  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() );
1166  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() );
1167  rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) );
1168  }
1169  else if (ht.Location().EpiLayer().present())
1170  {
1171  mEpiFraction = ht.Location().EpiLayer().get();
1172 
1174  if (mEpiFraction <0)
1175  {
1176  user_supplied_negative_value=true;
1177  }
1178  mIndexEpi = counter_of_heterogeneities;
1179  }
1180  else if (ht.Location().EndoLayer().present())
1181  {
1182  mEndoFraction = ht.Location().EndoLayer().get();
1183 
1185  if (mEndoFraction <0)
1186  {
1187  user_supplied_negative_value=true;
1188  }
1189  mIndexEndo = counter_of_heterogeneities;
1190  }
1191  else if (ht.Location().MidLayer().present())
1192  {
1193  mMidFraction = ht.Location().MidLayer().get();
1194 
1196  if (mMidFraction <0)
1197  {
1198  user_supplied_negative_value=true;
1199  }
1200  mIndexMid = counter_of_heterogeneities;
1201  }
1202  else
1203  {
1204  EXCEPTION("Invalid region type for cell heterogeneity definition");
1205  }
1206 
1207  // Old scale factors
1208  rScaleFactorGks.push_back(ht.ScaleFactorGks().present() ? (double)ht.ScaleFactorGks().get() : 1.0);
1209  rScaleFactorIto.push_back(ht.ScaleFactorIto().present() ? (double)ht.ScaleFactorIto().get() : 1.0);
1210  rScaleFactorGkr.push_back(ht.ScaleFactorGkr().present() ? (double)ht.ScaleFactorGkr().get() : 1.0);
1211 
1212  // Named parameters
1213  if (pParameterSettings)
1214  {
1215  std::map<std::string, double> param_settings;
1216  XSD_SEQUENCE_TYPE(cp::cell_heterogeneity_type::SetParameter)& params = ht.SetParameter();
1217  for (XSD_ITERATOR_TYPE(cp::cell_heterogeneity_type::SetParameter) param_it = params.begin();
1218  param_it != params.end();
1219  ++param_it)
1220  {
1221  cp::set_parameter_type param(*param_it);
1222  param_settings[param.name()] = param.value();
1223  }
1224  pParameterSettings->push_back(param_settings);
1225  }
1226 
1227  counter_of_heterogeneities++;
1228  }
1229 
1231  {
1232  // cuboids/ellipsoids and layers at the same time are not yet supported
1233  if (user_asked_for_cuboids_or_ellipsoids )
1234  {
1235  EXCEPTION ("Specification of cellular heterogeneities by cuboids/ellipsoids and layers at the same time is not yet supported");
1236  }
1237 
1238  //check that the user supplied all three layers, the indexes should be 0, 1 and 2.
1239  // As they are initialised to a higher value, if their summation is higher than 3,
1240  // one (or more) is missing
1241  if ((mIndexMid+mIndexEndo+mIndexEpi) > 3)
1242  {
1243  EXCEPTION ("Three specifications of layers must be supplied");
1244  }
1245  if (fabs((mEndoFraction+mMidFraction+mEpiFraction)-1)>1e-2)
1246  {
1247  EXCEPTION ("Summation of epicardial, midmyocardial and endocardial fractions should be 1");
1248  }
1249  if (user_supplied_negative_value)
1250  {
1251  EXCEPTION ("Fractions must be positive");
1252  }
1253  }
1254 }
1255 
1257 {
1259 }
1260 
1262 {
1263  return mEpiFraction;
1264 }
1265 
1267 {
1268  return mEndoFraction;
1269 }
1270 
1272 {
1273  return mMidFraction;
1274 }
1275 
1277 {
1278  return mIndexEpi;
1279 }
1280 
1282 {
1283  return mIndexEndo;
1284 }
1285 
1287 {
1288  return mIndexMid;
1289 }
1290 
1292 {
1293  CheckSimulationIsDefined("ConductivityHeterogeneities");
1294  return mpParameters->Physiological().ConductivityHeterogeneities().present();
1295 }
1296 
1297 template<unsigned DIM>
1299  std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rConductivitiesHeterogeneityAreas,
1300  std::vector< c_vector<double,3> >& rIntraConductivities,
1301  std::vector< c_vector<double,3> >& rExtraConductivities) const
1302 {
1303  CheckSimulationIsDefined("ConductivityHeterogeneities");
1304  CHECK_EXISTS(GetConductivityHeterogeneitiesProvided(), "Physiological/ConductivityHeterogeneities");
1305  XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity)&
1306  conductivity_heterogeneity = mpParameters->Physiological().ConductivityHeterogeneities()->ConductivityHeterogeneity();
1307 
1308  for (XSD_ANON_ITERATOR_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) i = conductivity_heterogeneity.begin();
1309  i != conductivity_heterogeneity.end();
1310  ++i)
1311  {
1312  cp::conductivity_heterogeneity_type ht(*i);
1313 
1314  if (ht.Location().Cuboid().present())
1315  {
1316  cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates();
1317  cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates();
1318  ChastePoint<DIM> chaste_point_a ( point_a.x(), point_a.y(), point_a.z() );
1319  ChastePoint<DIM> chaste_point_b ( point_b.x(), point_b.y(), point_b.z() );
1320  rConductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> > ( new ChasteCuboid<DIM> ( chaste_point_a, chaste_point_b )) );
1321  }
1322  else if (ht.Location().Ellipsoid().present())
1323  {
1324  cp::point_type centre = ht.Location().Ellipsoid()->Centre();
1325  cp::point_type radii = ht.Location().Ellipsoid()->Radii();
1326  ChastePoint<DIM> chaste_point_a ( centre.x(), centre.y(), centre.z() );
1327  ChastePoint<DIM> chaste_point_b ( radii.x(), radii.y(), radii.z() );
1328  rConductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> > ( new ChasteEllipsoid<DIM> ( chaste_point_a, chaste_point_b )) );
1329  }
1330  else if (ht.Location().EpiLayer().present() || ht.Location().MidLayer().present() || ht.Location().EndoLayer().present() )
1331  {
1333  EXCEPTION("Definition of transmural layers is not allowed for conductivities heterogeneities, you may use fibre orientation support instead");
1334  }
1335  else
1336  {
1337  EXCEPTION("Invalid region type for conductivity definition");
1338  }
1339 
1340  if (ht.IntracellularConductivities().present())
1341  {
1342  double intra_x = ht.IntracellularConductivities()->longi();
1343  double intra_y = ht.IntracellularConductivities()->trans();
1344  double intra_z = ht.IntracellularConductivities()->normal();
1345 
1346  rIntraConductivities.push_back( Create_c_vector(intra_x, intra_y, intra_z) );
1347  }
1348  else
1349  {
1350  c_vector<double, 3> intra_conductivities;
1351  GetIntracellularConductivities(intra_conductivities);
1352  rIntraConductivities.push_back(intra_conductivities);
1353  }
1354 
1355  if (ht.ExtracellularConductivities().present())
1356  {
1357  double extra_x = ht.ExtracellularConductivities()->longi();
1358  double extra_y = ht.ExtracellularConductivities()->trans();
1359  double extra_z = ht.ExtracellularConductivities()->normal();
1360 
1361  rExtraConductivities.push_back( Create_c_vector(extra_x, extra_y, extra_z) );
1362  }
1363  else
1364  {
1365  c_vector<double, 3> extra_conductivities;
1366  GetExtracellularConductivities(extra_conductivities);
1367  rExtraConductivities.push_back(extra_conductivities);
1368  }
1369  }
1370 }
1371 
1373 {
1374  CheckSimulationIsDefined("Simulation/OutputDirectory");
1375  CHECK_EXISTS(mpParameters->Simulation()->OutputDirectory().present(), "Simulation/OutputDirectory");
1376  return mpParameters->Simulation()->OutputDirectory().get();
1377 }
1378 
1380 {
1381  CheckSimulationIsDefined("Simulation/OutputFilenamePrefix");
1382  CHECK_EXISTS(mpParameters->Simulation()->OutputFilenamePrefix().present(), "Simulation/OutputFilenamePrefix");
1383  return mpParameters->Simulation()->OutputFilenamePrefix().get();
1384 }
1385 
1387 {
1388  CheckSimulationIsDefined("OutputVariables");
1389  return mpParameters->Simulation()->OutputVariables().present();
1390 }
1391 
1392 void HeartConfig::GetOutputVariables(std::vector<std::string>& rOutputVariables) const
1393 {
1394  CHECK_EXISTS(GetOutputVariablesProvided(), "Simulation/OutputVariables");
1395  XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)&
1396  output_variables = mpParameters->Simulation()->OutputVariables()->Var();
1397  rOutputVariables.clear();
1398 
1399  for (XSD_ITERATOR_TYPE(cp::output_variables_type::Var) i = output_variables.begin();
1400  i != output_variables.end();
1401  ++i)
1402  {
1403  cp::var_type& r_var(*i);
1404 
1405  // Add to outputVariables the string returned by var.name()
1406  rOutputVariables.push_back(r_var.name());
1407  }
1408 }
1409 
1411 {
1412  CheckSimulationIsDefined("OutputUsingOriginalNodeOrdering");
1413  bool result = false;
1414  if (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().present())
1415  {
1416  result = (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().get() == cp::yesno_type::yes);
1417  }
1418  return result;
1419 }
1420 
1422 {
1423  return IsSimulationDefined() && mpParameters->Simulation()->CheckpointSimulation().present();
1424 }
1425 
1427 {
1428  CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation");
1429  return mpParameters->Simulation()->CheckpointSimulation()->timestep();
1430 }
1431 
1433 {
1434  CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation");
1435  return mpParameters->Simulation()->CheckpointSimulation()->max_checkpoints_on_disk();
1436 }
1437 
1438 
1440 {
1441  CheckResumeSimulationIsDefined("GetArchivedSimulationDir");
1442 
1443  return HeartFileFinder(mpParameters->ResumeSimulation()->ArchiveDirectory());
1444 }
1445 
1446 
1447 void HeartConfig::GetIntracellularConductivities(c_vector<double, 3>& rIntraConductivities) const
1448 {
1449  CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1450  cp::conductivities_type intra_conductivities
1451  = mpParameters->Physiological().IntracellularConductivities().get();
1452  double intra_x_cond = intra_conductivities.longi();
1453  double intra_y_cond = intra_conductivities.trans();
1454  double intra_z_cond = intra_conductivities.normal();;
1455 
1456  assert(intra_y_cond != DBL_MAX);
1457  assert(intra_z_cond != DBL_MAX);
1458 
1459  rIntraConductivities[0] = intra_x_cond;
1460  rIntraConductivities[1] = intra_y_cond;
1461  rIntraConductivities[2] = intra_z_cond;
1462 }
1463 
1464 void HeartConfig::GetIntracellularConductivities(c_vector<double, 2>& rIntraConductivities) const
1465 {
1466  CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1467  cp::conductivities_type intra_conductivities
1468  = mpParameters->Physiological().IntracellularConductivities().get();
1469  double intra_x_cond = intra_conductivities.longi();
1470  double intra_y_cond = intra_conductivities.trans();
1471 
1472  assert(intra_y_cond != DBL_MAX);
1473 
1474  rIntraConductivities[0] = intra_x_cond;
1475  rIntraConductivities[1] = intra_y_cond;
1476 }
1477 
1478 void HeartConfig::GetIntracellularConductivities(c_vector<double, 1>& rIntraConductivities) const
1479 {
1480  CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1481  cp::conductivities_type intra_conductivities
1482  = mpParameters->Physiological().IntracellularConductivities().get();
1483  double intra_x_cond = intra_conductivities.longi();
1484 
1485  rIntraConductivities[0] = intra_x_cond;
1486 }
1487 
1488 void HeartConfig::GetExtracellularConductivities(c_vector<double, 3>& rExtraConductivities) const
1489 {
1490  CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1491  cp::conductivities_type extra_conductivities
1492  = mpParameters->Physiological().ExtracellularConductivities().get();
1493  double extra_x_cond = extra_conductivities.longi();
1494  double extra_y_cond = extra_conductivities.trans();
1495  double extra_z_cond = extra_conductivities.normal();;
1496 
1497  assert(extra_y_cond != DBL_MAX);
1498  assert(extra_z_cond != DBL_MAX);
1499 
1500  rExtraConductivities[0] = extra_x_cond;
1501  rExtraConductivities[1] = extra_y_cond;
1502  rExtraConductivities[2] = extra_z_cond;
1503 }
1504 
1505 void HeartConfig::GetExtracellularConductivities(c_vector<double, 2>& rExtraConductivities) const
1506 {
1507  CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1508  cp::conductivities_type extra_conductivities
1509  = mpParameters->Physiological().ExtracellularConductivities().get();
1510  double extra_x_cond = extra_conductivities.longi();
1511  double extra_y_cond = extra_conductivities.trans();
1512 
1513  assert(extra_y_cond != DBL_MAX);
1514 
1515  rExtraConductivities[0] = extra_x_cond;
1516  rExtraConductivities[1] = extra_y_cond;
1517 }
1518 
1519 void HeartConfig::GetExtracellularConductivities(c_vector<double, 1>& rExtraConductivities) const
1520 {
1521  CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1522  cp::conductivities_type extra_conductivities
1523  = mpParameters->Physiological().ExtracellularConductivities().get();
1524  double extra_x_cond = extra_conductivities.longi();
1525 
1526  rExtraConductivities[0] = extra_x_cond;
1527 }
1528 
1529 double HeartConfig::GetBathConductivity(unsigned bathRegion) const
1530 {
1531  /*
1532  * We have to consider three cases: The user asks for ...
1533  * a) ... the default conductivity (bathRegion=UINT_MAX)
1534  * b) ... the conductivity of region defined to be heterogeneous
1535  * c) ... the conductivity of region NOT defined to be heterogeneous
1536  *
1537  * a) and c) should return the same
1538  */
1539 
1540  if (bathRegion == UINT_MAX)
1541  {
1542  /*bath conductivity mS/cm*/
1543  CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity");
1544  return mpParameters->Physiological().BathConductivity().get();
1545  }
1546  else
1547  {
1548  assert(HeartRegionCode::IsRegionBath(bathRegion));
1549 
1550  std::map<unsigned, double>::const_iterator map_entry = mBathConductivities.find(bathRegion);
1551 
1552  if (map_entry != mBathConductivities.end())
1553  {
1554  return map_entry->second;
1555  }
1556  else
1557  {
1558  /*bath conductivity mS/cm*/
1559  CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity");
1560  return mpParameters->Physiological().BathConductivity().get();
1561  }
1562  }
1563 }
1564 const std::set<unsigned>& HeartConfig::rGetTissueIdentifiers()
1565 {
1566  return mTissueIdentifiers;
1567 }
1568 
1569 const std::set<unsigned>& HeartConfig::rGetBathIdentifiers()
1570 {
1571  return mBathIdentifiers;
1572 }
1573 
1575 {
1576  CHECK_EXISTS(mpParameters->Physiological().SurfaceAreaToVolumeRatio().present(), "Physiological/SurfaceAreaToVolumeRatio");
1577  return mpParameters->Physiological().SurfaceAreaToVolumeRatio().get();
1578 }
1579 
1581 {
1582  CHECK_EXISTS(mpParameters->Physiological().Capacitance().present(), "Physiological/Capacitance");
1583  return mpParameters->Physiological().Capacitance().get();
1584 }
1585 
1587 {
1588  CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1589  return mpParameters->Numerical().TimeSteps()->ode();
1590 }
1591 
1593 {
1594  CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1595  return mpParameters->Numerical().TimeSteps()->pde();
1596 }
1597 
1599 {
1600  CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1601  return mpParameters->Numerical().TimeSteps()->printing();
1602 }
1603 
1605 {
1606  CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1607  return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().present();
1608 }
1609 
1611 {
1612  CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1613  if (!GetUseAbsoluteTolerance())
1614  {
1615  EXCEPTION("Absolute tolerance is not set in Chaste parameters");
1616  }
1617  return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().get();
1618 }
1619 
1621 {
1622  CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1623  return mpParameters->Numerical().KSPTolerances()->KSPRelative().present();
1624 }
1625 
1627 {
1628  CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1629  if (!GetUseRelativeTolerance())
1630  {
1631  EXCEPTION("Relative tolerance is not set in Chaste parameters");
1632  }
1633  return mpParameters->Numerical().KSPTolerances()->KSPRelative().get();
1634 }
1635 
1636 const char* HeartConfig::GetKSPSolver() const
1637 {
1638  CHECK_EXISTS(mpParameters->Numerical().KSPSolver().present(), "Numerical/KSPSolver");
1639  switch (mpParameters->Numerical().KSPSolver().get())
1640  {
1641  case cp::ksp_solver_type::gmres :
1642  return "gmres";
1643  case cp::ksp_solver_type::cg :
1644  return "cg";
1645  case cp::ksp_solver_type::symmlq :
1646  return "symmlq";
1647  case cp::ksp_solver_type::chebychev :
1648  return "chebychev";
1649  }
1650 // LCOV_EXCL_START
1651  EXCEPTION("Unknown ksp solver");
1652 // LCOV_EXCL_STOP
1653 }
1654 
1656 {
1657  CHECK_EXISTS(mpParameters->Numerical().KSPPreconditioner().present(), "Numerical/KSPPreconditioner");
1658  switch ( mpParameters->Numerical().KSPPreconditioner().get() )
1659  {
1660  case cp::ksp_preconditioner_type::jacobi :
1661  return "jacobi";
1662  case cp::ksp_preconditioner_type::bjacobi :
1663  return "bjacobi";
1664  case cp::ksp_preconditioner_type::hypre :
1665  return "hypre";
1666  case cp::ksp_preconditioner_type::ml :
1667  return "ml";
1668  case cp::ksp_preconditioner_type::spai :
1669  return "spai";
1670  case cp::ksp_preconditioner_type::blockdiagonal :
1671  return "blockdiagonal";
1672  case cp::ksp_preconditioner_type::ldufactorisation :
1673  return "ldufactorisation";
1674  case cp::ksp_preconditioner_type::twolevelsblockdiagonal :
1675  return "twolevelsblockdiagonal";
1676  case cp::ksp_preconditioner_type::none :
1677  return "none";
1678 
1679  }
1680 // LCOV_EXCL_START
1681  EXCEPTION("Unknown ksp preconditioner");
1682 // LCOV_EXCL_STOP
1683 }
1684 
1686 {
1687  CHECK_EXISTS(mpParameters->Numerical().MeshPartitioning().present(), "Numerical/MeshPartitioning");
1688  switch ( mpParameters->Numerical().MeshPartitioning().get() )
1689  {
1690  case cp::mesh_partitioning_type::dumb :
1691  return DistributedTetrahedralMeshPartitionType::DUMB;
1692  case cp::mesh_partitioning_type::metis :
1693  return DistributedTetrahedralMeshPartitionType::METIS_LIBRARY;
1694  case cp::mesh_partitioning_type::parmetis :
1695  return DistributedTetrahedralMeshPartitionType::PARMETIS_LIBRARY;
1696  case cp::mesh_partitioning_type::petsc :
1697  return DistributedTetrahedralMeshPartitionType::PETSC_MAT_PARTITION;
1698  }
1699 // LCOV_EXCL_START
1700  EXCEPTION("Unknown mesh partitioning type");
1701 // LCOV_EXCL_STOP
1702 }
1703 
1705 {
1706  bool IsAdaptivityParametersPresent = mpParameters->Numerical().AdaptivityParameters().present();
1707  if (IsAdaptivityParametersPresent)
1708  {
1709  WARNING("Use of the Adaptivity library is deprecated");
1710  }
1712 }
1713 
1714 /*
1715  * PostProcessing
1716  */
1717 
1719 {
1720  return mpParameters->PostProcessing().present();
1721 }
1722 
1724 {
1725  ENSURE_SECTION_PRESENT(mpParameters->PostProcessing(), cp::postprocessing_type);
1726 }
1727 
1729 {
1730  if (IsPostProcessingSectionPresent() == false)
1731  {
1732  return false;
1733  }
1734  else
1735  {
1736  return(IsApdMapsRequested() ||
1742  }
1743 }
1745 {
1746  bool result = false;
1748  {
1749  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)&
1750  apd_maps = mpParameters->PostProcessing()->ActionPotentialDurationMap();
1751  result = (apd_maps.begin() != apd_maps.end());
1752  }
1753  return result;
1754 }
1755 
1756 void HeartConfig::GetApdMaps(std::vector<std::pair<double,double> >& apd_maps) const
1757 {
1758  CHECK_EXISTS(IsApdMapsRequested(), "PostProcessing/ActionPotentialDurationMap");
1759  apd_maps.clear();
1760 
1761  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)&
1762  apd_maps_sequence = mpParameters->PostProcessing()->ActionPotentialDurationMap();
1763 
1764  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ActionPotentialDurationMap) i = apd_maps_sequence.begin();
1765  i != apd_maps_sequence.end();
1766  ++i)
1767  {
1768  std::pair<double,double> map(i->repolarisation_percentage(),i->threshold());
1769 
1770  apd_maps.push_back(map);
1771  }
1772 }
1773 
1775 {
1776  bool result = false;
1778  {
1779  XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)&
1780  upstroke_map = mpParameters->PostProcessing()->UpstrokeTimeMap();
1781  result = (upstroke_map.begin() != upstroke_map.end());
1782  }
1783  return result;
1784 }
1785 void HeartConfig::GetUpstrokeTimeMaps (std::vector<double>& upstroke_time_maps) const
1786 {
1787  CHECK_EXISTS(IsUpstrokeTimeMapsRequested(), "PostProcessing/UpstrokeTimeMap");
1788  assert(upstroke_time_maps.size() == 0);
1789 
1790  XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)&
1791  upstroke_maps_sequence = mpParameters->PostProcessing()->UpstrokeTimeMap();
1792 
1793  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::UpstrokeTimeMap) i = upstroke_maps_sequence.begin();
1794  i != upstroke_maps_sequence.end();
1795  ++i)
1796  {
1797  upstroke_time_maps.push_back(i->threshold());
1798  }
1799 }
1800 
1802 {
1803  bool result = false;
1805  {
1806  XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)&
1807  max_upstroke_velocity_map = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
1808  result = (max_upstroke_velocity_map.begin() != max_upstroke_velocity_map.end());
1809  }
1810  return result;
1811 }
1812 
1813 void HeartConfig::GetMaxUpstrokeVelocityMaps(std::vector<double>& upstroke_velocity_maps) const
1814 {
1815  CHECK_EXISTS(IsMaxUpstrokeVelocityMapRequested(), "PostProcessing/MaxUpstrokeVelocityMap");
1816  assert(upstroke_velocity_maps.size() == 0);
1817 
1818  XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)&
1819  max_upstroke_velocity_maps_sequence = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
1820 
1821  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap) i = max_upstroke_velocity_maps_sequence.begin();
1822  i != max_upstroke_velocity_maps_sequence.end();
1823  ++i)
1824  {
1825  upstroke_velocity_maps.push_back(i->threshold());
1826  }
1827 }
1828 
1830 {
1831  bool result = false;
1833  {
1834  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)&
1835  cond_vel_maps = mpParameters->PostProcessing()->ConductionVelocityMap();
1836  result = (cond_vel_maps.begin() != cond_vel_maps.end());
1837  }
1838  return result;
1839 }
1840 
1841 void HeartConfig::GetConductionVelocityMaps(std::vector<unsigned>& conduction_velocity_maps) const
1842 {
1843  CHECK_EXISTS(IsConductionVelocityMapsRequested(), "PostProcessing/ConductionVelocityMap");
1844  assert(conduction_velocity_maps.size() == 0);
1845 
1846  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)&
1847  cond_vel_maps_sequence = mpParameters->PostProcessing()->ConductionVelocityMap();
1848 
1849  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ConductionVelocityMap) i = cond_vel_maps_sequence.begin();
1850  i != cond_vel_maps_sequence.end();
1851  ++i)
1852  {
1853  conduction_velocity_maps.push_back(i->origin_node());
1854  }
1855 }
1856 
1858 {
1859  bool result = false;
1861  {
1862  XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)&
1863  requested_nodes = mpParameters->PostProcessing()->TimeTraceAtNode();
1864  result = (requested_nodes.begin() != requested_nodes.end());
1865  }
1866  return result;
1867 }
1868 
1869 void HeartConfig::GetNodalTimeTraceRequested(std::vector<unsigned>& rRequestedNodes) const
1870 {
1871  CHECK_EXISTS(IsAnyNodalTimeTraceRequested(), "PostProcessing/TimeTraceAtNode");
1872  assert(rRequestedNodes.size() == 0);
1873 
1874  XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)&
1875  req_nodes = mpParameters->PostProcessing()->TimeTraceAtNode();
1876 
1877  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::TimeTraceAtNode) i = req_nodes.begin();
1878  i != req_nodes.end();
1879  ++i)
1880  {
1881  rRequestedNodes.push_back(i->node_number());
1882  }
1883 }
1884 
1885 
1887 {
1888  bool result = false;
1890  {
1891  XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)&
1892  electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
1893  result = (electrodes.begin() != electrodes.end());
1894  }
1895  return result;
1896 }
1897 
1898 template<unsigned SPACE_DIM>
1899 void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions) const
1900 {
1901  rPseudoEcgElectrodePositions.clear();
1902  XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)&
1903  electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
1904  for (XSD_ITERATOR_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition) i = electrodes.begin();
1905  i != electrodes.end();
1906  ++i)
1907  {
1908  rPseudoEcgElectrodePositions.push_back(ChastePoint<SPACE_DIM>(i->x(), i->y(), i->z()));
1909  }
1910 }
1911 
1912 
1913 /*
1914  * Output visualization
1915  */
1916 
1918 {
1919  CheckSimulationIsDefined("OutputVisualizer");
1920 
1921  return mpParameters->Simulation()->OutputVisualizer().present();
1922 }
1923 
1925 {
1927  {
1928  return false;
1929  }
1930  else
1931  {
1932  return mpParameters->Simulation()->OutputVisualizer()->meshalyzer() == cp::yesno_type::yes;
1933  }
1934 }
1935 
1937 {
1939  {
1940  return false;
1941  }
1942  else
1943  {
1944  return mpParameters->Simulation()->OutputVisualizer()->cmgui() == cp::yesno_type::yes;
1945  }
1946 }
1947 
1949 {
1951  {
1952  return false;
1953  }
1954  else
1955  {
1956  return mpParameters->Simulation()->OutputVisualizer()->parallel_vtk() == cp::yesno_type::yes;
1957  }
1958 }
1959 
1961 {
1963  {
1964  return false;
1965  }
1966  else
1967  {
1968  return mpParameters->Simulation()->OutputVisualizer()->vtk() == cp::yesno_type::yes;
1969  }
1970 }
1971 
1973 {
1975  {
1976  return 0u;
1977  }
1978  else
1979  {
1980  return mpParameters->Simulation()->OutputVisualizer()->precision();
1981  }
1982 }
1983 
1984 
1986 {
1987  return mpParameters->Simulation()->Electrodes().present();
1988 }
1989 
1990 /*
1991  * Set methods
1992  */
1993 void HeartConfig::SetSpaceDimension(unsigned spaceDimension)
1994 {
1995  mpParameters->Simulation()->SpaceDimension().set(spaceDimension);
1996 }
1997 
1998 void HeartConfig::SetSimulationDuration(double simulationDuration)
1999 {
2000  XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, time, simulationDuration, "ms");
2001  mpParameters->Simulation()->SimulationDuration().set(time);
2002 }
2003 
2004 void HeartConfig::SetDomain(const cp::domain_type& rDomain)
2005 {
2006  mpParameters->Simulation()->Domain().set(rDomain);
2007 }
2008 
2009 void HeartConfig::SetDefaultIonicModel(const cp::ionic_models_available_type& rIonicModel)
2010 {
2011  cp::ionic_model_selection_type ionic_model;
2012  ionic_model.Hardcoded(rIonicModel);
2013  cp::ionic_models_type container(ionic_model);
2014  mpParameters->Simulation()->IonicModels().set(container);
2015 }
2016 
2017 void HeartConfig::SetSlabDimensions(double x, double y, double z, double inter_node_space)
2018 {
2019  if (!mpParameters->Simulation()->Mesh().present())
2020  {
2021  XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2022  mpParameters->Simulation()->Mesh().set(mesh_to_load);
2023  }
2024 
2025  cp::slab_type slab_definition(x, y, z, inter_node_space);
2026  mpParameters->Simulation()->Mesh()->Slab().set(slab_definition);
2027 }
2028 
2029 void HeartConfig::SetSheetDimensions(double x, double y, double inter_node_space)
2030 {
2031  if (!mpParameters->Simulation()->Mesh().present())
2032  {
2033  XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2034  mpParameters->Simulation()->Mesh().set(mesh_to_load);
2035  }
2036 
2037  cp::sheet_type sheet_definition(x, y, inter_node_space);
2038  mpParameters->Simulation()->Mesh()->Sheet().set(sheet_definition);
2039 }
2040 
2041 void HeartConfig::SetFibreLength(double x, double inter_node_space)
2042 {
2043  if (!mpParameters->Simulation()->Mesh().present())
2044  {
2045  XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2046  mpParameters->Simulation()->Mesh().set(mesh_to_load);
2047  }
2048 
2049  cp::fibre_type fibre_definition(x, inter_node_space);
2050  mpParameters->Simulation()->Mesh()->Fibre().set(fibre_definition);
2051 }
2052 
2053 void HeartConfig::SetMeshFileName(std::string meshPrefix, cp::media_type fibreDefinition)
2054 {
2055  if (!mpParameters->Simulation()->Mesh().present())
2056  {
2057  XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2058  mpParameters->Simulation()->Mesh().set(mesh_to_load);
2059  }
2060 
2061  XSD_NESTED_TYPE(cp::mesh_type::LoadMesh) mesh_prefix(meshPrefix, fibreDefinition);
2062  mpParameters->Simulation()->Mesh()->LoadMesh().set(mesh_prefix);
2063 }
2064 
2065 void HeartConfig::SetIonicModelRegions(std::vector<ChasteCuboid<3> >& rDefinedRegions,
2066  std::vector<cp::ionic_model_selection_type>& rIonicModels) const
2067 {
2068  assert(rDefinedRegions.size() == rIonicModels.size());
2069  // You need to have defined a default model first...
2070  assert(mpParameters->Simulation()->IonicModels().present());
2071  XSD_SEQUENCE_TYPE(cp::ionic_models_type::Region)&
2072  regions = mpParameters->Simulation()->IonicModels()->Region();
2073  regions.clear();
2074  for (unsigned region_index=0; region_index<rDefinedRegions.size(); region_index++)
2075  {
2076  cp::point_type point_a(rDefinedRegions[region_index].rGetLowerCorner()[0],
2077  rDefinedRegions[region_index].rGetLowerCorner()[1],
2078  rDefinedRegions[region_index].rGetLowerCorner()[2]);
2079 
2080  cp::point_type point_b(rDefinedRegions[region_index].rGetUpperCorner()[0],
2081  rDefinedRegions[region_index].rGetUpperCorner()[1],
2082  rDefinedRegions[region_index].rGetUpperCorner()[2]);
2083 
2084  XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2085  locn.Cuboid().set(cp::box_type(point_a, point_b));
2086 
2087  cp::ionic_model_region_type region(rIonicModels[region_index], locn);
2088  regions.push_back(region);
2089  }
2090 }
2091 
2092 void HeartConfig::SetConductivityHeterogeneities(std::vector<ChasteCuboid<3> >& rConductivityAreas,
2093  std::vector< c_vector<double,3> >& rIntraConductivities,
2094  std::vector< c_vector<double,3> >& rExtraConductivities)
2095 {
2096  assert ( rConductivityAreas.size() == rIntraConductivities.size() );
2097  assert ( rIntraConductivities.size() == rExtraConductivities.size());
2098 
2099  XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) heterogeneities_container;
2100 
2101  for (unsigned region_index=0; region_index<rConductivityAreas.size(); region_index++)
2102  {
2103  cp::point_type point_a(rConductivityAreas[region_index].rGetLowerCorner()[0],
2104  rConductivityAreas[region_index].rGetLowerCorner()[1],
2105  rConductivityAreas[region_index].rGetLowerCorner()[2]);
2106 
2107  cp::point_type point_b(rConductivityAreas[region_index].rGetUpperCorner()[0],
2108  rConductivityAreas[region_index].rGetUpperCorner()[1],
2109  rConductivityAreas[region_index].rGetUpperCorner()[2]);
2110 
2111  XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2112  locn.Cuboid().set(cp::box_type(point_a, point_b));
2113  cp::conductivity_heterogeneity_type ht(locn);
2114 
2115  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2116  rIntraConductivities[region_index][0],
2117  rIntraConductivities[region_index][1],
2118  rIntraConductivities[region_index][2],
2119  "mS/cm");
2120 
2121  ht.IntracellularConductivities(intra);
2122 
2123  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2124  rExtraConductivities[region_index][0],
2125  rExtraConductivities[region_index][1],
2126  rExtraConductivities[region_index][2],
2127  "mS/cm");
2128 
2129  ht.ExtracellularConductivities(extra);
2130 
2131  heterogeneities_container.push_back(ht);
2132  }
2133 
2134  XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities) heterogeneities_object;
2135  heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container);
2136 
2137  mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object);
2138 }
2139 
2141  std::vector< c_vector<double,3> >& rIntraConductivities,
2142  std::vector< c_vector<double,3> >& rExtraConductivities)
2143 {
2144  assert ( rConductivityAreas.size() == rIntraConductivities.size() );
2145  assert ( rIntraConductivities.size() == rExtraConductivities.size());
2146 
2147  XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) heterogeneities_container;
2148 
2149  for (unsigned region_index=0; region_index<rConductivityAreas.size(); region_index++)
2150  {
2151  cp::point_type centre(rConductivityAreas[region_index].rGetCentre()[0],
2152  rConductivityAreas[region_index].rGetCentre()[1],
2153  rConductivityAreas[region_index].rGetCentre()[2]);
2154 
2155  cp::point_type radii(rConductivityAreas[region_index].rGetRadii()[0],
2156  rConductivityAreas[region_index].rGetRadii()[1],
2157  rConductivityAreas[region_index].rGetRadii()[2]);
2158 
2159  XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2160  locn.Ellipsoid().set(cp::ellipsoid_type(centre, radii));
2161  cp::conductivity_heterogeneity_type ht(locn);
2162 
2163  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2164  rIntraConductivities[region_index][0],
2165  rIntraConductivities[region_index][1],
2166  rIntraConductivities[region_index][2],
2167  "mS/cm");
2168 
2169  ht.IntracellularConductivities(intra);
2170 
2171  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2172  rExtraConductivities[region_index][0],
2173  rExtraConductivities[region_index][1],
2174  rExtraConductivities[region_index][2],
2175  "mS/cm");
2176 
2177  ht.ExtracellularConductivities(extra);
2178 
2179  heterogeneities_container.push_back(ht);
2180  }
2181 
2182  XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities) heterogeneities_object;
2183  heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container);
2184 
2185  mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object);
2186 }
2187 
2188 void HeartConfig::SetOutputDirectory(const std::string& rOutputDirectory)
2189 {
2190  mpParameters->Simulation()->OutputDirectory().set(rOutputDirectory);
2191 }
2192 
2193 void HeartConfig::SetOutputFilenamePrefix(const std::string& rOutputFilenamePrefix)
2194 {
2195  mpParameters->Simulation()->OutputFilenamePrefix().set(rOutputFilenamePrefix);
2196 }
2197 
2198 void HeartConfig::SetOutputVariables(const std::vector<std::string>& rOutputVariables)
2199 {
2200  if (!mpParameters->Simulation()->OutputVariables().present())
2201  {
2202  cp::output_variables_type variables_requested;
2203  mpParameters->Simulation()->OutputVariables().set(variables_requested);
2204  }
2205 
2206  XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)&
2207  var_type_sequence = mpParameters->Simulation()->OutputVariables()->Var();
2208  // Erase or create a sequence
2209  var_type_sequence.clear();
2210 
2211  for (unsigned i=0; i<rOutputVariables.size(); i++)
2212  {
2213  cp::var_type temp(rOutputVariables[i]);
2214  var_type_sequence.push_back(temp);
2215  }
2216 }
2217 
2219 {
2220  //What if it doesn't exist?
2221  mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().set(useOriginal? cp::yesno_type::yes : cp::yesno_type::no);
2222 }
2223 
2224 void HeartConfig::SetCheckpointSimulation(bool saveSimulation, double checkpointTimestep, unsigned maxCheckpointsOnDisk)
2225 {
2226  if (saveSimulation)
2227  {
2228  // Make sure values for the optional parameters have been provided
2229  assert(checkpointTimestep!=-1.0 && maxCheckpointsOnDisk!=UINT_MAX);
2230 
2231  XSD_CREATE_WITH_FIXED_ATTR2(cp::simulation_type::XSD_NESTED_TYPE(CheckpointSimulation),
2232  cs,
2233  checkpointTimestep,
2234  maxCheckpointsOnDisk,
2235  "ms");
2236  mpParameters->Simulation()->CheckpointSimulation().set(cs);
2237  }
2238  else
2239  {
2240  mpParameters->Simulation()->CheckpointSimulation().reset();
2241  }
2242 
2243  CheckTimeSteps();
2244 }
2245 
2246 // Physiological
2247 
2248 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 3>& rIntraConductivities)
2249 {
2250  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2251  rIntraConductivities[0],
2252  rIntraConductivities[1],
2253  rIntraConductivities[2],
2254  "mS/cm");
2255 
2256  mpParameters->Physiological().IntracellularConductivities().set(intra);
2257 }
2258 
2259 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 2>& rIntraConductivities)
2260 {
2261  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2262  rIntraConductivities[0],
2263  rIntraConductivities[1],
2264  0.0, "mS/cm");
2265 
2266  mpParameters->Physiological().IntracellularConductivities().set(intra);
2267 }
2268 
2269 void HeartConfig::SetIntracellularConductivities(const c_vector<double, 1>& rIntraConductivities)
2270 {
2271  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2272  rIntraConductivities[0],
2273  0.0, 0.0, "mS/cm");
2274 
2275  mpParameters->Physiological().IntracellularConductivities().set(intra);
2276 }
2277 
2278 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 3>& rExtraConductivities)
2279 {
2280  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2281  rExtraConductivities[0],
2282  rExtraConductivities[1],
2283  rExtraConductivities[2],
2284  "mS/cm");
2285 
2286  mpParameters->Physiological().ExtracellularConductivities().set(extra);
2287 }
2288 
2289 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 2>& rExtraConductivities)
2290 {
2291  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2292  rExtraConductivities[0],
2293  rExtraConductivities[1],
2294  0.0, "mS/cm");
2295 
2296  mpParameters->Physiological().ExtracellularConductivities().set(extra);
2297 }
2298 
2299 void HeartConfig::SetExtracellularConductivities(const c_vector<double, 1>& rExtraConductivities)
2300 {
2301  XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2302  rExtraConductivities[0],
2303  0.0, 0.0, "mS/cm");
2304 
2305  mpParameters->Physiological().ExtracellularConductivities().set(extra);
2306 }
2307 
2308 void HeartConfig::SetBathConductivity(double bathConductivity)
2309 {
2310  XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, cond, bathConductivity, "mS/cm");
2311  mpParameters->Physiological().BathConductivity().set(cond);
2312 }
2313 
2314 void HeartConfig::SetBathMultipleConductivities(std::map<unsigned, double> bathConductivities)
2315 {
2317  mBathConductivities = bathConductivities;
2318 }
2319 
2320 //void HeartConfig::SetTissueIdentifiers(const std::set<unsigned>& tissueIds)
2321 //{
2322 // std::set<unsigned> empty_bath_identifiers; //Too dangerous (see GetValidBathId)
2323 // SetTissueAndBathIdentifiers(tissueIds, mBathIdentifiers);
2324 //}
2325 
2326 void HeartConfig::SetTissueAndBathIdentifiers(const std::set<unsigned>& tissueIds, const std::set<unsigned>& bathIds)
2327 {
2328  if (tissueIds.empty() || bathIds.empty() )
2329  {
2330  EXCEPTION("Identifying set must be non-empty");
2331  }
2332  std::set<unsigned> shared_identifiers;
2333  std::set_intersection(tissueIds.begin(),
2334  tissueIds.end(),
2335  bathIds.begin(),
2336  bathIds.end(),
2337  std::inserter(shared_identifiers, shared_identifiers.begin()));
2338 
2339  if (!shared_identifiers.empty())
2340  {
2341  EXCEPTION("Tissue identifiers and bath identifiers overlap");
2342  }
2343  mTissueIdentifiers=tissueIds;
2344  mBathIdentifiers=bathIds;
2345 }
2346 
2348 {
2349  XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, ratio_object, ratio, "1/cm");
2350  mpParameters->Physiological().SurfaceAreaToVolumeRatio().set(ratio_object);
2351 }
2352 
2353 void HeartConfig::SetCapacitance(double capacitance)
2354 {
2355  XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, capacitance_object, capacitance, "uF/cm^2");
2356  mpParameters->Physiological().Capacitance().set(capacitance_object);
2357 }
2358 
2359 
2360 // Numerical
2361 void HeartConfig::SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep)
2362 {
2363  XSD_CREATE_WITH_FIXED_ATTR3(cp::time_steps_type, time_steps,
2364  odeTimeStep, pdeTimeStep, printingTimeStep, "ms");
2365  mpParameters->Numerical().TimeSteps().set(time_steps);
2366  CheckTimeSteps();
2367 }
2368 
2369 void HeartConfig::SetOdeTimeStep(double odeTimeStep)
2370 {
2372 }
2373 
2374 void HeartConfig::SetPdeTimeStep(double pdeTimeStep)
2375 {
2377 }
2378 
2379 void HeartConfig::SetPrintingTimeStep(double printingTimeStep)
2380 {
2382 }
2383 
2385 {
2386  if (GetOdeTimeStep() <= 0)
2387  {
2388  EXCEPTION("Ode time-step should be positive");
2389  }
2390  if (GetPdeTimeStep() <= 0)
2391  {
2392  EXCEPTION("Pde time-step should be positive");
2393  }
2394  if (GetPrintingTimeStep() <= 0.0)
2395  {
2396  EXCEPTION("Printing time-step should be positive");
2397  }
2398 
2400  {
2401  EXCEPTION("Printing time-step should not be smaller than PDE time-step");
2402  }
2403 
2405  {
2406  EXCEPTION("Printing time-step should be a multiple of PDE time step");
2407  }
2408 
2409  if (GetOdeTimeStep() > GetPdeTimeStep())
2410  {
2411  EXCEPTION("Ode time-step should not be greater than PDE time-step");
2412  }
2413 
2415  {
2416  if (GetCheckpointTimestep() <= 0.0)
2417  {
2418  EXCEPTION("Checkpoint time-step should be positive");
2419  }
2420 
2422  {
2423  EXCEPTION("Checkpoint time-step should be a multiple of printing time-step");
2424  }
2425  }
2426 }
2427 
2428 void HeartConfig::SetUseRelativeTolerance(double relativeTolerance)
2429 {
2430  ENSURE_SECTION_PRESENT(mpParameters->Numerical().KSPTolerances(), cp::ksp_tolerances_type);
2431  //Remove any reference to tolerances is user parameters
2432  mpParameters->Numerical().KSPTolerances()->KSPAbsolute().reset();
2433  mpParameters->Numerical().KSPTolerances()->KSPRelative().set(relativeTolerance);
2434 }
2435 
2436 void HeartConfig::SetUseAbsoluteTolerance(double absoluteTolerance)
2437 {
2438  ENSURE_SECTION_PRESENT(mpParameters->Numerical().KSPTolerances(), cp::ksp_tolerances_type);
2439  //Remove any reference to tolerances is user parameters
2440  mpParameters->Numerical().KSPTolerances()->KSPRelative().reset();
2441  mpParameters->Numerical().KSPTolerances()->KSPAbsolute().set(absoluteTolerance);
2442 }
2443 
2444 void HeartConfig::SetKSPSolver(const char* kspSolver, bool warnOfChange)
2445 {
2446  if (warnOfChange && strcmp(GetKSPSolver(), kspSolver) != 0)
2447  {
2448  //Warn
2449  WARNING("Code has changed the KSP solver type from "<<GetKSPSolver()<<" to "<< kspSolver);
2450  }
2451 
2452  /* Note that changes in these conditions need to be reflected in the Doxygen*/
2453  if (strcmp(kspSolver, "gmres") == 0)
2454  {
2455  mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::gmres);
2456  return;
2457  }
2458  if (strcmp(kspSolver, "cg") == 0)
2459  {
2460  mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::cg);
2461  return;
2462  }
2463  if (strcmp(kspSolver, "symmlq") == 0)
2464  {
2465  mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::symmlq);
2466  return;
2467  }
2468  if (strcmp(kspSolver, "chebychev") == 0)
2469  {
2470  mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::chebychev);
2471  return;
2472  }
2473 
2474  EXCEPTION("Unknown solver type provided");
2475 }
2476 
2477 void HeartConfig::SetKSPPreconditioner(const char* kspPreconditioner)
2478 {
2479  /* Note that changes in these conditions need to be reflected in the Doxygen*/
2480  if (strcmp(kspPreconditioner, "jacobi") == 0)
2481  {
2482  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::jacobi);
2483  return;
2484  }
2485  if (strcmp(kspPreconditioner, "bjacobi") == 0)
2486  {
2487  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::bjacobi);
2488  return;
2489  }
2490  if (strcmp(kspPreconditioner, "hypre") == 0)
2491  {
2492  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::hypre);
2493  return;
2494  }
2495  if (strcmp(kspPreconditioner, "ml") == 0)
2496  {
2497  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ml);
2498  return;
2499  }
2500  if (strcmp(kspPreconditioner, "spai") == 0)
2501  {
2502  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::spai);
2503  return;
2504  }
2505  if (strcmp(kspPreconditioner, "twolevelsblockdiagonal") == 0)
2506  {
2507  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::twolevelsblockdiagonal);
2508  return;
2509  }
2510  if (strcmp(kspPreconditioner, "blockdiagonal") == 0)
2511  {
2512  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::blockdiagonal);
2513  return;
2514  }
2515  if (strcmp(kspPreconditioner, "ldufactorisation") == 0)
2516  {
2517  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ldufactorisation);
2518  return;
2519  }
2520  if (strcmp(kspPreconditioner, "none") == 0)
2521  {
2522  mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::none);
2523  return;
2524  }
2525 
2526  EXCEPTION("Unknown preconditioner type provided");
2527 }
2528 
2529 void HeartConfig::SetMeshPartitioning(const char* meshPartioningMethod)
2530 {
2531  /* Note that changes in these conditions need to be reflected in the Doxygen*/
2532  if (strcmp(meshPartioningMethod, "dumb") == 0)
2533  {
2534  mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::dumb);
2535  return;
2536  }
2537  if (strcmp(meshPartioningMethod, "metis") == 0)
2538  {
2539  mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::metis);
2540  return;
2541  }
2542  if (strcmp(meshPartioningMethod, "parmetis") == 0)
2543  {
2544  mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::parmetis);
2545  return;
2546  }
2547  if (strcmp(meshPartioningMethod, "petsc") == 0)
2548  {
2549  mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::petsc);
2550  return;
2551  }
2552 
2553  EXCEPTION("Unknown mesh partitioning method provided");
2554 }
2555 
2556 
2557 void HeartConfig::SetApdMaps(const std::vector<std::pair<double,double> >& apdMaps)
2558 {
2560  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ActionPotentialDurationMap)& apd_maps_sequence
2561  = mpParameters->PostProcessing()->ActionPotentialDurationMap();
2562  //Erase or create a sequence
2563  apd_maps_sequence.clear();
2564 
2565  for (unsigned i=0; i<apdMaps.size(); i++)
2566  {
2567  XSD_CREATE_WITH_FIXED_ATTR2(cp::apd_map_type, temp,
2568  apdMaps[i].first, apdMaps[i].second,
2569  "mV");
2570  apd_maps_sequence.push_back( temp);
2571  }
2572 }
2573 
2574 
2575 void HeartConfig::SetUpstrokeTimeMaps (std::vector<double>& upstrokeTimeMaps)
2576 {
2578  XSD_SEQUENCE_TYPE(cp::postprocessing_type::UpstrokeTimeMap)& var_type_sequence
2579  = mpParameters->PostProcessing()->UpstrokeTimeMap();
2580 
2581  //Erase or create a sequence
2582  var_type_sequence.clear();
2583 
2584  for (unsigned i=0; i<upstrokeTimeMaps.size(); i++)
2585  {
2586  XSD_CREATE_WITH_FIXED_ATTR1(cp::upstrokes_map_type, temp,
2587  upstrokeTimeMaps[i],
2588  "mV");
2589  var_type_sequence.push_back(temp);
2590  }
2591 }
2592 
2593 void HeartConfig::SetMaxUpstrokeVelocityMaps (std::vector<double>& maxUpstrokeVelocityMaps)
2594 {
2596  XSD_SEQUENCE_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap)& max_upstroke_velocity_maps_sequence
2597  = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
2598 
2599  //Erase or create a sequence
2600  max_upstroke_velocity_maps_sequence.clear();
2601 
2602  for (unsigned i=0; i<maxUpstrokeVelocityMaps.size(); i++)
2603  {
2604  XSD_CREATE_WITH_FIXED_ATTR1(cp::max_upstrokes_velocity_map_type, temp,
2605  maxUpstrokeVelocityMaps[i],
2606  "mV");
2607 
2608 
2609  max_upstroke_velocity_maps_sequence.push_back(temp);
2610  }
2611 
2612 }
2613 
2614 void HeartConfig::SetConductionVelocityMaps (std::vector<unsigned>& conductionVelocityMaps)
2615 {
2617  XSD_SEQUENCE_TYPE(cp::postprocessing_type::ConductionVelocityMap)& conduction_velocity_maps_sequence
2618  = mpParameters->PostProcessing()->ConductionVelocityMap();
2619 
2620  //Erase or create a sequence
2621  conduction_velocity_maps_sequence.clear();
2622 
2623  for (unsigned i=0; i<conductionVelocityMaps.size(); i++)
2624  {
2625  cp::conduction_velocity_map_type temp(conductionVelocityMaps[i]);
2626  conduction_velocity_maps_sequence.push_back(temp);
2627  }
2628 }
2629 
2630 void HeartConfig::SetRequestedNodalTimeTraces (std::vector<unsigned>& requestedNodes)
2631 {
2633  XSD_SEQUENCE_TYPE(cp::postprocessing_type::TimeTraceAtNode)& requested_nodes_sequence
2634  = mpParameters->PostProcessing()->TimeTraceAtNode();
2635 
2636  //Erase or create a sequence
2637  requested_nodes_sequence.clear();
2638 
2639  for (unsigned i=0; i<requestedNodes.size(); i++)
2640  {
2641  cp::node_number_type temp(requestedNodes[i]);
2642  requested_nodes_sequence.push_back(temp);
2643  }
2644 }
2645 
2646 template<unsigned SPACE_DIM>
2647 void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions)
2648 {
2650  XSD_SEQUENCE_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition)& electrodes_sequence
2651  = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
2652 
2653  //Erase or create a sequence
2654  electrodes_sequence.clear();
2655 
2656  for (unsigned i=0; i<rPseudoEcgElectrodePositions.size(); i++)
2657  {
2658  cp::point_type temp(rPseudoEcgElectrodePositions[i].GetWithDefault(0),
2659  rPseudoEcgElectrodePositions[i].GetWithDefault(1),
2660  rPseudoEcgElectrodePositions[i].GetWithDefault(2));
2661  electrodes_sequence.push_back(temp);
2662  }
2663 }
2664 
2665 
2666 /*
2667  * Output visualizer
2668  */
2669 
2671 {
2672  ENSURE_SECTION_PRESENT(mpParameters->Simulation()->OutputVisualizer(), cp::output_visualizer_type);
2673 }
2674 
2676 {
2678 
2679  mpParameters->Simulation()->OutputVisualizer()->meshalyzer(
2680  useMeshalyzer ? cp::yesno_type::yes : cp::yesno_type::no);
2681 }
2682 
2684 {
2686 
2687  mpParameters->Simulation()->OutputVisualizer()->cmgui(
2688  useCmgui ? cp::yesno_type::yes : cp::yesno_type::no);
2689 }
2690 
2692 {
2694 
2695  mpParameters->Simulation()->OutputVisualizer()->vtk(
2696  useVtk ? cp::yesno_type::yes : cp::yesno_type::no);
2697 }
2698 
2700 {
2702 
2703  mpParameters->Simulation()->OutputVisualizer()->parallel_vtk(
2704  useParallelVtk ? cp::yesno_type::yes : cp::yesno_type::no);
2705 }
2706 
2707 void HeartConfig::SetVisualizerOutputPrecision(unsigned numberOfDigits)
2708 {
2710 
2711  mpParameters->Simulation()->OutputVisualizer()->precision(numberOfDigits);
2712 }
2713 
2714 
2715 void HeartConfig::SetElectrodeParameters(bool groundSecondElectrode,
2716  unsigned index, double magnitude,
2717  double startTime, double duration )
2718 {
2719  assert(index < 3);
2720 
2721  cp::axis_type axis = cp::axis_type::x;
2722  if (index==1)
2723  {
2724  axis = cp::axis_type::y;
2725  }
2726  else if (index==2)
2727  {
2728  axis = cp::axis_type::z;
2729  }
2730 
2731  XSD_CREATE_WITH_FIXED_ATTR1(cp::surface_stimulus_strength_type, strength, magnitude, "uA/cm^2");
2732  XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, start_time, startTime, "ms");
2733  XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, duration_time, duration, "ms");
2734 
2735  if (!IsElectrodesPresent())
2736  {
2737  cp::electrodes_type element( groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no,
2738  axis,
2739  strength,
2740  start_time,
2741  duration_time );
2742  mpParameters->Simulation()->Electrodes().set(element);
2743  }
2744  else
2745  {
2746  mpParameters->Simulation()->Electrodes()->GroundSecondElectrode(groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no);
2747  mpParameters->Simulation()->Electrodes()->PerpendicularToAxis(axis);
2748  mpParameters->Simulation()->Electrodes()->Strength(strength);
2749  mpParameters->Simulation()->Electrodes()->StartTime(start_time);
2750  mpParameters->Simulation()->Electrodes()->Duration(duration_time);
2751  }
2752 }
2753 
2754 void HeartConfig::GetElectrodeParameters(bool& rGroundSecondElectrode,
2755  unsigned& rIndex, double& rMagnitude,
2756  double& rStartTime, double& rDuration )
2757 {
2758  if (!IsElectrodesPresent())
2759  {
2760  EXCEPTION("Attempted to get electrodes that have not been defined.");
2761  }
2762  else
2763  {
2764  rGroundSecondElectrode = (mpParameters->Simulation()->Electrodes()->GroundSecondElectrode()==cp::yesno_type::yes);
2765 
2766  cp::axis_type axis = mpParameters->Simulation()->Electrodes()->PerpendicularToAxis();
2767  if (axis==cp::axis_type::x)
2768  {
2769  rIndex = 0;
2770  }
2771  else if (axis==cp::axis_type::y)
2772  {
2773  rIndex = 1;
2774  }
2775  else
2776  {
2777  rIndex = 2;
2778  }
2779 
2780  rMagnitude = mpParameters->Simulation()->Electrodes()->Strength();
2781  rStartTime = mpParameters->Simulation()->Electrodes()->StartTime();
2782  rDuration = mpParameters->Simulation()->Electrodes()->Duration();
2783  }
2784 
2785 }
2786 
2788 {
2789  // If it's an older version parameters & defaults (we're loading a checkpoint) say 'no'
2790  bool result = false;
2791  if (mpParameters->Numerical().UseStateVariableInterpolation().present())
2792  {
2793  result = mpParameters->Numerical().UseStateVariableInterpolation().get() == cp::yesno_type::yes;
2794  }
2795  return result;
2796 }
2797 
2798 void HeartConfig::SetUseStateVariableInterpolation(bool useStateVariableInterpolation)
2799 {
2800  if (useStateVariableInterpolation)
2801  {
2802  mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::yes);
2803  }
2804  else
2805  {
2806  mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::no);
2807  }
2808 }
2809 
2811 {
2812  return mpParameters->Physiological().ApplyDrug().present();
2813 }
2814 
2816 {
2817  CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug");
2818  return mpParameters->Physiological().ApplyDrug()->concentration();
2819 }
2820 
2821 void HeartConfig::SetDrugDose(double drugDose)
2822 {
2823  if (!mpParameters->Physiological().ApplyDrug().present())
2824  {
2825  cp::apply_drug_type drug(drugDose);
2826  mpParameters->Physiological().ApplyDrug().set(drug);
2827  }
2828  else
2829  {
2830  mpParameters->Physiological().ApplyDrug()->concentration(drugDose);
2831  }
2832 }
2833 
2834 std::map<std::string, std::pair<double, double> > HeartConfig::GetIc50Values()
2835 {
2836  CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug");
2837  std::map<std::string, std::pair<double, double> > ic50s;
2838 
2839  XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)&
2840  ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50();
2841 
2842  for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin();
2843  i != ic50_seq.end();
2844  ++i)
2845  {
2846  std::pair<double, double> ic50_hill(*i, i->hill());
2847  std::string current = i->current();
2848  ic50s[current] = ic50_hill;
2849  }
2850 
2851  return ic50s;
2852 }
2853 
2854 void HeartConfig::SetIc50Value(const std::string& rCurrentName, double ic50, double hill)
2855 {
2856  if (!mpParameters->Physiological().ApplyDrug().present())
2857  {
2858  SetDrugDose(0.0);
2859  }
2860  XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)& ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50();
2861  if (ic50_seq.empty())
2862  {
2863  // Erase or create a sequence
2864  ic50_seq.clear();
2865  }
2866  bool entry_exists = false;
2867  cp::ic50_type ic50_elt(ic50, rCurrentName);
2868  ic50_elt.hill(hill);
2869  for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin();
2870  i != ic50_seq.end();
2871  ++i)
2872  {
2873  if (i->current() == rCurrentName)
2874  {
2875  entry_exists = true;
2876  *i = ic50_elt;
2877  break;
2878  }
2879  }
2880  if (!entry_exists)
2881  {
2882  ic50_seq.push_back(ic50_elt);
2883  }
2884 }
2885 
2886 void HeartConfig::SetUseMassLumping(bool useMassLumping)
2887 {
2888  mUseMassLumping = useMassLumping;
2889 }
2890 
2892 {
2893  return mUseMassLumping;
2894 }
2895 
2897 {
2898  mUseMassLumpingForPrecond = useMassLumping;
2899 }
2900 
2902 {
2904 }
2905 
2907 {
2908  mUseReactionDiffusionOperatorSplitting = useOperatorSplitting;
2909 }
2910 
2912 {
2914 }
2915 
2916 void HeartConfig::SetUseFixedNumberIterationsLinearSolver(bool useFixedNumberIterations, unsigned evaluateNumItsEveryNSolves)
2917 {
2918  mUseFixedNumberIterations = useFixedNumberIterations;
2919  mEvaluateNumItsEveryNSolves = evaluateNumItsEveryNSolves;
2920 }
2921 
2923 {
2925 }
2926 
2928 {
2930 }
2931 
2932 //
2933 // Purkinje methods
2934 //
2935 
2937 {
2938  CheckSimulationIsDefined("Purkinje");
2939  return mpParameters->Simulation()->Purkinje().present();
2940 }
2941 
2943 {
2944  CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2945  CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Capacitance().present(),
2946  "Physiological/Purkinje/Capacitance");
2947  return mpParameters->Physiological().Purkinje()->Capacitance().get();
2948 }
2949 
2950 void HeartConfig::SetPurkinjeCapacitance(double capacitance)
2951 {
2952  ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2953  XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, purk_Cm, capacitance, "uF/cm^2");
2954  mpParameters->Physiological().Purkinje()->Capacitance().set(purk_Cm);
2955 }
2956 
2957 
2959 {
2960  CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2961  CHECK_EXISTS(mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().present(),
2962  "Physiological/Purkinje/SurfaceAreaToVolumeRatio");
2963  return mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().get();
2964 }
2965 
2967 {
2968  ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2969  XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, purk_Am, ratio, "1/cm");
2970  mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().set(purk_Am);
2971 }
2972 
2974 {
2975  CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2976  CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Conductivity().present(),
2977  "Physiological/Purkinje/Conductivity");
2978  return mpParameters->Physiological().Purkinje()->Conductivity().get();
2979 }
2980 
2981 void HeartConfig::SetPurkinjeConductivity(double conductivity)
2982 {
2983  ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2984  XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, purkinje_conductivity, conductivity, "mS/cm");
2985  mpParameters->Physiological().Purkinje()->Conductivity().set(purkinje_conductivity);
2986 }
2987 
2988 /**********************************************************************
2989  * *
2990  * *
2991  * Utility methods for reading/transforming XML *
2992  * *
2993  * *
2994  **********************************************************************/
2995 
2996 
2997 void XmlTransforms::TransformArchiveDirectory(xercesc::DOMDocument* pDocument,
2998  xercesc::DOMElement* pRootElement)
2999 {
3000  using namespace xercesc;
3001  std::vector<xercesc::DOMElement*> elts = XmlTools::FindElements(
3002  pRootElement,
3003  "ResumeSimulation/ArchiveDirectory");
3004  if (elts.size() > 0)
3005  {
3006  // We have an ArchiveDirectory element, so add the relative_to='chaste_test_output' attribute
3007  DOMElement* p_dir_elt = elts[0];
3008  p_dir_elt->setAttribute(X("relative_to"), X("chaste_test_output"));
3009  }
3010 }
3011 
3012 void XmlTransforms::TransformIonicModelDefinitions(xercesc::DOMDocument* pDocument,
3013  xercesc::DOMElement* pRootElement)
3014 {
3015  // Default ionic model
3016  std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
3017  pRootElement,
3018  "Simulation/IonicModels/Default");
3019  if (p_elt_list.size() > 0)
3020  {
3021  assert(p_elt_list.size() == 1); // Asserted by schema
3022  XmlTools::WrapContentInElement(pDocument, p_elt_list[0], X("Hardcoded"));
3023  // Now do any region-specific definitions
3024  p_elt_list = XmlTools::FindElements(pRootElement, "Simulation/IonicModels/Region/IonicModel");
3025  for (unsigned i=0; i<p_elt_list.size(); i++)
3026  {
3027  XmlTools::WrapContentInElement(pDocument, p_elt_list[i], X("Hardcoded"));
3028  }
3029  }
3030 }
3031 
3032 void XmlTransforms::CheckForIluPreconditioner(xercesc::DOMDocument* pDocument,
3033  xercesc::DOMElement* pRootElement)
3034 {
3035  std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
3036  pRootElement,
3037  "Numerical/KSPPreconditioner");
3038  if (p_elt_list.size() > 0)
3039  {
3040  assert(p_elt_list.size() == 1); // Asserted by schema
3041  std::string text_value = X2C(p_elt_list[0]->getTextContent());
3042  if (text_value == "ilu")
3043  {
3044  EXCEPTION("PETSc does not have a parallel implementation of ilu, so we no longer allow it as an option. Use bjacobi instead.");
3045  }
3046  }
3047 }
3048 
3049 void XmlTransforms::MoveConductivityHeterogeneities(xercesc::DOMDocument* pDocument,
3050  xercesc::DOMElement* pRootElement)
3051 {
3052  std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
3053  pRootElement,
3054  "Simulation/ConductivityHeterogeneities");
3055  if (p_elt_list.size() > 0)
3056  {
3057  assert(p_elt_list.size() == 1); // Asserted by schema
3058  xercesc::DOMNode* p_parent = p_elt_list[0]->getParentNode();
3059  xercesc::DOMNode* p_child = p_parent->removeChild(p_elt_list[0]);
3060  std::vector<xercesc::DOMElement*> p_phys_list = XmlTools::FindElements(pRootElement, "Physiological");
3061  assert(p_phys_list.size() == 1); // Asserted by schema
3062  p_phys_list[0]->appendChild(p_child);
3063  }
3064 }
3065 
3066 void XmlTransforms::SetDefaultVisualizer(xercesc::DOMDocument* pDocument,
3067  xercesc::DOMElement* pRootElement)
3068 {
3069  std::vector<xercesc::DOMElement*> p_sim_list = XmlTools::FindElements(pRootElement, "Simulation");
3070  if (p_sim_list.size() > 0)
3071  {
3072  std::vector<xercesc::DOMElement*> p_viz_list = XmlTools::FindElements(p_sim_list[0], "OutputVisualizer");
3073  if (p_viz_list.empty())
3074  {
3075  // Create the element and set meshalyzer (only) to on
3076  xercesc::DOMElement* p_viz_elt = pDocument->createElementNS(X("https://chaste.comlab.ox.ac.uk/nss/parameters/3_3"), X("OutputVisualizer"));
3077  p_sim_list[0]->appendChild(p_viz_elt);
3078  p_viz_elt->setAttribute(X("meshalyzer"), X("yes"));
3079  }
3080  }
3081 }
3082 
3084 // Explicit instantiation of the templated functions
3086 // LCOV_EXCL_START //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously
3091 template void HeartConfig::GetIonicModelRegions<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& , std::vector<cp::ionic_model_selection_type>&) const;
3092 template void HeartConfig::GetStimuli<3u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >& ) const;
3093 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> >*);
3094 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;
3095 
3096 template void HeartConfig::GetIonicModelRegions<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& , std::vector<cp::ionic_model_selection_type>&) const;
3097 template void HeartConfig::GetStimuli<2u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >& ) const;
3098 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> >*);
3099 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;
3100 
3101 template void HeartConfig::GetIonicModelRegions<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& , std::vector<cp::ionic_model_selection_type>&) const;
3102 template void HeartConfig::GetStimuli<1u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >& , std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >& ) const;
3103 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> >*);
3104 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;
3105 
3106 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions) const;
3107 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions) const;
3108 template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions) const;
3109 
3110 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions);
3111 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions);
3112 template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions);
3117 // LCOV_EXCL_STOP //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously
3118 
3119 
3120 // Serialization for Boost >= 1.36
static std::string EscapeSpaces(const std::string &rPath)
Definition: XmlTools.cpp:442
void UpdateParametersFromResumeSimulation(boost::shared_ptr< cp::chaste_parameters_type > pResumeParameters)
double GetBathConductivity(unsigned bathRegion=UINT_MAX) const
void EnsureOutputVisualizerExists(void)
void SetIc50Value(const std::string &rCurrentName, double ic50, double hill=1.0)
void SetMeshFileName(std::string meshPrefix, cp::media_type fibreDefinition=cp::media_type::NoFibreOrientation)
void SetApdMaps(const std::vector< std::pair< double, double > > &rApdMaps)
void SetUseRelativeTolerance(double relativeTolerance)
std::map< std::string, std::string > SchemaLocationsMap
std::string GetOutputFilenamePrefix() const
bool GetUseAbsoluteTolerance() const
SchemaLocationsMap mSchemaLocations
void SetDomain(const cp::domain_type &rDomain)
double GetPurkinjeSurfaceAreaToVolumeRatio()
cp::media_type GetConductivityMedia() const
unsigned mEvaluateNumItsEveryNSolves
void SetRequestedNodalTimeTraces(std::vector< unsigned > &requestedNodes)
double GetSimulationDuration() const
void SetSpaceDimension(unsigned spaceDimension)
static bool IsRegionBath(HeartRegionType regionId)
bool GetCreateSheet() const
void GetIonicModelRegions(std::vector< boost::shared_ptr< AbstractChasteRegion< DIM > > > &rDefinedRegions, std::vector< cp::ionic_model_selection_type > &rIonicModels) const
const std::set< unsigned > & rGetTissueIdentifiers()
bool GetVisualizeWithVtk() const
bool IsAnyNodalTimeTraceRequested() const
void SetVisualizeWithMeshalyzer(bool useMeshalyzer=true)
void SetOutputDirectory(const std::string &rOutputDirectory)
void SetUseFixedNumberIterationsLinearSolver(bool useFixedNumberIterations=true, unsigned evaluateNumItsEveryNSolves=UINT_MAX)
bool IsConductionVelocityMapsRequested() const
void SetPseudoEcgElectrodePositions(const std::vector< ChastePoint< SPACE_DIM > > &rPseudoEcgElectrodePositions)
void SetSlabDimensions(double x, double y, double z, double inter_node_space)
unsigned GetVersionFromNamespace(const std::string &rNamespaceUri)
void SetBathMultipleConductivities(std::map< unsigned, double > bathConductivities)
unsigned GetEvaluateNumItsEveryNSolves()
void SetSheetDimensions(double x, double y, double inter_node_space)
bool HasPurkinje()
void GetCellHeterogeneities(std::vector< boost::shared_ptr< AbstractChasteRegion< DIM > > > &rCellHeterogeneityRegions, std::vector< double > &rScaleFactorGks, std::vector< double > &rScaleFactorIto, std::vector< double > &rScaleFactorGkr, std::vector< std::map< std::string, double > > *pParameterSettings)
void SetDefaultIonicModel(const cp::ionic_models_available_type &rIonicModel)
void GetIntracellularConductivities(c_vector< double, 3 > &rIntraConductivities) const
void GetExtracellularConductivities(c_vector< double, 3 > &rExtraConductivities) const
void CheckResumeSimulationIsDefined(std::string callingMethod="") const
void CheckSimulationIsDefined(std::string callingMethod="") const
bool GetUseMassLumpingForPrecond()
static xercesc::DOMElement * SetNamespace(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pElement, const std::string &rNamespace)
Definition: XmlTools.cpp:335
unsigned mIndexMid
void GetConductionVelocityMaps(std::vector< unsigned > &rConductionVelocityMaps) const
void Write(bool useArchiveLocationInfo=false, std::string subfolderName="output")
void GetSlabDimensions(c_vector< double, 3 > &slabDimensions) const
void SetPdeTimeStep(double pdeTimeStep)
double GetCheckpointTimestep() const
bool mUseMassLumpingForPrecond
double mMidFraction
#define EXCEPTION(message)
Definition: Exception.hpp:143
boost::shared_ptr< cp::chaste_parameters_type > mpParameters
std::map< unsigned, double > mBathConductivities
bool mUseFixedSchemaLocation
void SetTissueAndBathIdentifiers(const std::set< unsigned > &rTissueIds, const std::set< unsigned > &rBathIds)
void EnsurePostProcessingSectionPresent()
bool Divides(double smallerNumber, double largerNumber)
static std::vector< xercesc::DOMElement * > FindElements(const xercesc::DOMElement *pContextElement, const std::string &rPath)
Definition: XmlTools.cpp:384
bool IsSimulationDefined() const
void SetVisualizeWithCmgui(bool useCmgui=true)
static void TransformArchiveDirectory(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pRootElement)
void SetUseMassLumpingForPrecond(bool useMassLumping=true)
void SetUseStateVariableInterpolation(bool useStateVariableInterpolation=true)
bool GetOutputUsingOriginalNodeOrdering()
void SetKSPPreconditioner(const char *kspPreconditioner)
static bool AmMaster()
Definition: PetscTools.cpp:120
FileFinder CopyTo(const FileFinder &rDest) const
Definition: FileFinder.cpp:308
bool IsPseudoEcgCalculationRequested() const
unsigned mIndexEpi
unsigned GetEndoLayerIndex()
void SetElectrodeParameters(bool groundSecondElectrode, unsigned index, double magnitude, double startTime, double duration)
bool IsMaxUpstrokeVelocityMapRequested() const
void SetOutputUsingOriginalNodeOrdering(bool useOriginal)
bool GetVisualizeWithCmgui() const
void GetOutputVariables(std::vector< std::string > &rOutputVariables) const
DistributedTetrahedralMeshPartitionType::type GetMeshPartitioning() const
bool GetCreateFibre() const
double GetPrintingTimeStep() const
void SetVisualizeWithParallelVtk(bool useParallelVtk=true)
std::set< unsigned > mTissueIdentifiers
void SetPurkinjeSurfaceAreaToVolumeRatio(double ratio)
bool GetOutputVariablesProvided() const
void SetUseReactionDiffusionOperatorSplitting(bool useOperatorSplitting=true)
double GetAbsoluteTolerance() const
void SetDrugDose(double drugDose)
void SetCheckpointSimulation(bool checkpointSimulation, double checkpointTimestep=-1.0, unsigned maxCheckpointsOnDisk=UINT_MAX)
void SetUseFixedSchemaLocation(bool useFixedSchemaLocation)
std::string GetOutputDirectoryFullPath() const
double GetPdeTimeStep() const
void GetUpstrokeTimeMaps(std::vector< double > &rUpstrokeTimeMaps) const
bool IsApdMapsRequested() const
bool IsPostProcessingSectionPresent() const
#define NEVER_REACHED
Definition: Exception.hpp:206
void SetSurfaceAreaToVolumeRatio(double ratio)
double GetRelativeTolerance() const
bool mUseReactionDiffusionOperatorSplitting
std::string GetMeshName() const
void GetConductivityHeterogeneities(std::vector< boost::shared_ptr< AbstractChasteRegion< DIM > > > &conductivitiesHeterogeneityAreas, std::vector< c_vector< double, 3 > > &intraConductivities, std::vector< c_vector< double, 3 > > &extraConductivities) const
void GetFibreLength(c_vector< double, 1 > &fibreLength) const
bool GetUseFixedNumberIterationsLinearSolver()
bool IsAdaptivityParametersPresent() const
void MergeDefaults(boost::shared_ptr< cp::chaste_parameters_type > pParams, boost::shared_ptr< cp::chaste_parameters_type > pDefaults)
boost::shared_ptr< cp::chaste_parameters_type > CreateDefaultParameters()
void SetSimulationDuration(double simulationDuration)
void SetOdeTimeStep(double odeTimeStep)
cp::domain_type GetDomain() const
double GetEpiLayerFraction()
void SetExtracellularConductivities(const c_vector< double, 3 > &rExtraConductivities)
bool GetCreateSlab() const
static void TransformIonicModelDefinitions(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pRootElement)
bool mUserAskedForCellularTransmuralHeterogeneities
static void WrapContentInElement(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pElement, const XMLCh *pNewElementLocalName)
Definition: XmlTools.cpp:409
double GetDrugDose() const
void GetNodalTimeTraceRequested(std::vector< unsigned > &rRequestedNodes) const
void GetSheetDimensions(c_vector< double, 2 > &sheetDimensions) const
void SetConductivityHeterogeneities(std::vector< ChasteCuboid< 3 > > &rConductivityAreas, std::vector< c_vector< double, 3 > > &rIntraConductivities, std::vector< c_vector< double, 3 > > &rExtraConductivities)
double GetMidLayerFraction()
void SetUseMassLumping(bool useMassLumping=true)
bool GetUseStateVariableInterpolation() const
static void MoveConductivityHeterogeneities(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pRootElement)
std::set< unsigned > mBathIdentifiers
bool IsPostProcessingRequested() const
unsigned GetVisualizerOutputPrecision()
void LoadFromCheckpoint()
void SetConductionVelocityMaps(std::vector< unsigned > &rConductionVelocityMaps)
void SetFibreLength(double x, double inter_node_space)
void CheckTimeSteps() const
static void CheckForIluPreconditioner(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pRootElement)
void SetCapacitance(double capacitance)
double GetOdeTimeStep() const
unsigned GetSpaceDimension() const
void GetElectrodeParameters(bool &rGroundSecondElectrode, unsigned &rIndex, double &rMagnitude, double &rStartTime, double &rDuration)
unsigned GetEpiLayerIndex()
void GetPseudoEcgElectrodePositions(std::vector< ChastePoint< SPACE_DIM > > &rPseudoEcgElectrodePositions) const
bool GetUseReactionDiffusionOperatorSplitting()
void SetDefaultSchemaLocations()
bool IsElectrodesPresent() const
FileFinder GetParametersFilePath()
void SetMaxUpstrokeVelocityMaps(std::vector< double > &rMaxUpstrokeVelocityMaps)
bool GetUseMassLumping()
double mEndoFraction
c_vector< double, 1 > Create_c_vector(double x)
cp::ionic_model_selection_type GetDefaultIonicModel() const
void SetUpstrokeTimeMaps(std::vector< double > &rUpstrokeTimeMaps)
void SetMeshPartitioning(const char *meshPartioningMethod)
bool IsMeshProvided() const
static xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument > ReadXmlFile(const std::string &rFileName, const ::xsd::cxx::tree::properties< char > &rProps, bool validate=true)
Definition: XmlTools.cpp:53
unsigned GetMaxCheckpointsOnDisk() const
boost::shared_ptr< cp::chaste_parameters_type > ReadFile(const std::string &rFileName)
void SetFixedSchemaLocations(const SchemaLocationsMap &rSchemaLocations)
double GetInterNodeSpace() const
double GetPurkinjeConductivity()
bool HasDrugDose() const
bool Exists() const
Definition: FileFinder.cpp:180
double GetEndoLayerFraction()
unsigned GetMidLayerIndex()
void GetApdMaps(std::vector< std::pair< double, double > > &rApdMaps) const
void SetParametersFile(const std::string &rFileName)
static void SetDefaultVisualizer(xercesc::DOMDocument *pDocument, xercesc::DOMElement *pRootElement)
bool GetCreateMesh() const
void SetIonicModelRegions(std::vector< ChasteCuboid< 3 > > &rDefinedRegions, std::vector< cp::ionic_model_selection_type > &rIonicModels) const
bool GetCheckpointSimulation() const
bool GetVisualizeWithParallelVtk() const
double GetPurkinjeCapacitance()
void SetKSPSolver(const char *kspSolver, bool warnOfChange=false)
bool GetLoadMesh() const
bool mUseFixedNumberIterations
const std::set< unsigned > & rGetBathIdentifiers()
double GetCapacitance() const
bool IsOutputVisualizerPresent() const
#define CHASTE_CLASS_EXPORT(T)
void SetIntracellularConductivities(const c_vector< double, 3 > &rIntraConductivities)
bool GetVisualizeWithMeshalyzer() const
FileFinder mParametersFilePath
void SetPurkinjeCapacitance(double capacitance)
double GetSurfaceAreaToVolumeRatio() const
std::string GetOutputDirectory() const
void SetOutputVariables(const std::vector< std::string > &rOutputVariables)
const char * GetKSPPreconditioner() const
bool IsSimulationResumed() const
virtual void SetPath(const std::string &rPath, RelativeTo::Value relativeTo)
Definition: FileFinder.cpp:99
void GetMaxUpstrokeVelocityMaps(std::vector< double > &rUpstrokeVelocityMaps) const
void SetVisualizerOutputPrecision(unsigned numberOfDigits)
static std::string GetArchiveDirectory()
HeartFileFinder GetArchivedSimulationDir() const
static void Reset()
void SetPrintingTimeStep(double printingTimeStep)
unsigned mIndexEndo
void SetPurkinjeConductivity(double conductivity)
bool AreCellularTransmuralHeterogeneitiesRequested()
void GetStimuli(std::vector< boost::shared_ptr< AbstractStimulusFunction > > &rStimuliApplied, std::vector< boost::shared_ptr< AbstractChasteRegion< DIM > > > &rStimulatedAreas) const
void SetUseAbsoluteTolerance(double absoluteTolerance)
void SetOutputFilenamePrefix(const std::string &rOutputFilenamePrefix)
bool mUseMassLumping
static HeartConfig * Instance()
static boost::shared_ptr< HeartConfig > mpInstance
static const char * GetRootDir()
bool GetUseRelativeTolerance() const
void SetBathConductivity(double bathConductivity)
bool IsUpstrokeTimeMapsRequested() const
void SetVisualizeWithVtk(bool useVtk=true)
const char * GetKSPSolver() const
bool GetConductivityHeterogeneitiesProvided() const
double mEpiFraction
void CopySchema(const std::string &rToDirectory)
void SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep)
void SetConductivityHeterogeneitiesEllipsoid(std::vector< ChasteEllipsoid< 3 > > &rConductivityAreas, std::vector< c_vector< double, 3 > > &rIntraConductivities, std::vector< c_vector< double, 3 > > &rExtraConductivities)
std::map< std::string, std::pair< double, double > > GetIc50Values()