PostProcessingWriter.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "UblasCustomFunctions.hpp"
00030 #include "HeartConfig.hpp"
00031 #include "PostProcessingWriter.hpp"
00032 #include "PetscTools.hpp"
00033 #include "OutputFileHandler.hpp"
00034 #include "DistanceMapCalculator.hpp"
00035 #include "PseudoEcgCalculator.hpp"
00036 #include "Version.hpp"
00037 #include "HeartEventHandler.hpp"
00038 
00039 #include <iostream>
00040 
00041 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00042 PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::PostProcessingWriter(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>& rMesh,
00043                                                                    std::string directory,
00044                                                                    std::string hdf5File,
00045                                                                    bool makeAbsolute,
00046                                                                    std::string voltageName)
00047         : mDirectory(directory),
00048           mHdf5File(hdf5File),
00049           mMakeAbsolute(makeAbsolute),
00050           mVoltageName(voltageName),
00051           mrMesh(rMesh)
00052 {
00053     mLo = mrMesh.GetDistributedVectorFactory()->GetLow();
00054     mHi = mrMesh.GetDistributedVectorFactory()->GetHigh();
00055     mpDataReader = new Hdf5DataReader(directory, hdf5File, makeAbsolute);
00056     mpCalculator = new PropagationPropertiesCalculator(mpDataReader,voltageName);
00057     //check that the hdf file was generated by simulations from the same mesh
00058     assert(mpDataReader->GetNumberOfRows() == mrMesh.GetNumNodes());
00059 }
00060 
00061 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00062 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WritePostProcessingFiles()
00063 {
00064 // Please note that only the master processor should write to file.
00065 // Each of the private methods called here takes care of checking.
00066 
00067     if (HeartConfig::Instance()->IsApdMapsRequested())
00068     {
00069         std::vector<std::pair<double,double> > apd_maps;
00070         HeartConfig::Instance()->GetApdMaps(apd_maps);
00071         for (unsigned i=0; i<apd_maps.size(); i++)
00072         {
00073             WriteApdMapFile(apd_maps[i].first, apd_maps[i].second);
00074         }
00075     }
00076 
00077     if (HeartConfig::Instance()->IsUpstrokeTimeMapsRequested())
00078     {
00079         std::vector<double> upstroke_time_maps;
00080         HeartConfig::Instance()->GetUpstrokeTimeMaps(upstroke_time_maps);
00081         for (unsigned i=0; i<upstroke_time_maps.size(); i++)
00082         {
00083             WriteUpstrokeTimeMap(upstroke_time_maps[i]);
00084         }
00085     }
00086 
00087     if (HeartConfig::Instance()->IsMaxUpstrokeVelocityMapRequested())
00088     {
00089         std::vector<double> upstroke_velocity_maps;
00090         HeartConfig::Instance()->GetMaxUpstrokeVelocityMaps(upstroke_velocity_maps);
00091         for (unsigned i=0; i<upstroke_velocity_maps.size(); i++)
00092         {
00093             WriteMaxUpstrokeVelocityMap(upstroke_velocity_maps[i]);
00094         }
00095     }
00096 
00097     if (HeartConfig::Instance()->IsConductionVelocityMapsRequested())
00098     {
00099         std::vector<unsigned> conduction_velocity_maps;
00100         HeartConfig::Instance()->GetConductionVelocityMaps(conduction_velocity_maps);
00101 
00102         //get the mesh here
00103         DistanceMapCalculator<ELEMENT_DIM, SPACE_DIM> dist_map_calculator(mrMesh);
00104 
00105         for (unsigned i=0; i<conduction_velocity_maps.size(); i++)
00106         {
00107             std::vector<double> distance_map;
00108             std::vector<unsigned> origin_surface;
00109             origin_surface.push_back(conduction_velocity_maps[i]);
00110             dist_map_calculator.ComputeDistanceMap(origin_surface, distance_map);
00111             WriteConductionVelocityMap(conduction_velocity_maps[i], distance_map);
00112         }
00113     }
00114 
00115     if (HeartConfig::Instance()->IsAnyNodalTimeTraceRequested())
00116     {
00117         std::vector<unsigned> requested_nodes;
00118         HeartConfig::Instance()->GetNodalTimeTraceRequested(requested_nodes);
00119         WriteVariablesOverTimeAtNodes(requested_nodes);
00120     }
00121 
00122     if (HeartConfig::Instance()->IsPseudoEcgCalculationRequested())
00123     {
00124         std::vector<ChastePoint<SPACE_DIM> > electrodes;
00125         HeartConfig::Instance()->GetPseudoEcgElectrodePositions(electrodes);
00126 
00127         for (unsigned i=0; i<electrodes.size(); i++)
00128         {
00129             PseudoEcgCalculator<ELEMENT_DIM,SPACE_DIM,1> calculator(mrMesh, electrodes[i], mDirectory, mHdf5File, mVoltageName, mMakeAbsolute);
00130             calculator.WritePseudoEcg();
00131         }
00132     }
00133 }
00134 
00135 
00136 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00137 PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::~PostProcessingWriter()
00138 {
00139     delete mpDataReader;
00140     delete mpCalculator;
00141 }
00142 
00143 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00144 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteApdMapFile(double repolarisationPercentage, double threshold)
00145 {
00146     std::vector<std::vector<double> > output_data = mpCalculator->CalculateAllActionPotentialDurationsForNodeRange(repolarisationPercentage, mLo, mHi, threshold);
00147     std::stringstream filename_stream;
00148     filename_stream << "Apd_" << repolarisationPercentage << "_" << threshold << "_Map.dat";
00149     WriteGenericFile(output_data, filename_stream.str());
00150 }
00151 
00152 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00153 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteUpstrokeTimeMap(double threshold)
00154 {
00155     std::vector<std::vector<double> > output_data;
00156     //Fill in data
00157     for (unsigned node_index = mLo; node_index < mHi; node_index++)
00158     {
00159         std::vector<double> upstroke_times;
00160         try
00161         {
00162             upstroke_times = mpCalculator->CalculateUpstrokeTimes(node_index, threshold);
00163             assert(upstroke_times.size() != 0);
00164         }
00165         catch(Exception& e)
00166         {
00167             upstroke_times.push_back(0);
00168             assert(upstroke_times.size() == 1);
00169         }
00170         output_data.push_back(upstroke_times);
00171     }
00172     std::stringstream filename_stream;
00173     filename_stream << "UpstrokeTimeMap_" << threshold << ".dat";
00174     WriteGenericFile(output_data, filename_stream.str());
00175 }
00176 
00177 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00178 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteMaxUpstrokeVelocityMap(double threshold)
00179 {
00180     std::vector<std::vector<double> > output_data;
00181     //Fill in data
00182     for (unsigned node_index = mLo; node_index < mHi; node_index++)
00183     {
00184         std::vector<double> upstroke_velocities;
00185         try
00186         {
00187             upstroke_velocities = mpCalculator->CalculateAllMaximumUpstrokeVelocities(node_index, threshold);
00188             assert(upstroke_velocities.size() != 0);
00189         }
00190         catch(Exception& e)
00191         {
00192             upstroke_velocities.push_back(0);
00193             assert(upstroke_velocities.size() ==1);
00194         }
00195         output_data.push_back(upstroke_velocities);
00196     }
00197     std::stringstream filename_stream;
00198     filename_stream << "MaxUpstrokeVelocityMap_" << threshold << ".dat";
00199     WriteGenericFile(output_data, filename_stream.str());
00200 }
00201 
00202 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00203 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteConductionVelocityMap(unsigned originNode, std::vector<double> distancesFromOriginNode)
00204 {
00205     //Fill in data
00206     std::vector<std::vector<double> > output_data;
00207     for (unsigned dest_node = mLo; dest_node < mHi; dest_node++)
00208     {
00209         std::vector<double> conduction_velocities;
00210         try
00211         {
00212             conduction_velocities = mpCalculator->CalculateAllConductionVelocities(originNode, dest_node, distancesFromOriginNode[dest_node]);
00213             assert(conduction_velocities.size() != 0);
00214         }
00215         catch(Exception& e)
00216         {
00217             conduction_velocities.push_back(0);
00218             assert(conduction_velocities.size() == 1);
00219         }
00220         output_data.push_back(conduction_velocities);
00221     }
00222     std::stringstream filename_stream;
00223     filename_stream << "ConductionVelocityFromNode" << originNode << ".dat";
00224     WriteGenericFile(output_data, filename_stream.str());
00225 }
00226 
00227 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00228 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteAboveThresholdDepolarisationFile(double threshold )
00229 {
00230     std::vector<std::vector<double> > output_data;
00231 
00232     //Fill in data
00233     for (unsigned node_index = mLo; node_index < mHi; node_index++)
00234     {
00235         std::vector<double> upstroke_velocities;
00236         std::vector<unsigned> above_threshold_depolarisations;
00237         std::vector<double> output_item;
00238         bool no_upstroke_occurred = false;
00239 
00240         try
00241         {
00242             upstroke_velocities = mpCalculator->CalculateAllMaximumUpstrokeVelocities(node_index, threshold);
00243             assert(upstroke_velocities.size() != 0);
00244         }
00245         catch(Exception& e)
00246         {
00247             upstroke_velocities.push_back(0);
00248             assert(upstroke_velocities.size() ==1);
00249             no_upstroke_occurred = true;
00250         }
00251         //this method won't throw any exception, so there is no need to put it into the try/catch
00252         above_threshold_depolarisations =  mpCalculator->CalculateAllAboveThresholdDepolarisations(node_index, threshold);
00253 
00254         //count the total above threshold depolarisations
00255         unsigned total_number_of_above_threshold_depolarisations = 0;
00256         for (unsigned ead_index = 0; ead_index< above_threshold_depolarisations.size();ead_index++)
00257         {
00258             total_number_of_above_threshold_depolarisations = total_number_of_above_threshold_depolarisations + above_threshold_depolarisations[ead_index];
00259         }
00260 
00261         //for this item, puch back the number of upstrokes...
00262         if (no_upstroke_occurred)
00263         {
00264             output_item.push_back(0);
00265         }
00266         else
00267         {
00268             output_item.push_back(upstroke_velocities.size());
00269         }
00270         //... and the number of above thrshold depolarisations
00271         output_item.push_back((double) total_number_of_above_threshold_depolarisations);
00272 
00273         output_data.push_back(output_item);
00274     }
00275     std::stringstream filename_stream;
00276     filename_stream << "AboveThresholdDepolarisations" << threshold << ".dat";
00277     WriteGenericFile(output_data, filename_stream.str());
00278 }
00279 
00280 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00281 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteVariablesOverTimeAtNodes(std::vector<unsigned>& rNodeIndices)
00282 {
00283     std::vector<std::string> variable_names = mpDataReader->GetVariableNames();
00284 
00285     //we will write one file per variable in the hdf5 file
00286     for (unsigned name_index=0; name_index < variable_names.size(); name_index++)
00287     {
00288         std::vector<std::vector<double> > output_data;
00289         if (PetscTools::AmMaster())//only master process fills the data structure
00290         {
00291             //allocate memory: NXM matrix where N = numbe rof time stpes and M number of requested nodes
00292             output_data.resize( mpDataReader->GetUnlimitedDimensionValues().size() );
00293             for (unsigned j = 0; j < mpDataReader->GetUnlimitedDimensionValues().size(); j++)
00294             {
00295                 output_data[j].resize(rNodeIndices.size());
00296             }
00297 
00298             for (unsigned requested_index = 0; requested_index < rNodeIndices.size(); requested_index++)
00299             {
00300                 unsigned node_index = rNodeIndices[requested_index];
00301 
00302                 //handle permutation, if any
00303                 if ( (mrMesh.rGetNodePermutation().size() != 0) &&
00304                       !HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() )
00305                 {
00306                     node_index = mrMesh.rGetNodePermutation()[ rNodeIndices[requested_index] ];
00307                 }
00308 
00309                 //grab the data from the hdf5 file.
00310                 std::vector<double> time_series =  mpDataReader->GetVariableOverTime(variable_names[name_index], node_index);
00311                 assert ( time_series.size() == mpDataReader->GetUnlimitedDimensionValues().size());
00312 
00313                 //fill the output_data data structure
00314                 for (unsigned time_step = 0; time_step < time_series.size(); time_step++)
00315                 {
00316                     output_data[time_step][requested_index] = time_series[time_step];
00317                 }
00318             }
00319         }
00320         std::stringstream filename_stream;
00321         filename_stream << "NodalTraces_" << variable_names[name_index] << ".dat";
00322         WriteGenericFile(output_data, filename_stream.str());
00323     }
00324 }
00325 
00326 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00327 void PostProcessingWriter<ELEMENT_DIM, SPACE_DIM>::WriteGenericFile(std::vector<std::vector<double> >& rDataPayload, std::string fileName)
00328 {
00329     OutputFileHandler output_file_handler(HeartConfig::Instance()->GetOutputDirectory() + "/output", false);
00330     for (unsigned writing_process=0; writing_process<PetscTools::GetNumProcs(); writing_process++)
00331     {
00332         if(PetscTools::GetMyRank() == writing_process)
00333         {
00334             out_stream p_file=out_stream(NULL);
00335             if (PetscTools::AmMaster())
00336             {
00337                 //Open the file for the first time
00338                 p_file = output_file_handler.OpenOutputFile(fileName);
00339                 //write provenance info
00340                 std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
00341                 *p_file << comment;
00342             }
00343             else
00344             {
00345                 //Append to the existing file
00346                 p_file = output_file_handler.OpenOutputFile(fileName, std::ios::app);
00347             }
00348             for (unsigned line_number=0; line_number<rDataPayload.size(); line_number++)
00349             {
00350                 for (unsigned i = 0; i < rDataPayload[line_number].size(); i++)
00351                 {
00352                     *p_file << rDataPayload[line_number][i] << "\t";
00353                 }
00354                 *p_file << std::endl;
00355             }
00356             p_file->close();
00357         }
00358         //Process i+1 waits for process i to close the file
00359         PetscTools::Barrier();
00360     }//Loop in writing_process
00361 }
00362 
00364 // Explicit instantiation
00366 
00367 template class PostProcessingWriter<1,1>;
00368 template class PostProcessingWriter<1,2>;
00369 template class PostProcessingWriter<2,2>;
00370 template class PostProcessingWriter<1,3>;
00371 //template class PostProcessingWriter<2,3>;
00372 template class PostProcessingWriter<3,3>;
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3