Chaste Commit::ca8ccdedf819b6e02855bc0e8e6f50bdecbc5208
Hdf5ToCmguiConverter.cpp
1/*
2
3Copyright (c) 2005-2024, 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
36#include "Hdf5ToCmguiConverter.hpp"
37#include "CmguiMeshWriter.hpp"
39#include "HeartConfig.hpp"
40#include "PetscTools.hpp"
41#include "Exception.hpp"
42#include "ReplicatableVector.hpp"
43#include "DistributedVector.hpp"
44#include "DistributedVectorFactory.hpp"
45#include "Version.hpp"
46#include "GenericMeshReader.hpp"
47
48template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
50{
51 out_stream p_file = out_stream(NULL);
52
53 unsigned num_nodes = this->mpReader->GetNumberOfRows();
54 unsigned num_timesteps = this->mpReader->GetUnlimitedDimensionValues().size();
55
56 DistributedVectorFactory factory(num_nodes);
57
58 Vec data = factory.CreateVec();//for V
59 Vec data_phie = factory.CreateVec();//for phi_e
60 Vec data_second_cell = factory.CreateVec();//for the V of the second cell, used in extended bidomain problems.
61
62 for (unsigned time_step=0; time_step<num_timesteps; time_step++)
63 {
64 // Create the file for this time step
65 std::stringstream time_step_string;
66
67 // unsigned to string
68 time_step_string << time_step;
70 {
71 p_file = this->mpOutputFileHandler->OpenOutputFile(this->mFileBaseName + "_" + time_step_string.str() + ".exnode");
72
73 // Check how many digits are to be output in the solution (0 goes to default value of digits)
74 if (this->mPrecision != 0)
75 {
76 p_file->precision(this->mPrecision);
77 }
78 }
79
80 std::vector<ReplicatableVector*> all_data;
81 unsigned num_vars = this->mpReader->GetVariableNames().size();
82 for (unsigned var=0; var<num_vars; var++)
83 {
84 // Read the data for this time step
85 this->mpReader->GetVariableOverNodes(data, this->mpReader->GetVariableNames()[var], time_step);
86 ReplicatableVector* p_repl_data = new ReplicatableVector(data);
87 assert(p_repl_data->GetSize()==num_nodes);
88 all_data.push_back(p_repl_data);
89 }
90
92 {
93 // Write provenance info
94 std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
95 *p_file << comment;
96 // The header first
97 *p_file << "Group name: " << this->mFileBaseName << "\n";
98 *p_file << "#Fields=" << num_vars << "\n";
99 for (unsigned var=0; var<num_vars; var++)
100 {
101 *p_file << " " << var+1 << ") " <<this->mpReader->GetVariableNames()[var]<< " , field, rectangular cartesian, #Components=1" << "\n" << "x. Value index=1, #Derivatives=0, #Versions=1"<<"\n";
102 if (var != num_vars-1)
103 {
104 *p_file << "\n";
105 }
106 }
107
108 // Write the data
109 for (unsigned i=0; i<num_nodes; i++)
110 {
111 // cmgui counts nodes from 1
112 *p_file << "Node: "<< i+1 << "\n";
113 for (unsigned var=0; var<num_vars; var++)
114 {
115 *p_file << (*(all_data[var]))[i] << "\n";
116 }
117 }
118 }
119
120 for (unsigned var=0; var<num_vars; var++)
121 {
122 delete all_data[var];
123 }
124 }
126 PetscTools::Destroy(data_phie);
127 PetscTools::Destroy(data_second_cell);
128
130 {
131 p_file->close();
132 }
133}
134
135template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
137 const std::string& rFileBaseName,
139 bool hasBath,
140 unsigned precision)
141 : AbstractHdf5Converter<ELEMENT_DIM,SPACE_DIM>(rInputDirectory, rFileBaseName, pMesh, "cmgui_output", precision)
142{
144 while (this->mDatasetNames[this->mOpenDatasetIndex] != "Data")
145 {
146 bool next_open = this->MoveOntoNextDataset();
147 UNUSED_OPT(next_open);
148 assert(next_open);
149 }
150
151 // Write the node data out
152 Write("");
153
154 // Write mesh in a suitable form for cmgui
155 std::string output_directory = HeartConfig::Instance()->GetOutputDirectory() + "/cmgui_output";
156
157 CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM> cmgui_mesh_writer(output_directory, HeartConfig::Instance()->GetOutputFilenamePrefix(), false);
158
159 // Used to inform the mesh of the data names
160 std::vector<std::string> field_names = this->mpReader->GetVariableNames();
161 cmgui_mesh_writer.SetAdditionalFieldNames(field_names);
162 if (hasBath)
163 {
164 std::vector<std::string> names;
165 names.push_back("tissue");
166 names.push_back("bath");
167 cmgui_mesh_writer.SetRegionNames(names);
168 }
169
170 // Normally the in-memory mesh is converted:
171 if (HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() == false || !this->mpMesh->IsMeshOnDisk())
172 {
173 cmgui_mesh_writer.WriteFilesUsingMesh(*(this->mpMesh), false);
174 }
175 else
176 {
177 // In this case we expect the mesh to have been read in from file
179 // Note that the next line will throw if the mesh has not been read from file
180 std::string original_file=this->mpMesh->GetMeshFileBaseName();
181 std::shared_ptr<AbstractMeshReader<ELEMENT_DIM, SPACE_DIM> > p_original_mesh_reader
182 = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(original_file);
183 cmgui_mesh_writer.WriteFilesUsingMeshReader(*p_original_mesh_reader);
184 }
185
187 PetscTools::Barrier("Hdf5ToCmguiConverter");
188}
189
190template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
192{
193 unsigned num_timesteps = this->mpReader->GetUnlimitedDimensionValues().size();
194 assert(this->mpReader->GetVariableNames().size() > 0); // seg fault guard
195 std::string variable_name = this->mpReader->GetVariableNames()[0];
196
198 {
199 out_stream p_script_file = this->mpOutputFileHandler->OpenOutputFile("LoadSolutions.com");
200
201 // Write provenance info, note the # instead of ! because this is - essentially - a PERL script that Cmgui interprets
202 std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
203 *p_script_file << comment;
204
205 *p_script_file << "# Read the mesh \n"
206 << "gfx read node "<<HeartConfig::Instance()->GetOutputFilenamePrefix()<<".exnode \n"
207 << "gfx read elem "<<HeartConfig::Instance()->GetOutputFilenamePrefix()<<".exelem \n" // note the mesh file name is taken from HeartConfig...
208 << "gfx define faces egroup "<<HeartConfig::Instance()->GetOutputFilenamePrefix()<<"\n"
209 << "# Create a window \n"
210 << "gfx cre win 1 \n"
211 << "# Modify the scene (obtained by gfx list g_element XXXX commands) to visualize first var on lines and nodes \n"
212 << "gfx modify g_element "<< HeartConfig::Instance()->GetOutputFilenamePrefix()<<" general clear circle_discretization 6 default_coordinate coordinates element_discretization \"4*4*4\" native_discretization none; \n"
213 << "gfx modify g_element "<< HeartConfig::Instance()->GetOutputFilenamePrefix()<<" lines select_on material default data "<<variable_name<<" spectrum default selected_material default_selected; \n"
214 << "gfx modify g_element "<< HeartConfig::Instance()->GetOutputFilenamePrefix()<<" node_points glyph point general size \"1*1*1\" centre 0,0,0 font default select_on material default data "<<variable_name<<" spectrum default selected_material default_selected; \n"
215 << "# Load the data \n"
216 << "for ($i=0; $i<" << num_timesteps << "; $i++) { \n"
217 << " gfx read node " << this->mFileBaseName << "_$i.exnode time $i\n" // ...while the data file from mFileBaseName...
218 << "}\n";
219 p_script_file->close();
220 }
221}
222
223// Explicit instantiation
224template class Hdf5ToCmguiConverter<1,1>;
225template class Hdf5ToCmguiConverter<1,2>;
226template class Hdf5ToCmguiConverter<2,2>;
227template class Hdf5ToCmguiConverter<1,3>;
228template class Hdf5ToCmguiConverter<2,3>;
229template class Hdf5ToCmguiConverter<3,3>;
#define UNUSED_OPT(var)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpMesh
std::vector< std::string > mDatasetNames
boost::shared_ptr< Hdf5DataReader > mpReader
void WriteFilesUsingMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)
virtual void WriteFilesUsingMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, bool keepOriginalElementIndexing=true)
static std::string GetProvenanceString()
void SetAdditionalFieldNames(std::vector< std::string > &rFieldNames)
void SetRegionNames(std::vector< std::string > &rRegionNames)
Hdf5ToCmguiConverter(const FileFinder &rInputDirectory, const std::string &rFileBaseName, AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > *pMesh, bool hasBath=false, unsigned precision=0u)
void Write(std::string type)
std::string GetOutputFilenamePrefix() const
std::string GetOutputDirectory() const
static HeartConfig * Instance()
static void Destroy(Vec &rVec)
static bool AmMaster()
static void Barrier(const std::string callerId="")