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