Chaste Commit::9e4a273f0754a391514ab12ed9d4a38fc9933db2
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 auto cell_heterogeneity = mpParameters->Simulation()->CellHeterogeneities()->CellHeterogeneity();
1134
1135 bool user_supplied_negative_value = false;
1136 mUserAskedForCellularTransmuralHeterogeneities = false; // overwritten with true below if necessary
1137 bool user_asked_for_cuboids_or_ellipsoids = false;
1138 unsigned counter_of_heterogeneities = 0;
1139
1140 for (XSD_ITERATOR_TYPE(cp::cell_heterogeneities_type::CellHeterogeneity) i = cell_heterogeneity.begin();
1141 i != cell_heterogeneity.end();
1142 ++i)
1143 {
1144 cp::cell_heterogeneity_type ht(*i);
1145
1146 if (ht.Location().Cuboid().present())
1147 {
1148 user_asked_for_cuboids_or_ellipsoids = true;
1149 cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates();
1150 cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates();
1151
1152 ChastePoint<DIM> chaste_point_a(point_a.x(), point_a.y(), point_a.z());
1153 ChastePoint<DIM> chaste_point_b(point_b.x(), point_b.y(), point_b.z());
1154
1155 rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>(chaste_point_a, chaste_point_b)));
1156 }
1157 else if (ht.Location().Ellipsoid().present())
1158 {
1159 user_asked_for_cuboids_or_ellipsoids = true;
1160 cp::point_type centre = ht.Location().Ellipsoid()->Centre();
1161 cp::point_type radii = ht.Location().Ellipsoid()->Radii();
1162
1163 ChastePoint<DIM> chaste_point_a(centre.x(), centre.y(), centre.z());
1164 ChastePoint<DIM> chaste_point_b(radii.x(), radii.y(), radii.z());
1165 rCellHeterogeneityRegions.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM>(chaste_point_a, chaste_point_b)));
1166 }
1167 else if (ht.Location().EpiLayer().present())
1168 {
1169 mEpiFraction = ht.Location().EpiLayer().get();
1170
1172 if (mEpiFraction < 0)
1173 {
1174 user_supplied_negative_value = true;
1175 }
1176 mIndexEpi = counter_of_heterogeneities;
1177 }
1178 else if (ht.Location().EndoLayer().present())
1179 {
1180 mEndoFraction = ht.Location().EndoLayer().get();
1181
1183 if (mEndoFraction < 0)
1184 {
1185 user_supplied_negative_value = true;
1186 }
1187 mIndexEndo = counter_of_heterogeneities;
1188 }
1189 else if (ht.Location().MidLayer().present())
1190 {
1191 mMidFraction = ht.Location().MidLayer().get();
1192
1194 if (mMidFraction < 0)
1195 {
1196 user_supplied_negative_value = true;
1197 }
1198 mIndexMid = counter_of_heterogeneities;
1199 }
1200 else
1201 {
1202 EXCEPTION("Invalid region type for cell heterogeneity definition");
1203 }
1204
1205 // Old scale factors
1206 rScaleFactorGks.push_back(ht.ScaleFactorGks().present() ? (double)ht.ScaleFactorGks().get() : 1.0);
1207 rScaleFactorIto.push_back(ht.ScaleFactorIto().present() ? (double)ht.ScaleFactorIto().get() : 1.0);
1208 rScaleFactorGkr.push_back(ht.ScaleFactorGkr().present() ? (double)ht.ScaleFactorGkr().get() : 1.0);
1209
1210 // Named parameters
1211 if (pParameterSettings)
1212 {
1213 std::map<std::string, double> param_settings;
1214 XSD_SEQUENCE_TYPE(cp::cell_heterogeneity_type::SetParameter)& params = ht.SetParameter();
1215 for (XSD_ITERATOR_TYPE(cp::cell_heterogeneity_type::SetParameter) param_it = params.begin();
1216 param_it != params.end();
1217 ++param_it)
1218 {
1219 cp::set_parameter_type param(*param_it);
1220 param_settings[param.name()] = param.value();
1221 }
1222 pParameterSettings->push_back(param_settings);
1223 }
1224
1225 counter_of_heterogeneities++;
1226 }
1227
1229 {
1230 // cuboids/ellipsoids and layers at the same time are not yet supported
1231 if (user_asked_for_cuboids_or_ellipsoids)
1232 {
1233 EXCEPTION("Specification of cellular heterogeneities by cuboids/ellipsoids and layers at the same time is not yet supported");
1234 }
1235
1236 //check that the user supplied all three layers, the indexes should be 0, 1 and 2.
1237 // As they are initialised to a higher value, if their summation is higher than 3,
1238 // one (or more) is missing
1239 if ((mIndexMid + mIndexEndo + mIndexEpi) > 3)
1240 {
1241 EXCEPTION("Three specifications of layers must be supplied");
1242 }
1243 if (fabs((mEndoFraction + mMidFraction + mEpiFraction) - 1) > 1e-2)
1244 {
1245 EXCEPTION("Summation of epicardial, midmyocardial and endocardial fractions should be 1");
1246 }
1247 if (user_supplied_negative_value)
1248 {
1249 EXCEPTION("Fractions must be positive");
1250 }
1251 }
1252}
1253
1258
1260{
1261 return mEpiFraction;
1262}
1263
1265{
1266 return mEndoFraction;
1267}
1268
1270{
1271 return mMidFraction;
1272}
1273
1275{
1276 return mIndexEpi;
1277}
1278
1280{
1281 return mIndexEndo;
1282}
1283
1285{
1286 return mIndexMid;
1287}
1288
1290{
1291 CheckSimulationIsDefined("ConductivityHeterogeneities");
1292 return mpParameters->Physiological().ConductivityHeterogeneities().present();
1293}
1294
1295template <unsigned DIM>
1297 std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rConductivitiesHeterogeneityAreas,
1298 std::vector<c_vector<double, 3> >& rIntraConductivities,
1299 std::vector<c_vector<double, 3> >& rExtraConductivities) const
1300{
1301 CheckSimulationIsDefined("ConductivityHeterogeneities");
1302 CHECK_EXISTS(GetConductivityHeterogeneitiesProvided(), "Physiological/ConductivityHeterogeneities");
1303 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity)& conductivity_heterogeneity = mpParameters->Physiological().ConductivityHeterogeneities()->ConductivityHeterogeneity();
1304
1305 for (XSD_ANON_ITERATOR_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity) i = conductivity_heterogeneity.begin();
1306 i != conductivity_heterogeneity.end();
1307 ++i)
1308 {
1309 cp::conductivity_heterogeneity_type ht(*i);
1310
1311 if (ht.Location().Cuboid().present())
1312 {
1313 cp::point_type point_a = ht.Location().Cuboid()->LowerCoordinates();
1314 cp::point_type point_b = ht.Location().Cuboid()->UpperCoordinates();
1315 ChastePoint<DIM> chaste_point_a(point_a.x(), point_a.y(), point_a.z());
1316 ChastePoint<DIM> chaste_point_b(point_b.x(), point_b.y(), point_b.z());
1317 rConductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteCuboid<DIM>(chaste_point_a, chaste_point_b)));
1318 }
1319 else if (ht.Location().Ellipsoid().present())
1320 {
1321 cp::point_type centre = ht.Location().Ellipsoid()->Centre();
1322 cp::point_type radii = ht.Location().Ellipsoid()->Radii();
1323 ChastePoint<DIM> chaste_point_a(centre.x(), centre.y(), centre.z());
1324 ChastePoint<DIM> chaste_point_b(radii.x(), radii.y(), radii.z());
1325 rConductivitiesHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<DIM> >(new ChasteEllipsoid<DIM>(chaste_point_a, chaste_point_b)));
1326 }
1327 else if (ht.Location().EpiLayer().present() || ht.Location().MidLayer().present() || ht.Location().EndoLayer().present())
1328 {
1330 EXCEPTION("Definition of transmural layers is not allowed for conductivities heterogeneities, you may use fibre orientation support instead");
1331 }
1332 else
1333 {
1334 EXCEPTION("Invalid region type for conductivity definition");
1335 }
1336
1337 if (ht.IntracellularConductivities().present())
1338 {
1339 double intra_x = ht.IntracellularConductivities()->longi();
1340 double intra_y = ht.IntracellularConductivities()->trans();
1341 double intra_z = ht.IntracellularConductivities()->normal();
1342
1343 rIntraConductivities.push_back(Create_c_vector(intra_x, intra_y, intra_z));
1344 }
1345 else
1346 {
1347 c_vector<double, 3> intra_conductivities;
1348 GetIntracellularConductivities(intra_conductivities);
1349 rIntraConductivities.push_back(intra_conductivities);
1350 }
1351
1352 if (ht.ExtracellularConductivities().present())
1353 {
1354 double extra_x = ht.ExtracellularConductivities()->longi();
1355 double extra_y = ht.ExtracellularConductivities()->trans();
1356 double extra_z = ht.ExtracellularConductivities()->normal();
1357
1358 rExtraConductivities.push_back(Create_c_vector(extra_x, extra_y, extra_z));
1359 }
1360 else
1361 {
1362 c_vector<double, 3> extra_conductivities;
1363 GetExtracellularConductivities(extra_conductivities);
1364 rExtraConductivities.push_back(extra_conductivities);
1365 }
1366 }
1367}
1368
1370{
1371 CheckSimulationIsDefined("Simulation/OutputDirectory");
1372 CHECK_EXISTS(mpParameters->Simulation()->OutputDirectory().present(), "Simulation/OutputDirectory");
1373 return mpParameters->Simulation()->OutputDirectory().get();
1374}
1375
1377{
1378 CheckSimulationIsDefined("Simulation/OutputFilenamePrefix");
1379 CHECK_EXISTS(mpParameters->Simulation()->OutputFilenamePrefix().present(), "Simulation/OutputFilenamePrefix");
1380 return mpParameters->Simulation()->OutputFilenamePrefix().get();
1381}
1382
1384{
1385 CheckSimulationIsDefined("OutputVariables");
1386 return mpParameters->Simulation()->OutputVariables().present();
1387}
1388
1389void HeartConfig::GetOutputVariables(std::vector<std::string>& rOutputVariables) const
1390{
1391 CHECK_EXISTS(GetOutputVariablesProvided(), "Simulation/OutputVariables");
1392 XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)& output_variables = mpParameters->Simulation()->OutputVariables()->Var();
1393 rOutputVariables.clear();
1394
1395 for (XSD_ITERATOR_TYPE(cp::output_variables_type::Var) i = output_variables.begin();
1396 i != output_variables.end();
1397 ++i)
1398 {
1399 cp::var_type& r_var(*i);
1400
1401 // Add to outputVariables the string returned by var.name()
1402 rOutputVariables.push_back(r_var.name());
1403 }
1404}
1405
1407{
1408 CheckSimulationIsDefined("OutputUsingOriginalNodeOrdering");
1409 bool result = false;
1410 if (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().present())
1411 {
1412 result = (mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().get() == cp::yesno_type::yes);
1413 }
1414 return result;
1415}
1416
1418{
1419 return IsSimulationDefined() && mpParameters->Simulation()->CheckpointSimulation().present();
1420}
1421
1423{
1424 CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation");
1425 return mpParameters->Simulation()->CheckpointSimulation()->timestep();
1426}
1427
1429{
1430 CHECK_EXISTS(GetCheckpointSimulation(), "Simulation/CheckpointSimulation");
1431 return mpParameters->Simulation()->CheckpointSimulation()->max_checkpoints_on_disk();
1432}
1433
1435{
1436 CheckResumeSimulationIsDefined("GetArchivedSimulationDir");
1437
1438 return HeartFileFinder(mpParameters->ResumeSimulation()->ArchiveDirectory());
1439}
1440
1441void HeartConfig::GetIntracellularConductivities(c_vector<double, 3>& rIntraConductivities) const
1442{
1443 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1444 cp::conductivities_type intra_conductivities = mpParameters->Physiological().IntracellularConductivities().get();
1445 double intra_x_cond = intra_conductivities.longi();
1446 double intra_y_cond = intra_conductivities.trans();
1447 double intra_z_cond = intra_conductivities.normal();
1448 ;
1449
1450 assert(intra_y_cond != DBL_MAX);
1451 assert(intra_z_cond != DBL_MAX);
1452
1453 rIntraConductivities[0] = intra_x_cond;
1454 rIntraConductivities[1] = intra_y_cond;
1455 rIntraConductivities[2] = intra_z_cond;
1456}
1457
1458void HeartConfig::GetIntracellularConductivities(c_vector<double, 2>& rIntraConductivities) const
1459{
1460 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1461 cp::conductivities_type intra_conductivities = mpParameters->Physiological().IntracellularConductivities().get();
1462 double intra_x_cond = intra_conductivities.longi();
1463 double intra_y_cond = intra_conductivities.trans();
1464
1465 assert(intra_y_cond != DBL_MAX);
1466
1467 rIntraConductivities[0] = intra_x_cond;
1468 rIntraConductivities[1] = intra_y_cond;
1469}
1470
1471void HeartConfig::GetIntracellularConductivities(c_vector<double, 1>& rIntraConductivities) const
1472{
1473 CHECK_EXISTS(mpParameters->Physiological().IntracellularConductivities().present(), "Physiological/IntracellularConductivities");
1474 cp::conductivities_type intra_conductivities = mpParameters->Physiological().IntracellularConductivities().get();
1475 double intra_x_cond = intra_conductivities.longi();
1476
1477 rIntraConductivities[0] = intra_x_cond;
1478}
1479
1480void HeartConfig::GetExtracellularConductivities(c_vector<double, 3>& rExtraConductivities) const
1481{
1482 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1483 cp::conductivities_type extra_conductivities = mpParameters->Physiological().ExtracellularConductivities().get();
1484 double extra_x_cond = extra_conductivities.longi();
1485 double extra_y_cond = extra_conductivities.trans();
1486 double extra_z_cond = extra_conductivities.normal();
1487 ;
1488
1489 assert(extra_y_cond != DBL_MAX);
1490 assert(extra_z_cond != DBL_MAX);
1491
1492 rExtraConductivities[0] = extra_x_cond;
1493 rExtraConductivities[1] = extra_y_cond;
1494 rExtraConductivities[2] = extra_z_cond;
1495}
1496
1497void HeartConfig::GetExtracellularConductivities(c_vector<double, 2>& rExtraConductivities) const
1498{
1499 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1500 cp::conductivities_type extra_conductivities = mpParameters->Physiological().ExtracellularConductivities().get();
1501 double extra_x_cond = extra_conductivities.longi();
1502 double extra_y_cond = extra_conductivities.trans();
1503
1504 assert(extra_y_cond != DBL_MAX);
1505
1506 rExtraConductivities[0] = extra_x_cond;
1507 rExtraConductivities[1] = extra_y_cond;
1508}
1509
1510void HeartConfig::GetExtracellularConductivities(c_vector<double, 1>& rExtraConductivities) const
1511{
1512 CHECK_EXISTS(mpParameters->Physiological().ExtracellularConductivities().present(), "Physiological/ExtracellularConductivities");
1513 cp::conductivities_type extra_conductivities = mpParameters->Physiological().ExtracellularConductivities().get();
1514 double extra_x_cond = extra_conductivities.longi();
1515
1516 rExtraConductivities[0] = extra_x_cond;
1517}
1518
1519double HeartConfig::GetBathConductivity(unsigned bathRegion) const
1520{
1521 /*
1522 * We have to consider three cases: The user asks for ...
1523 * a) ... the default conductivity (bathRegion=UINT_MAX)
1524 * b) ... the conductivity of region defined to be heterogeneous
1525 * c) ... the conductivity of region NOT defined to be heterogeneous
1526 *
1527 * a) and c) should return the same
1528 */
1529
1530 if (bathRegion == UINT_MAX)
1531 {
1532 /*bath conductivity mS/cm*/
1533 CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity");
1534 return mpParameters->Physiological().BathConductivity().get();
1535 }
1536 else
1537 {
1538 assert(HeartRegionCode::IsRegionBath(bathRegion));
1539
1540 std::map<unsigned, double>::const_iterator map_entry = mBathConductivities.find(bathRegion);
1541
1542 if (map_entry != mBathConductivities.end())
1543 {
1544 return map_entry->second;
1545 }
1546 else
1547 {
1548 /*bath conductivity mS/cm*/
1549 CHECK_EXISTS(mpParameters->Physiological().BathConductivity().present(), "Physiological/BathConductivity");
1550 return mpParameters->Physiological().BathConductivity().get();
1551 }
1552 }
1553}
1554const std::set<unsigned>& HeartConfig::rGetTissueIdentifiers()
1555{
1556 return mTissueIdentifiers;
1557}
1558
1559const std::set<unsigned>& HeartConfig::rGetBathIdentifiers()
1560{
1561 return mBathIdentifiers;
1562}
1563
1565{
1566 CHECK_EXISTS(mpParameters->Physiological().SurfaceAreaToVolumeRatio().present(), "Physiological/SurfaceAreaToVolumeRatio");
1567 return mpParameters->Physiological().SurfaceAreaToVolumeRatio().get();
1568}
1569
1571{
1572 CHECK_EXISTS(mpParameters->Physiological().Capacitance().present(), "Physiological/Capacitance");
1573 return mpParameters->Physiological().Capacitance().get();
1574}
1575
1577{
1578 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1579 return mpParameters->Numerical().TimeSteps()->ode();
1580}
1581
1583{
1584 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1585 return mpParameters->Numerical().TimeSteps()->pde();
1586}
1587
1589{
1590 CHECK_EXISTS(mpParameters->Numerical().TimeSteps().present(), "Numerical/TimeSteps");
1591 return mpParameters->Numerical().TimeSteps()->printing();
1592}
1593
1595{
1596 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1597 return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().present();
1598}
1599
1601{
1602 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1604 {
1605 EXCEPTION("Absolute tolerance is not set in Chaste parameters");
1606 }
1607 return mpParameters->Numerical().KSPTolerances()->KSPAbsolute().get();
1608}
1609
1611{
1612 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1613 return mpParameters->Numerical().KSPTolerances()->KSPRelative().present();
1614}
1615
1617{
1618 CHECK_EXISTS(mpParameters->Numerical().KSPTolerances().present(), "Numerical/KSPTolerances");
1620 {
1621 EXCEPTION("Relative tolerance is not set in Chaste parameters");
1622 }
1623 return mpParameters->Numerical().KSPTolerances()->KSPRelative().get();
1624}
1625
1626const char* HeartConfig::GetKSPSolver() const
1627{
1628 CHECK_EXISTS(mpParameters->Numerical().KSPSolver().present(), "Numerical/KSPSolver");
1629 switch (mpParameters->Numerical().KSPSolver().get())
1630 {
1631 case cp::ksp_solver_type::gmres:
1632 return "gmres";
1633 case cp::ksp_solver_type::cg:
1634 return "cg";
1635 case cp::ksp_solver_type::symmlq:
1636 return "symmlq";
1637 case cp::ksp_solver_type::chebychev:
1638 return "chebychev";
1639 }
1640 // LCOV_EXCL_START
1641 EXCEPTION("Unknown ksp solver");
1642 // LCOV_EXCL_STOP
1643}
1644
1646{
1647 CHECK_EXISTS(mpParameters->Numerical().KSPPreconditioner().present(), "Numerical/KSPPreconditioner");
1648 switch (mpParameters->Numerical().KSPPreconditioner().get())
1649 {
1650 case cp::ksp_preconditioner_type::jacobi:
1651 return "jacobi";
1652 case cp::ksp_preconditioner_type::bjacobi:
1653 return "bjacobi";
1654 case cp::ksp_preconditioner_type::hypre:
1655 return "hypre";
1656 case cp::ksp_preconditioner_type::ml:
1657 return "ml";
1658 case cp::ksp_preconditioner_type::spai:
1659 return "spai";
1660 case cp::ksp_preconditioner_type::blockdiagonal:
1661 return "blockdiagonal";
1662 case cp::ksp_preconditioner_type::ldufactorisation:
1663 return "ldufactorisation";
1664 case cp::ksp_preconditioner_type::twolevelsblockdiagonal:
1665 return "twolevelsblockdiagonal";
1666 case cp::ksp_preconditioner_type::none:
1667 return "none";
1668 }
1669 // LCOV_EXCL_START
1670 EXCEPTION("Unknown ksp preconditioner");
1671 // LCOV_EXCL_STOP
1672}
1673
1675{
1676 CHECK_EXISTS(mpParameters->Numerical().MeshPartitioning().present(), "Numerical/MeshPartitioning");
1677 switch (mpParameters->Numerical().MeshPartitioning().get())
1678 {
1679 case cp::mesh_partitioning_type::dumb:
1680 return DistributedTetrahedralMeshPartitionType::DUMB;
1681 case cp::mesh_partitioning_type::metis:
1682 return DistributedTetrahedralMeshPartitionType::METIS_LIBRARY;
1683 case cp::mesh_partitioning_type::parmetis:
1684 return DistributedTetrahedralMeshPartitionType::PARMETIS_LIBRARY;
1685 case cp::mesh_partitioning_type::petsc:
1686 return DistributedTetrahedralMeshPartitionType::PETSC_MAT_PARTITION;
1687 }
1688 // LCOV_EXCL_START
1689 EXCEPTION("Unknown mesh partitioning type");
1690 // LCOV_EXCL_STOP
1691}
1692
1694{
1695 bool IsAdaptivityParametersPresent = mpParameters->Numerical().AdaptivityParameters().present();
1697 {
1698 WARNING("Use of the Adaptivity library is deprecated");
1699 }
1701}
1702
1703/*
1704 * PostProcessing
1705 */
1706
1708{
1709 return mpParameters->PostProcessing().present();
1710}
1711
1713{
1714 ENSURE_SECTION_PRESENT(mpParameters->PostProcessing(), cp::postprocessing_type);
1715}
1716
1729{
1730 bool result = false;
1732 {
1733 auto& apd_maps = mpParameters->PostProcessing()->ActionPotentialDurationMap();
1734 result = (apd_maps.begin() != apd_maps.end());
1735 }
1736 return result;
1737}
1738
1739void HeartConfig::GetApdMaps(std::vector<std::pair<double, double> >& apd_maps) const
1740{
1741 CHECK_EXISTS(IsApdMapsRequested(), "PostProcessing/ActionPotentialDurationMap");
1742 apd_maps.clear();
1743
1744 auto& apd_maps_sequence = mpParameters->PostProcessing()->ActionPotentialDurationMap();
1745
1746 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ActionPotentialDurationMap) i = apd_maps_sequence.begin();
1747 i != apd_maps_sequence.end();
1748 ++i)
1749 {
1750 std::pair<double, double> map(i->repolarisation_percentage(), i->threshold());
1751
1752 apd_maps.push_back(map);
1753 }
1754}
1755
1757{
1758 bool result = false;
1760 {
1761 auto& upstroke_map = mpParameters->PostProcessing()->UpstrokeTimeMap();
1762 result = (upstroke_map.begin() != upstroke_map.end());
1763 }
1764 return result;
1765}
1766void HeartConfig::GetUpstrokeTimeMaps(std::vector<double>& upstroke_time_maps) const
1767{
1768 CHECK_EXISTS(IsUpstrokeTimeMapsRequested(), "PostProcessing/UpstrokeTimeMap");
1769 assert(upstroke_time_maps.size() == 0);
1770
1771 auto& upstroke_maps_sequence = mpParameters->PostProcessing()->UpstrokeTimeMap();
1772
1773 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::UpstrokeTimeMap) i = upstroke_maps_sequence.begin();
1774 i != upstroke_maps_sequence.end();
1775 ++i)
1776 {
1777 upstroke_time_maps.push_back(i->threshold());
1778 }
1779}
1780
1782{
1783 bool result = false;
1785 {
1786 auto& max_upstroke_velocity_map = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
1787 result = (max_upstroke_velocity_map.begin() != max_upstroke_velocity_map.end());
1788 }
1789 return result;
1790}
1791
1792void HeartConfig::GetMaxUpstrokeVelocityMaps(std::vector<double>& upstroke_velocity_maps) const
1793{
1794 CHECK_EXISTS(IsMaxUpstrokeVelocityMapRequested(), "PostProcessing/MaxUpstrokeVelocityMap");
1795 assert(upstroke_velocity_maps.size() == 0);
1796
1797 auto& max_upstroke_velocity_maps_sequence = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
1798
1799 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::MaxUpstrokeVelocityMap) i = max_upstroke_velocity_maps_sequence.begin();
1800 i != max_upstroke_velocity_maps_sequence.end();
1801 ++i)
1802 {
1803 upstroke_velocity_maps.push_back(i->threshold());
1804 }
1805}
1806
1808{
1809 bool result = false;
1811 {
1812 auto& cond_vel_maps = mpParameters->PostProcessing()->ConductionVelocityMap();
1813 result = (cond_vel_maps.begin() != cond_vel_maps.end());
1814 }
1815 return result;
1816}
1817
1818void HeartConfig::GetConductionVelocityMaps(std::vector<unsigned>& conduction_velocity_maps) const
1819{
1820 CHECK_EXISTS(IsConductionVelocityMapsRequested(), "PostProcessing/ConductionVelocityMap");
1821 assert(conduction_velocity_maps.size() == 0);
1822
1823 auto& cond_vel_maps_sequence = mpParameters->PostProcessing()->ConductionVelocityMap();
1824
1825 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::ConductionVelocityMap) i = cond_vel_maps_sequence.begin();
1826 i != cond_vel_maps_sequence.end();
1827 ++i)
1828 {
1829 conduction_velocity_maps.push_back(i->origin_node());
1830 }
1831}
1832
1834{
1835 bool result = false;
1837 {
1838 auto& requested_nodes = mpParameters->PostProcessing()->TimeTraceAtNode();
1839 result = (requested_nodes.begin() != requested_nodes.end());
1840 }
1841 return result;
1842}
1843
1844void HeartConfig::GetNodalTimeTraceRequested(std::vector<unsigned>& rRequestedNodes) const
1845{
1846 CHECK_EXISTS(IsAnyNodalTimeTraceRequested(), "PostProcessing/TimeTraceAtNode");
1847 assert(rRequestedNodes.size() == 0);
1848
1849 auto& req_nodes = mpParameters->PostProcessing()->TimeTraceAtNode();
1850
1851 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::TimeTraceAtNode) i = req_nodes.begin();
1852 i != req_nodes.end();
1853 ++i)
1854 {
1855 rRequestedNodes.push_back(i->node_number());
1856 }
1857}
1858
1860{
1861 bool result = false;
1863 {
1864 auto& electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
1865 result = (electrodes.begin() != electrodes.end());
1866 }
1867 return result;
1868}
1869
1870template <unsigned SPACE_DIM>
1871void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions) const
1872{
1873 rPseudoEcgElectrodePositions.clear();
1874 auto& electrodes = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
1875 for (XSD_ITERATOR_TYPE(cp::postprocessing_type::PseudoEcgElectrodePosition) i = electrodes.begin();
1876 i != electrodes.end();
1877 ++i)
1878 {
1879 rPseudoEcgElectrodePositions.push_back(ChastePoint<SPACE_DIM>(i->x(), i->y(), i->z()));
1880 }
1881}
1882
1883/*
1884 * Output visualization
1885 */
1886
1888{
1889 CheckSimulationIsDefined("OutputVisualizer");
1890
1891 return mpParameters->Simulation()->OutputVisualizer().present();
1892}
1893
1895{
1897 {
1898 return false;
1899 }
1900 else
1901 {
1902 return mpParameters->Simulation()->OutputVisualizer()->meshalyzer() == cp::yesno_type::yes;
1903 }
1904}
1905
1907{
1909 {
1910 return false;
1911 }
1912 else
1913 {
1914 return mpParameters->Simulation()->OutputVisualizer()->cmgui() == cp::yesno_type::yes;
1915 }
1916}
1917
1919{
1921 {
1922 return false;
1923 }
1924 else
1925 {
1926 return mpParameters->Simulation()->OutputVisualizer()->parallel_vtk() == cp::yesno_type::yes;
1927 }
1928}
1929
1931{
1933 {
1934 return false;
1935 }
1936 else
1937 {
1938 return mpParameters->Simulation()->OutputVisualizer()->vtk() == cp::yesno_type::yes;
1939 }
1940}
1941
1943{
1945 {
1946 return 0u;
1947 }
1948 else
1949 {
1950 return mpParameters->Simulation()->OutputVisualizer()->precision();
1951 }
1952}
1953
1955{
1956 return mpParameters->Simulation()->Electrodes().present();
1957}
1958
1959/*
1960 * Set methods
1961 */
1962void HeartConfig::SetSpaceDimension(unsigned spaceDimension)
1963{
1964 mpParameters->Simulation()->SpaceDimension().set(spaceDimension);
1965}
1966
1967void HeartConfig::SetSimulationDuration(double simulationDuration)
1968{
1969 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, time, simulationDuration, "ms");
1970 mpParameters->Simulation()->SimulationDuration().set(time);
1971}
1972
1973void HeartConfig::SetDomain(const cp::domain_type& rDomain)
1974{
1975 mpParameters->Simulation()->Domain().set(rDomain);
1976}
1977
1978void HeartConfig::SetDefaultIonicModel(const cp::ionic_models_available_type& rIonicModel)
1979{
1980 cp::ionic_model_selection_type ionic_model;
1981 ionic_model.Hardcoded(rIonicModel);
1982 cp::ionic_models_type container(ionic_model);
1983 mpParameters->Simulation()->IonicModels().set(container);
1984}
1985
1986void HeartConfig::SetSlabDimensions(double x, double y, double z, double inter_node_space)
1987{
1988 if (!mpParameters->Simulation()->Mesh().present())
1989 {
1990 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
1991 mpParameters->Simulation()->Mesh().set(mesh_to_load);
1992 }
1993
1994 cp::slab_type slab_definition(x, y, z, inter_node_space);
1995 mpParameters->Simulation()->Mesh()->Slab().set(slab_definition);
1996}
1997
1998void HeartConfig::SetSheetDimensions(double x, double y, double inter_node_space)
1999{
2000 if (!mpParameters->Simulation()->Mesh().present())
2001 {
2002 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2003 mpParameters->Simulation()->Mesh().set(mesh_to_load);
2004 }
2005
2006 cp::sheet_type sheet_definition(x, y, inter_node_space);
2007 mpParameters->Simulation()->Mesh()->Sheet().set(sheet_definition);
2008}
2009
2010void HeartConfig::SetFibreLength(double x, double inter_node_space)
2011{
2012 if (!mpParameters->Simulation()->Mesh().present())
2013 {
2014 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2015 mpParameters->Simulation()->Mesh().set(mesh_to_load);
2016 }
2017
2018 cp::fibre_type fibre_definition(x, inter_node_space);
2019 mpParameters->Simulation()->Mesh()->Fibre().set(fibre_definition);
2020}
2021
2022void HeartConfig::SetMeshFileName(std::string meshPrefix, cp::media_type fibreDefinition)
2023{
2024 if (!mpParameters->Simulation()->Mesh().present())
2025 {
2026 XSD_CREATE_WITH_FIXED_ATTR(cp::mesh_type, mesh_to_load, "cm");
2027 mpParameters->Simulation()->Mesh().set(mesh_to_load);
2028 }
2029
2030 XSD_NESTED_TYPE(cp::mesh_type::LoadMesh)
2031 mesh_prefix(meshPrefix, fibreDefinition);
2032 mpParameters->Simulation()->Mesh()->LoadMesh().set(mesh_prefix);
2033}
2034
2035void HeartConfig::SetIonicModelRegions(std::vector<ChasteCuboid<3> >& rDefinedRegions,
2036 std::vector<cp::ionic_model_selection_type>& rIonicModels) const
2037{
2038 assert(rDefinedRegions.size() == rIonicModels.size());
2039 // You need to have defined a default model first...
2040 assert(mpParameters->Simulation()->IonicModels().present());
2041 XSD_SEQUENCE_TYPE(cp::ionic_models_type::Region)& regions = mpParameters->Simulation()->IonicModels()->Region();
2042 regions.clear();
2043 for (unsigned region_index = 0; region_index < rDefinedRegions.size(); region_index++)
2044 {
2045 cp::point_type point_a(rDefinedRegions[region_index].rGetLowerCorner()[0],
2046 rDefinedRegions[region_index].rGetLowerCorner()[1],
2047 rDefinedRegions[region_index].rGetLowerCorner()[2]);
2048
2049 cp::point_type point_b(rDefinedRegions[region_index].rGetUpperCorner()[0],
2050 rDefinedRegions[region_index].rGetUpperCorner()[1],
2051 rDefinedRegions[region_index].rGetUpperCorner()[2]);
2052
2053 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2054 locn.Cuboid().set(cp::box_type(point_a, point_b));
2055
2056 cp::ionic_model_region_type region(rIonicModels[region_index], locn);
2057 regions.push_back(region);
2058 }
2059}
2060
2062 std::vector<c_vector<double, 3> >& rIntraConductivities,
2063 std::vector<c_vector<double, 3> >& rExtraConductivities)
2064{
2065 assert(rConductivityAreas.size() == rIntraConductivities.size());
2066 assert(rIntraConductivities.size() == rExtraConductivities.size());
2067
2068 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity)
2069 heterogeneities_container;
2070
2071 for (unsigned region_index = 0; region_index < rConductivityAreas.size(); region_index++)
2072 {
2073 cp::point_type point_a(rConductivityAreas[region_index].rGetLowerCorner()[0],
2074 rConductivityAreas[region_index].rGetLowerCorner()[1],
2075 rConductivityAreas[region_index].rGetLowerCorner()[2]);
2076
2077 cp::point_type point_b(rConductivityAreas[region_index].rGetUpperCorner()[0],
2078 rConductivityAreas[region_index].rGetUpperCorner()[1],
2079 rConductivityAreas[region_index].rGetUpperCorner()[2]);
2080
2081 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2082 locn.Cuboid().set(cp::box_type(point_a, point_b));
2083 cp::conductivity_heterogeneity_type ht(locn);
2084
2085 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2086 rIntraConductivities[region_index][0],
2087 rIntraConductivities[region_index][1],
2088 rIntraConductivities[region_index][2],
2089 "mS/cm");
2090
2091 ht.IntracellularConductivities(intra);
2092
2093 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2094 rExtraConductivities[region_index][0],
2095 rExtraConductivities[region_index][1],
2096 rExtraConductivities[region_index][2],
2097 "mS/cm");
2098
2099 ht.ExtracellularConductivities(extra);
2100
2101 heterogeneities_container.push_back(ht);
2102 }
2103
2104 XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities)
2105 heterogeneities_object;
2106 heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container);
2107
2108 mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object);
2109}
2110
2112 std::vector<c_vector<double, 3> >& rIntraConductivities,
2113 std::vector<c_vector<double, 3> >& rExtraConductivities)
2114{
2115 assert(rConductivityAreas.size() == rIntraConductivities.size());
2116 assert(rIntraConductivities.size() == rExtraConductivities.size());
2117
2118 XSD_ANON_SEQUENCE_TYPE(cp::physiological_type, ConductivityHeterogeneities, ConductivityHeterogeneity)
2119 heterogeneities_container;
2120
2121 for (unsigned region_index = 0; region_index < rConductivityAreas.size(); region_index++)
2122 {
2123 cp::point_type centre(rConductivityAreas[region_index].rGetCentre()[0],
2124 rConductivityAreas[region_index].rGetCentre()[1],
2125 rConductivityAreas[region_index].rGetCentre()[2]);
2126
2127 cp::point_type radii(rConductivityAreas[region_index].rGetRadii()[0],
2128 rConductivityAreas[region_index].rGetRadii()[1],
2129 rConductivityAreas[region_index].rGetRadii()[2]);
2130
2131 XSD_CREATE_WITH_FIXED_ATTR(cp::location_type, locn, "cm");
2132 locn.Ellipsoid().set(cp::ellipsoid_type(centre, radii));
2133 cp::conductivity_heterogeneity_type ht(locn);
2134
2135 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2136 rIntraConductivities[region_index][0],
2137 rIntraConductivities[region_index][1],
2138 rIntraConductivities[region_index][2],
2139 "mS/cm");
2140
2141 ht.IntracellularConductivities(intra);
2142
2143 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2144 rExtraConductivities[region_index][0],
2145 rExtraConductivities[region_index][1],
2146 rExtraConductivities[region_index][2],
2147 "mS/cm");
2148
2149 ht.ExtracellularConductivities(extra);
2150
2151 heterogeneities_container.push_back(ht);
2152 }
2153
2154 XSD_ANON_TYPE(cp::physiological_type, ConductivityHeterogeneities)
2155 heterogeneities_object;
2156 heterogeneities_object.ConductivityHeterogeneity(heterogeneities_container);
2157
2158 mpParameters->Physiological().ConductivityHeterogeneities().set(heterogeneities_object);
2159}
2160
2161void HeartConfig::SetOutputDirectory(const std::string& rOutputDirectory)
2162{
2163 mpParameters->Simulation()->OutputDirectory().set(rOutputDirectory);
2164}
2165
2166void HeartConfig::SetOutputFilenamePrefix(const std::string& rOutputFilenamePrefix)
2167{
2168 mpParameters->Simulation()->OutputFilenamePrefix().set(rOutputFilenamePrefix);
2169}
2170
2171void HeartConfig::SetOutputVariables(const std::vector<std::string>& rOutputVariables)
2172{
2173 if (!mpParameters->Simulation()->OutputVariables().present())
2174 {
2175 cp::output_variables_type variables_requested;
2176 mpParameters->Simulation()->OutputVariables().set(variables_requested);
2177 }
2178
2179 XSD_SEQUENCE_TYPE(cp::output_variables_type::Var)& var_type_sequence = mpParameters->Simulation()->OutputVariables()->Var();
2180 // Erase or create a sequence
2181 var_type_sequence.clear();
2182
2183 for (unsigned i = 0; i < rOutputVariables.size(); i++)
2184 {
2185 cp::var_type temp(rOutputVariables[i]);
2186 var_type_sequence.push_back(temp);
2187 }
2188}
2189
2191{
2192 //What if it doesn't exist?
2193 mpParameters->Simulation()->OutputUsingOriginalNodeOrdering().set(useOriginal ? cp::yesno_type::yes : cp::yesno_type::no);
2194}
2195
2196void HeartConfig::SetCheckpointSimulation(bool saveSimulation, double checkpointTimestep, unsigned maxCheckpointsOnDisk)
2197{
2198 if (saveSimulation)
2199 {
2200 // Make sure values for the optional parameters have been provided
2201 assert(checkpointTimestep != -1.0 && maxCheckpointsOnDisk != UINT_MAX);
2202
2203 XSD_CREATE_WITH_FIXED_ATTR2(cp::simulation_type::XSD_NESTED_TYPE(CheckpointSimulation),
2204 cs,
2205 checkpointTimestep,
2206 maxCheckpointsOnDisk,
2207 "ms");
2208 mpParameters->Simulation()->CheckpointSimulation().set(cs);
2209 }
2210 else
2211 {
2212 mpParameters->Simulation()->CheckpointSimulation().reset();
2213 }
2214
2216}
2217
2218// Physiological
2219
2220void HeartConfig::SetIntracellularConductivities(const c_vector<double, 3>& rIntraConductivities)
2221{
2222 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2223 rIntraConductivities[0],
2224 rIntraConductivities[1],
2225 rIntraConductivities[2],
2226 "mS/cm");
2227
2228 mpParameters->Physiological().IntracellularConductivities().set(intra);
2229}
2230
2231void HeartConfig::SetIntracellularConductivities(const c_vector<double, 2>& rIntraConductivities)
2232{
2233 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2234 rIntraConductivities[0],
2235 rIntraConductivities[1],
2236 0.0, "mS/cm");
2237
2238 mpParameters->Physiological().IntracellularConductivities().set(intra);
2239}
2240
2241void HeartConfig::SetIntracellularConductivities(const c_vector<double, 1>& rIntraConductivities)
2242{
2243 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, intra,
2244 rIntraConductivities[0],
2245 0.0, 0.0, "mS/cm");
2246
2247 mpParameters->Physiological().IntracellularConductivities().set(intra);
2248}
2249
2250void HeartConfig::SetExtracellularConductivities(const c_vector<double, 3>& rExtraConductivities)
2251{
2252 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2253 rExtraConductivities[0],
2254 rExtraConductivities[1],
2255 rExtraConductivities[2],
2256 "mS/cm");
2257
2258 mpParameters->Physiological().ExtracellularConductivities().set(extra);
2259}
2260
2261void HeartConfig::SetExtracellularConductivities(const c_vector<double, 2>& rExtraConductivities)
2262{
2263 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2264 rExtraConductivities[0],
2265 rExtraConductivities[1],
2266 0.0, "mS/cm");
2267
2268 mpParameters->Physiological().ExtracellularConductivities().set(extra);
2269}
2270
2271void HeartConfig::SetExtracellularConductivities(const c_vector<double, 1>& rExtraConductivities)
2272{
2273 XSD_CREATE_WITH_FIXED_ATTR3(cp::conductivities_type, extra,
2274 rExtraConductivities[0],
2275 0.0, 0.0, "mS/cm");
2276
2277 mpParameters->Physiological().ExtracellularConductivities().set(extra);
2278}
2279
2280void HeartConfig::SetBathConductivity(double bathConductivity)
2281{
2282 XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, cond, bathConductivity, "mS/cm");
2283 mpParameters->Physiological().BathConductivity().set(cond);
2284}
2285
2286void HeartConfig::SetBathMultipleConductivities(std::map<unsigned, double> bathConductivities)
2287{
2289 mBathConductivities = bathConductivities;
2290}
2291
2292//void HeartConfig::SetTissueIdentifiers(const std::set<unsigned>& tissueIds)
2293//{
2294// std::set<unsigned> empty_bath_identifiers; //Too dangerous (see GetValidBathId)
2295// SetTissueAndBathIdentifiers(tissueIds, mBathIdentifiers);
2296//}
2297
2298void HeartConfig::SetTissueAndBathIdentifiers(const std::set<unsigned>& tissueIds, const std::set<unsigned>& bathIds)
2299{
2300 if (tissueIds.empty() || bathIds.empty())
2301 {
2302 EXCEPTION("Identifying set must be non-empty");
2303 }
2304 std::set<unsigned> shared_identifiers;
2305 std::set_intersection(tissueIds.begin(),
2306 tissueIds.end(),
2307 bathIds.begin(),
2308 bathIds.end(),
2309 std::inserter(shared_identifiers, shared_identifiers.begin()));
2310
2311 if (!shared_identifiers.empty())
2312 {
2313 EXCEPTION("Tissue identifiers and bath identifiers overlap");
2314 }
2315 mTissueIdentifiers = tissueIds;
2316 mBathIdentifiers = bathIds;
2317}
2318
2320{
2321 XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, ratio_object, ratio, "1/cm");
2322 mpParameters->Physiological().SurfaceAreaToVolumeRatio().set(ratio_object);
2323}
2324
2325void HeartConfig::SetCapacitance(double capacitance)
2326{
2327 XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, capacitance_object, capacitance, "uF/cm^2");
2328 mpParameters->Physiological().Capacitance().set(capacitance_object);
2329}
2330
2331// Numerical
2332void HeartConfig::SetOdePdeAndPrintingTimeSteps(double odeTimeStep, double pdeTimeStep, double printingTimeStep)
2333{
2334 XSD_CREATE_WITH_FIXED_ATTR3(cp::time_steps_type, time_steps,
2335 odeTimeStep, pdeTimeStep, printingTimeStep, "ms");
2336 mpParameters->Numerical().TimeSteps().set(time_steps);
2338}
2339
2340void HeartConfig::SetOdeTimeStep(double odeTimeStep)
2341{
2343}
2344
2345void HeartConfig::SetPdeTimeStep(double pdeTimeStep)
2346{
2348}
2349
2350void HeartConfig::SetPrintingTimeStep(double printingTimeStep)
2351{
2353}
2354
2356{
2357 if (GetOdeTimeStep() <= 0)
2358 {
2359 EXCEPTION("Ode time-step should be positive");
2360 }
2361 if (GetPdeTimeStep() <= 0)
2362 {
2363 EXCEPTION("Pde time-step should be positive");
2364 }
2365 if (GetPrintingTimeStep() <= 0.0)
2366 {
2367 EXCEPTION("Printing time-step should be positive");
2368 }
2369
2371 {
2372 EXCEPTION("Printing time-step should not be smaller than PDE time-step");
2373 }
2374
2375 if (!Divides(GetPdeTimeStep(), GetPrintingTimeStep()))
2376 {
2377 EXCEPTION("Printing time-step should be a multiple of PDE time step");
2378 }
2379
2381 {
2382 EXCEPTION("Ode time-step should not be greater than PDE time-step");
2383 }
2384
2386 {
2387 if (GetCheckpointTimestep() <= 0.0)
2388 {
2389 EXCEPTION("Checkpoint time-step should be positive");
2390 }
2391
2392 if (!Divides(GetPrintingTimeStep(), GetCheckpointTimestep()))
2393 {
2394 EXCEPTION("Checkpoint time-step should be a multiple of printing time-step");
2395 }
2396 }
2397}
2398
2399void HeartConfig::SetUseRelativeTolerance(double relativeTolerance)
2400{
2401 ENSURE_SECTION_PRESENT(mpParameters->Numerical().KSPTolerances(), cp::ksp_tolerances_type);
2402 //Remove any reference to tolerances is user parameters
2403 mpParameters->Numerical().KSPTolerances()->KSPAbsolute().reset();
2404 mpParameters->Numerical().KSPTolerances()->KSPRelative().set(relativeTolerance);
2405}
2406
2407void HeartConfig::SetUseAbsoluteTolerance(double absoluteTolerance)
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()->KSPRelative().reset();
2412 mpParameters->Numerical().KSPTolerances()->KSPAbsolute().set(absoluteTolerance);
2413}
2414
2415void HeartConfig::SetKSPSolver(const char* kspSolver, bool warnOfChange)
2416{
2417 if (warnOfChange && strcmp(GetKSPSolver(), kspSolver) != 0)
2418 {
2419 //Warn
2420 WARNING("Code has changed the KSP solver type from " << GetKSPSolver() << " to " << kspSolver);
2421 }
2422
2423 /* Note that changes in these conditions need to be reflected in the Doxygen*/
2424 if (strcmp(kspSolver, "gmres") == 0)
2425 {
2426 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::gmres);
2427 return;
2428 }
2429 if (strcmp(kspSolver, "cg") == 0)
2430 {
2431 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::cg);
2432 return;
2433 }
2434 if (strcmp(kspSolver, "symmlq") == 0)
2435 {
2436 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::symmlq);
2437 return;
2438 }
2439 if (strcmp(kspSolver, "chebychev") == 0)
2440 {
2441 mpParameters->Numerical().KSPSolver().set(cp::ksp_solver_type::chebychev);
2442 return;
2443 }
2444
2445 EXCEPTION("Unknown solver type provided");
2446}
2447
2448void HeartConfig::SetKSPPreconditioner(const char* kspPreconditioner)
2449{
2450 /* Note that changes in these conditions need to be reflected in the Doxygen*/
2451 if (strcmp(kspPreconditioner, "jacobi") == 0)
2452 {
2453 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::jacobi);
2454 return;
2455 }
2456 if (strcmp(kspPreconditioner, "bjacobi") == 0)
2457 {
2458 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::bjacobi);
2459 return;
2460 }
2461 if (strcmp(kspPreconditioner, "hypre") == 0)
2462 {
2463 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::hypre);
2464 return;
2465 }
2466 if (strcmp(kspPreconditioner, "ml") == 0)
2467 {
2468 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ml);
2469 return;
2470 }
2471 if (strcmp(kspPreconditioner, "spai") == 0)
2472 {
2473 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::spai);
2474 return;
2475 }
2476 if (strcmp(kspPreconditioner, "twolevelsblockdiagonal") == 0)
2477 {
2478 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::twolevelsblockdiagonal);
2479 return;
2480 }
2481 if (strcmp(kspPreconditioner, "blockdiagonal") == 0)
2482 {
2483 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::blockdiagonal);
2484 return;
2485 }
2486 if (strcmp(kspPreconditioner, "ldufactorisation") == 0)
2487 {
2488 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::ldufactorisation);
2489 return;
2490 }
2491 if (strcmp(kspPreconditioner, "none") == 0)
2492 {
2493 mpParameters->Numerical().KSPPreconditioner().set(cp::ksp_preconditioner_type::none);
2494 return;
2495 }
2496
2497 EXCEPTION("Unknown preconditioner type provided");
2498}
2499
2500void HeartConfig::SetMeshPartitioning(const char* meshPartioningMethod)
2501{
2502 /* Note that changes in these conditions need to be reflected in the Doxygen*/
2503 if (strcmp(meshPartioningMethod, "dumb") == 0)
2504 {
2505 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::dumb);
2506 return;
2507 }
2508 if (strcmp(meshPartioningMethod, "metis") == 0)
2509 {
2510 WARNING("METIS library partitioning is deprecated")
2511 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::metis);
2512 return;
2513 }
2514 if (strcmp(meshPartioningMethod, "parmetis") == 0)
2515 {
2516 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::parmetis);
2517 return;
2518 }
2519 if (strcmp(meshPartioningMethod, "petsc") == 0)
2520 {
2521 mpParameters->Numerical().MeshPartitioning().set(cp::mesh_partitioning_type::petsc);
2522 return;
2523 }
2524
2525 EXCEPTION("Unknown mesh partitioning method provided");
2526}
2527
2528void HeartConfig::SetApdMaps(const std::vector<std::pair<double, double> >& apdMaps)
2529{
2531 auto& apd_maps_sequence = mpParameters->PostProcessing()->ActionPotentialDurationMap();
2532 //Erase or create a sequence
2533 apd_maps_sequence.clear();
2534
2535 for (unsigned i = 0; i < apdMaps.size(); i++)
2536 {
2537 XSD_CREATE_WITH_FIXED_ATTR2(cp::apd_map_type, temp,
2538 apdMaps[i].first, apdMaps[i].second,
2539 "mV");
2540 apd_maps_sequence.push_back(temp);
2541 }
2542}
2543
2544void HeartConfig::SetUpstrokeTimeMaps(std::vector<double>& upstrokeTimeMaps)
2545{
2547 auto& var_type_sequence = mpParameters->PostProcessing()->UpstrokeTimeMap();
2548
2549 //Erase or create a sequence
2550 var_type_sequence.clear();
2551
2552 for (unsigned i = 0; i < upstrokeTimeMaps.size(); i++)
2553 {
2554 XSD_CREATE_WITH_FIXED_ATTR1(cp::upstrokes_map_type, temp,
2555 upstrokeTimeMaps[i],
2556 "mV");
2557 var_type_sequence.push_back(temp);
2558 }
2559}
2560
2561void HeartConfig::SetMaxUpstrokeVelocityMaps(std::vector<double>& maxUpstrokeVelocityMaps)
2562{
2564 auto& max_upstroke_velocity_maps_sequence = mpParameters->PostProcessing()->MaxUpstrokeVelocityMap();
2565
2566 //Erase or create a sequence
2567 max_upstroke_velocity_maps_sequence.clear();
2568
2569 for (unsigned i = 0; i < maxUpstrokeVelocityMaps.size(); i++)
2570 {
2571 XSD_CREATE_WITH_FIXED_ATTR1(cp::max_upstrokes_velocity_map_type, temp,
2572 maxUpstrokeVelocityMaps[i],
2573 "mV");
2574
2575 max_upstroke_velocity_maps_sequence.push_back(temp);
2576 }
2577}
2578
2579void HeartConfig::SetConductionVelocityMaps(std::vector<unsigned>& conductionVelocityMaps)
2580{
2582 auto& conduction_velocity_maps_sequence = mpParameters->PostProcessing()->ConductionVelocityMap();
2583
2584 //Erase or create a sequence
2585 conduction_velocity_maps_sequence.clear();
2586
2587 for (unsigned i = 0; i < conductionVelocityMaps.size(); i++)
2588 {
2589 cp::conduction_velocity_map_type temp(conductionVelocityMaps[i]);
2590 conduction_velocity_maps_sequence.push_back(temp);
2591 }
2592}
2593
2594void HeartConfig::SetRequestedNodalTimeTraces(std::vector<unsigned>& requestedNodes)
2595{
2597 auto& requested_nodes_sequence = mpParameters->PostProcessing()->TimeTraceAtNode();
2598
2599 //Erase or create a sequence
2600 requested_nodes_sequence.clear();
2601
2602 for (unsigned i = 0; i < requestedNodes.size(); i++)
2603 {
2604 cp::node_number_type temp(requestedNodes[i]);
2605 requested_nodes_sequence.push_back(temp);
2606 }
2607}
2608
2609template <unsigned SPACE_DIM>
2610void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<SPACE_DIM> >& rPseudoEcgElectrodePositions)
2611{
2613 auto& electrodes_sequence = mpParameters->PostProcessing()->PseudoEcgElectrodePosition();
2614
2615 //Erase or create a sequence
2616 electrodes_sequence.clear();
2617
2618 for (unsigned i = 0; i < rPseudoEcgElectrodePositions.size(); i++)
2619 {
2620 cp::point_type temp(rPseudoEcgElectrodePositions[i].GetWithDefault(0),
2621 rPseudoEcgElectrodePositions[i].GetWithDefault(1),
2622 rPseudoEcgElectrodePositions[i].GetWithDefault(2));
2623 electrodes_sequence.push_back(temp);
2624 }
2625}
2626
2627/*
2628 * Output visualizer
2629 */
2630
2632{
2633 ENSURE_SECTION_PRESENT(mpParameters->Simulation()->OutputVisualizer(), cp::output_visualizer_type);
2634}
2635
2637{
2639
2640 mpParameters->Simulation()->OutputVisualizer()->meshalyzer(
2641 useMeshalyzer ? cp::yesno_type::yes : cp::yesno_type::no);
2642}
2643
2645{
2647
2648 mpParameters->Simulation()->OutputVisualizer()->cmgui(
2649 useCmgui ? cp::yesno_type::yes : cp::yesno_type::no);
2650}
2651
2653{
2655
2656 mpParameters->Simulation()->OutputVisualizer()->vtk(
2657 useVtk ? cp::yesno_type::yes : cp::yesno_type::no);
2658}
2659
2661{
2663
2664 mpParameters->Simulation()->OutputVisualizer()->parallel_vtk(
2665 useParallelVtk ? cp::yesno_type::yes : cp::yesno_type::no);
2666}
2667
2669{
2671
2672 mpParameters->Simulation()->OutputVisualizer()->precision(numberOfDigits);
2673}
2674
2675void HeartConfig::SetElectrodeParameters(bool groundSecondElectrode,
2676 unsigned index, double magnitude,
2677 double startTime, double duration)
2678{
2679 assert(index < 3);
2680
2681 cp::axis_type axis = cp::axis_type::x;
2682 if (index == 1)
2683 {
2684 axis = cp::axis_type::y;
2685 }
2686 else if (index == 2)
2687 {
2688 axis = cp::axis_type::z;
2689 }
2690
2691 XSD_CREATE_WITH_FIXED_ATTR1(cp::surface_stimulus_strength_type, strength, magnitude, "uA/cm^2");
2692 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, start_time, startTime, "ms");
2693 XSD_CREATE_WITH_FIXED_ATTR1(cp::time_type, duration_time, duration, "ms");
2694
2695 if (!IsElectrodesPresent())
2696 {
2697 cp::electrodes_type element(groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no,
2698 axis,
2699 strength,
2700 start_time,
2701 duration_time);
2702 mpParameters->Simulation()->Electrodes().set(element);
2703 }
2704 else
2705 {
2706 mpParameters->Simulation()->Electrodes()->GroundSecondElectrode(groundSecondElectrode ? cp::yesno_type::yes : cp::yesno_type::no);
2707 mpParameters->Simulation()->Electrodes()->PerpendicularToAxis(axis);
2708 mpParameters->Simulation()->Electrodes()->Strength(strength);
2709 mpParameters->Simulation()->Electrodes()->StartTime(start_time);
2710 mpParameters->Simulation()->Electrodes()->Duration(duration_time);
2711 }
2712}
2713
2714void HeartConfig::GetElectrodeParameters(bool& rGroundSecondElectrode,
2715 unsigned& rIndex, double& rMagnitude,
2716 double& rStartTime, double& rDuration)
2717{
2718 if (!IsElectrodesPresent())
2719 {
2720 EXCEPTION("Attempted to get electrodes that have not been defined.");
2721 }
2722 else
2723 {
2724 rGroundSecondElectrode = (mpParameters->Simulation()->Electrodes()->GroundSecondElectrode() == cp::yesno_type::yes);
2725
2726 cp::axis_type axis = mpParameters->Simulation()->Electrodes()->PerpendicularToAxis();
2727 if (axis == cp::axis_type::x)
2728 {
2729 rIndex = 0;
2730 }
2731 else if (axis == cp::axis_type::y)
2732 {
2733 rIndex = 1;
2734 }
2735 else
2736 {
2737 rIndex = 2;
2738 }
2739
2740 rMagnitude = mpParameters->Simulation()->Electrodes()->Strength();
2741 rStartTime = mpParameters->Simulation()->Electrodes()->StartTime();
2742 rDuration = mpParameters->Simulation()->Electrodes()->Duration();
2743 }
2744}
2745
2747{
2748 // If it's an older version parameters & defaults (we're loading a checkpoint) say 'no'
2749 bool result = false;
2750 if (mpParameters->Numerical().UseStateVariableInterpolation().present())
2751 {
2752 result = mpParameters->Numerical().UseStateVariableInterpolation().get() == cp::yesno_type::yes;
2753 }
2754 return result;
2755}
2756
2757void HeartConfig::SetUseStateVariableInterpolation(bool useStateVariableInterpolation)
2758{
2759 if (useStateVariableInterpolation)
2760 {
2761 mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::yes);
2762 }
2763 else
2764 {
2765 mpParameters->Numerical().UseStateVariableInterpolation().set(cp::yesno_type::no);
2766 }
2767}
2768
2770{
2771 return mpParameters->Physiological().ApplyDrug().present();
2772}
2773
2775{
2776 CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug");
2777 return mpParameters->Physiological().ApplyDrug()->concentration();
2778}
2779
2780void HeartConfig::SetDrugDose(double drugDose)
2781{
2782 if (!mpParameters->Physiological().ApplyDrug().present())
2783 {
2784 cp::apply_drug_type drug(drugDose);
2785 mpParameters->Physiological().ApplyDrug().set(drug);
2786 }
2787 else
2788 {
2789 mpParameters->Physiological().ApplyDrug()->concentration(drugDose);
2790 }
2791}
2792
2793std::map<std::string, std::pair<double, double> > HeartConfig::GetIc50Values()
2794{
2795 CHECK_EXISTS(HasDrugDose(), "Physiological/ApplyDrug");
2796 std::map<std::string, std::pair<double, double> > ic50s;
2797
2798 XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)& ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50();
2799
2800 for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin();
2801 i != ic50_seq.end();
2802 ++i)
2803 {
2804 std::pair<double, double> ic50_hill(*i, i->hill());
2805 std::string current = i->current();
2806 ic50s[current] = ic50_hill;
2807 }
2808
2809 return ic50s;
2810}
2811
2812void HeartConfig::SetIc50Value(const std::string& rCurrentName, double ic50, double hill)
2813{
2814 if (!mpParameters->Physiological().ApplyDrug().present())
2815 {
2816 SetDrugDose(0.0);
2817 }
2818 XSD_SEQUENCE_TYPE(cp::apply_drug_type::IC50)& ic50_seq = mpParameters->Physiological().ApplyDrug()->IC50();
2819 if (ic50_seq.empty())
2820 {
2821 // Erase or create a sequence
2822 ic50_seq.clear();
2823 }
2824 bool entry_exists = false;
2825 cp::ic50_type ic50_elt(ic50, rCurrentName);
2826 ic50_elt.hill(hill);
2827 for (XSD_ITERATOR_TYPE(cp::apply_drug_type::IC50) i = ic50_seq.begin();
2828 i != ic50_seq.end();
2829 ++i)
2830 {
2831 if (i->current() == rCurrentName)
2832 {
2833 entry_exists = true;
2834 *i = ic50_elt;
2835 break;
2836 }
2837 }
2838 if (!entry_exists)
2839 {
2840 ic50_seq.push_back(ic50_elt);
2841 }
2842}
2843
2844void HeartConfig::SetUseMassLumping(bool useMassLumping)
2845{
2846 mUseMassLumping = useMassLumping;
2847}
2848
2850{
2851 return mUseMassLumping;
2852}
2853
2855{
2856 mUseMassLumpingForPrecond = useMassLumping;
2857}
2858
2863
2865{
2866 mUseReactionDiffusionOperatorSplitting = useOperatorSplitting;
2867}
2868
2873
2874void HeartConfig::SetUseFixedNumberIterationsLinearSolver(bool useFixedNumberIterations, unsigned evaluateNumItsEveryNSolves)
2875{
2876 mUseFixedNumberIterations = useFixedNumberIterations;
2877 mEvaluateNumItsEveryNSolves = evaluateNumItsEveryNSolves;
2878}
2879
2884
2889
2890//
2891// Purkinje methods
2892//
2893
2895{
2896 CheckSimulationIsDefined("Purkinje");
2897 return mpParameters->Simulation()->Purkinje().present();
2898}
2899
2901{
2902 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2903 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Capacitance().present(),
2904 "Physiological/Purkinje/Capacitance");
2905 return mpParameters->Physiological().Purkinje()->Capacitance().get();
2906}
2907
2909{
2910 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2911 XSD_CREATE_WITH_FIXED_ATTR1(cp::capacitance_type, purk_Cm, capacitance, "uF/cm^2");
2912 mpParameters->Physiological().Purkinje()->Capacitance().set(purk_Cm);
2913}
2914
2916{
2917 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2918 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().present(),
2919 "Physiological/Purkinje/SurfaceAreaToVolumeRatio");
2920 return mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().get();
2921}
2922
2924{
2925 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2926 XSD_CREATE_WITH_FIXED_ATTR1(cp::inverse_length_type, purk_Am, ratio, "1/cm");
2927 mpParameters->Physiological().Purkinje()->SurfaceAreaToVolumeRatio().set(purk_Am);
2928}
2929
2931{
2932 CHECK_EXISTS(mpParameters->Physiological().Purkinje().present(), "Physiological/Purkinje");
2933 CHECK_EXISTS(mpParameters->Physiological().Purkinje()->Conductivity().present(),
2934 "Physiological/Purkinje/Conductivity");
2935 return mpParameters->Physiological().Purkinje()->Conductivity().get();
2936}
2937
2939{
2940 ENSURE_SECTION_PRESENT(mpParameters->Physiological().Purkinje(), cp::purkinje_physiological_type);
2941 XSD_CREATE_WITH_FIXED_ATTR1(cp::conductivity_type, purkinje_conductivity, conductivity, "mS/cm");
2942 mpParameters->Physiological().Purkinje()->Conductivity().set(purkinje_conductivity);
2943}
2944
2945/**********************************************************************
2946 * *
2947 * *
2948 * Utility methods for reading/transforming XML *
2949 * *
2950 * *
2951 **********************************************************************/
2952
2953void XmlTransforms::TransformArchiveDirectory(xercesc::DOMDocument* pDocument,
2954 xercesc::DOMElement* pRootElement)
2955{
2956 using namespace xercesc;
2957 std::vector<xercesc::DOMElement*> elts = XmlTools::FindElements(
2958 pRootElement,
2959 "ResumeSimulation/ArchiveDirectory");
2960 if (elts.size() > 0)
2961 {
2962 // We have an ArchiveDirectory element, so add the relative_to='chaste_test_output' attribute
2963 DOMElement* p_dir_elt = elts[0];
2964 p_dir_elt->setAttribute(X("relative_to"), X("chaste_test_output"));
2965 }
2966}
2967
2968void XmlTransforms::TransformIonicModelDefinitions(xercesc::DOMDocument* pDocument,
2969 xercesc::DOMElement* pRootElement)
2970{
2971 // Default ionic model
2972 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
2973 pRootElement,
2974 "Simulation/IonicModels/Default");
2975 if (p_elt_list.size() > 0)
2976 {
2977 assert(p_elt_list.size() == 1); // Asserted by schema
2978 XmlTools::WrapContentInElement(pDocument, p_elt_list[0], X("Hardcoded"));
2979 // Now do any region-specific definitions
2980 p_elt_list = XmlTools::FindElements(pRootElement, "Simulation/IonicModels/Region/IonicModel");
2981 for (unsigned i = 0; i < p_elt_list.size(); i++)
2982 {
2983 XmlTools::WrapContentInElement(pDocument, p_elt_list[i], X("Hardcoded"));
2984 }
2985 }
2986}
2987
2988void XmlTransforms::CheckForIluPreconditioner(xercesc::DOMDocument* pDocument,
2989 xercesc::DOMElement* pRootElement)
2990{
2991 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
2992 pRootElement,
2993 "Numerical/KSPPreconditioner");
2994 if (p_elt_list.size() > 0)
2995 {
2996 assert(p_elt_list.size() == 1); // Asserted by schema
2997 std::string text_value = X2C(p_elt_list[0]->getTextContent());
2998 if (text_value == "ilu")
2999 {
3000 EXCEPTION("PETSc does not have a parallel implementation of ilu, so we no longer allow it as an option. Use bjacobi instead.");
3001 }
3002 }
3003}
3004
3005void XmlTransforms::MoveConductivityHeterogeneities(xercesc::DOMDocument* pDocument,
3006 xercesc::DOMElement* pRootElement)
3007{
3008 std::vector<xercesc::DOMElement*> p_elt_list = XmlTools::FindElements(
3009 pRootElement,
3010 "Simulation/ConductivityHeterogeneities");
3011 if (p_elt_list.size() > 0)
3012 {
3013 assert(p_elt_list.size() == 1); // Asserted by schema
3014 xercesc::DOMNode* p_parent = p_elt_list[0]->getParentNode();
3015 xercesc::DOMNode* p_child = p_parent->removeChild(p_elt_list[0]);
3016 std::vector<xercesc::DOMElement*> p_phys_list = XmlTools::FindElements(pRootElement, "Physiological");
3017 assert(p_phys_list.size() == 1); // Asserted by schema
3018 p_phys_list[0]->appendChild(p_child);
3019 }
3020}
3021
3022void XmlTransforms::SetDefaultVisualizer(xercesc::DOMDocument* pDocument,
3023 xercesc::DOMElement* pRootElement)
3024{
3025 std::vector<xercesc::DOMElement*> p_sim_list = XmlTools::FindElements(pRootElement, "Simulation");
3026 if (p_sim_list.size() > 0)
3027 {
3028 std::vector<xercesc::DOMElement*> p_viz_list = XmlTools::FindElements(p_sim_list[0], "OutputVisualizer");
3029 if (p_viz_list.empty())
3030 {
3031 // Create the element and set meshalyzer (only) to on
3032 xercesc::DOMElement* p_viz_elt = pDocument->createElementNS(X("https://chaste.comlab.ox.ac.uk/nss/parameters/3_3"), X("OutputVisualizer"));
3033 p_sim_list[0]->appendChild(p_viz_elt);
3034 p_viz_elt->setAttribute(X("meshalyzer"), X("yes"));
3035 }
3036 }
3037}
3038
3040// Explicit instantiation of the templated functions
3042// LCOV_EXCL_START //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously
3047template void HeartConfig::GetIonicModelRegions<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >&, std::vector<cp::ionic_model_selection_type>&) const;
3048template void HeartConfig::GetStimuli<3u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >&, std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >&) const;
3049template 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> >*);
3050template void HeartConfig::GetConductivityHeterogeneities<3u>(std::vector<boost::shared_ptr<AbstractChasteRegion<3u> > >&, std::vector<c_vector<double, 3> >&, std::vector<c_vector<double, 3> >&) const;
3051
3052template void HeartConfig::GetIonicModelRegions<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >&, std::vector<cp::ionic_model_selection_type>&) const;
3053template void HeartConfig::GetStimuli<2u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >&, std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >&) const;
3054template 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> >*);
3055template void HeartConfig::GetConductivityHeterogeneities<2u>(std::vector<boost::shared_ptr<AbstractChasteRegion<2u> > >&, std::vector<c_vector<double, 3> >&, std::vector<c_vector<double, 3> >&) const;
3056
3057template void HeartConfig::GetIonicModelRegions<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >&, std::vector<cp::ionic_model_selection_type>&) const;
3058template void HeartConfig::GetStimuli<1u>(std::vector<boost::shared_ptr<AbstractStimulusFunction> >&, std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >&) const;
3059template 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> >*);
3060template void HeartConfig::GetConductivityHeterogeneities<1u>(std::vector<boost::shared_ptr<AbstractChasteRegion<1u> > >&, std::vector<c_vector<double, 3> >&, std::vector<c_vector<double, 3> >&) const;
3061
3062template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions) const;
3063template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions) const;
3064template void HeartConfig::GetPseudoEcgElectrodePositions(std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions) const;
3065
3066template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<1u> >& rPseudoEcgElectrodePositions);
3067template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<2u> >& rPseudoEcgElectrodePositions);
3068template void HeartConfig::SetPseudoEcgElectrodePositions(const std::vector<ChastePoint<3u> >& rPseudoEcgElectrodePositions);
3073// LCOV_EXCL_STOP //These methods are covered above with DIM=1,2,3 but the instantiations may fail spuriously
3074
3075// 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)