LCOV - code coverage report
Current view: top level - ugbase/lib_grid/file_io - file_io_swc.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 142 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 6 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Markus Breit
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include <string>
      34              : #include <fstream>
      35              : #include <sstream>
      36              : #include <vector>
      37              : #include <queue>
      38              : #include <map>
      39              : #include "file_io_swc.h"
      40              : #include "common/error.h"
      41              : #include "common/util/string_util.h"
      42              : #include "lib_grid/global_attachments.h"
      43              : #include "lib_grid/algorithms/subset_util.h" // EraseEmptySubsets
      44              : #include "lib_grid/algorithms/element_side_util.h" // GetOpposingSide
      45              : #include <boost/lexical_cast.hpp>
      46              : 
      47              : using namespace std;
      48              : 
      49              : namespace ug{
      50              : 
      51              : 
      52            0 : bool FileReaderSWC::load_file(const char* fileName)
      53              : {
      54              :     m_vPts.clear();
      55              : 
      56            0 :     std::ifstream inFile(fileName);
      57            0 :     if (!inFile)
      58              :     {
      59            0 :         UG_LOGN("SWC input file '" << fileName << "' could not be opened for reading.");
      60              :         return false;
      61              :     }
      62              : 
      63              :     // read line by line
      64              :     std::string line;
      65              :     size_t lineCnt = 0;
      66            0 :     size_t curInd = 0;
      67              :     std::map<int, size_t> indexMap;
      68            0 :     while (std::getline(inFile, line))
      69              :     {
      70            0 :         ++lineCnt;
      71              : 
      72              :         // trim whitespace
      73            0 :         line = TrimString(line);
      74              : 
      75              :         // ignore anything from possible '#' onwards
      76              :         size_t nChar = line.size();
      77            0 :         for (size_t i = 0; i < nChar; ++i)
      78              :         {
      79            0 :             if (line.at(i) == '#')
      80              :             {
      81            0 :                 line = line.substr(0, i);
      82            0 :                 break;
      83              :             }
      84              :         }
      85              : 
      86              :         // empty lines can be ignored
      87            0 :         if (line.empty()) continue;
      88              : 
      89              :         // split the line into tokens
      90            0 :         std::istringstream buf(line);
      91            0 :         std::istream_iterator<std::string> beg(buf), end;
      92            0 :         std::vector<std::string> strs(beg, end);
      93              : 
      94              :         // assert number of tokens is correct
      95            0 :        if (strs.size() != 7)
      96              :        {
      97            0 :            UG_LOGN("Error reading SWC file '" << fileName << "': Line " << lineCnt
      98              :                    << " does not contain exactly 7 values.");
      99              :            return false;
     100              :        }
     101              : 
     102              : 
     103              :         // collect data for SWC point
     104            0 :         m_vPts.resize(m_vPts.size() + 1);
     105              :         SWCPoint& pt = m_vPts.back();
     106              : 
     107              :         // get index from file and map to our index
     108            0 :         indexMap[boost::lexical_cast<int>(strs[0])] = curInd;
     109              : 
     110              :         // type
     111            0 :         int type = boost::lexical_cast<int>(strs[1]);
     112            0 :         switch (type)
     113              :         {
     114            0 :             case 0: pt.type = swc_types::SWC_UNDF; break;
     115            0 :             case 1: pt.type = swc_types::SWC_SOMA; break;
     116            0 :             case 2: pt.type = swc_types::SWC_AXON; break;
     117            0 :             case 3: pt.type = swc_types::SWC_DEND; break;
     118            0 :             case 4: pt.type = swc_types::SWC_APIC; break;
     119            0 :             case 5: pt.type = swc_types::SWC_FORK; break;
     120            0 :             case 6: pt.type = swc_types::SWC_END; break;
     121            0 :             default: pt.type = swc_types::SWC_CUSTOM;
     122              :         }
     123              : 
     124              :         // coordinates
     125            0 :         pt.coords.x() = boost::lexical_cast<number>(strs[2]);
     126            0 :         pt.coords.y() = boost::lexical_cast<number>(strs[3]);
     127            0 :         pt.coords.z() = boost::lexical_cast<number>(strs[4]);
     128              : 
     129              :         // radius
     130            0 :         pt.radius = boost::lexical_cast<number>(strs[5]);
     131              : 
     132              :         // connections
     133            0 :         int conn = boost::lexical_cast<int>(strs[6]);
     134            0 :         if (conn >= 0)
     135              :         {
     136              :             std::map<int, size_t>::const_iterator it = indexMap.find(conn);
     137            0 :             if (it == indexMap.end())
     138              :             {
     139            0 :                 UG_LOGN("Error reading SWC file '" << fileName << "': Line " << lineCnt
     140              :                         << " refers to unknown parent index " << conn << ".");
     141            0 :                 return false;
     142              :             }
     143              : 
     144            0 :             size_t parentID = indexMap[conn];
     145            0 :             pt.conns.push_back(parentID);
     146            0 :             m_vPts[parentID].conns.push_back(curInd);
     147              :         }
     148              : 
     149              :         // increase current point index
     150            0 :         ++curInd;
     151            0 :     }
     152              : 
     153              :     return true;
     154            0 : }
     155              : 
     156              : 
     157              : 
     158            0 : bool FileReaderSWC::create_grid(Grid& g, ISubsetHandler* pSH, number scale_length)
     159              : {
     160            0 :         if (!g.has_vertex_attachment(aPosition))
     161              :                 g.attach_to_vertices(aPosition);
     162              :         Grid::VertexAttachmentAccessor<APosition> aaPos(g, aPosition);
     163              : 
     164              :         // handle diameter attachment
     165            0 :         if (!GlobalAttachments::is_declared("diameter"))
     166              :         {
     167            0 :                 try {GlobalAttachments::declare_attachment<ANumber>("diameter");}
     168            0 :                 catch (ug::UGError& err)
     169              :                 {
     170              :                         UG_LOGN(err.get_msg());
     171              :                         return false;
     172            0 :                 }
     173              :         }
     174              : 
     175            0 :         ANumber aDiam = GlobalAttachments::attachment<ANumber>("diameter");
     176            0 :         if (!g.has_vertex_attachment(aDiam))
     177              :                 g.attach_to_vertices(aDiam, true);
     178              : 
     179              :         Grid::AttachmentAccessor<Vertex, ANumber> aaDiam(g, aDiam);
     180              : 
     181              :         // create grid
     182              :         const size_t nP = m_vPts.size();
     183            0 :         std::vector<Vertex*> vrts(nP, NULL);
     184            0 :         for (size_t i = 0; i < nP; ++i)
     185              :         {
     186              :                 const SWCPoint& pt = m_vPts[i];
     187              : 
     188              :                 // create vertex and save
     189            0 :                 Vertex* v = vrts[i] = *g.create<RegularVertex>();
     190              :                 VecScale(aaPos[v], pt.coords, scale_length);
     191            0 :                 pSH->assign_subset(v, pt.type - 1);
     192            0 :                 aaDiam[v] = 2 * pt.radius * scale_length;
     193              : 
     194              :                 // create edge connections to already created vertices
     195            0 :                 for (size_t j = 0; j < pt.conns.size(); ++j)
     196              :                 {
     197            0 :                         if (pt.conns[j] < i)
     198              :                         {
     199            0 :                                 Edge* e = *g.create<RegularEdge>(EdgeDescriptor(vrts[pt.conns[j]], v));
     200            0 :                                 pSH->assign_subset(e, pt.type - 1);
     201              :                         }
     202              :                 }
     203              :         }
     204              : 
     205              :         // final subset management
     206            0 :         AssignSubsetColors(*pSH);
     207            0 :         pSH->set_subset_name("soma", 0);
     208            0 :         pSH->set_subset_name("axon", 1);
     209            0 :         pSH->set_subset_name("dend", 2);
     210            0 :         pSH->set_subset_name("apic", 3);
     211            0 :         pSH->set_subset_name("fork", 4);
     212            0 :         pSH->set_subset_name("end", 5);
     213            0 :         pSH->set_subset_name("custom", 6);
     214            0 :         EraseEmptySubsets(*pSH);
     215              : 
     216              :         return true;
     217            0 : }
     218              : 
     219              : 
     220              : 
     221            0 : const std::vector<swc_types::SWCPoint>& FileReaderSWC::swc_points() const
     222              : {
     223            0 :         return m_vPts;
     224              : }
     225              : 
     226              : 
     227              : 
     228            0 : std::vector<swc_types::SWCPoint>& FileReaderSWC::swc_points()
     229              : {
     230            0 :         return m_vPts;
     231              : }
     232              : 
     233              : 
     234              : 
     235            0 : bool LoadGridFromSWC(Grid& g, ISubsetHandler* pSH, const char* fileName, AVector3& aPos)
     236              : {
     237              :         // now read the file
     238              :         FileReaderSWC reader;
     239            0 :         return reader.load_file(fileName) && reader.create_grid(g, pSH, 1.0);
     240              : }
     241              : 
     242              : 
     243              : 
     244            0 : bool ExportGridToSWC(Grid& g, ISubsetHandler* pSH, const char* fileName, AVector3& aPos)
     245              : {
     246              :         // get access to positions
     247            0 :         if (!g.has_vertex_attachment(aPosition))
     248              :         {
     249              :                 UG_LOGN("Position attachment not attached to grid.");
     250            0 :                 return false;
     251              :         }
     252              :         Grid::VertexAttachmentAccessor<APosition> aaPos(g, aPosition);
     253              : 
     254              :         // get access to diameter attachment
     255            0 :         if (!GlobalAttachments::is_declared("diameter"))
     256              :         {
     257            0 :                 try {GlobalAttachments::declare_attachment<ANumber>("diameter");}
     258            0 :                 catch (ug::UGError& err)
     259              :                 {
     260              :                         UG_LOGN(err.get_msg());
     261              :                         return false;
     262            0 :                 }
     263              :         }
     264            0 :         ANumber aDiam = GlobalAttachments::attachment<ANumber>("diameter");
     265            0 :         if (!g.has_vertex_attachment(aDiam))
     266              :         {
     267              :                 UG_LOGN("WARNING: No diameter attachment attached to grid. "
     268              :                         "Will use 1.0 as default diameter.");
     269            0 :                 g.attach_to_vertices_dv(aDiam, 1.0);
     270              :         }
     271              :         Grid::AttachmentAccessor<Vertex, ANumber> aaDiam(g, aDiam);
     272              : 
     273              :         // analyze subset names to find out corresponding swc-types
     274            0 :         size_t nss = pSH->num_subsets();
     275            0 :         std::vector<size_t> vType(nss);
     276              :         bool soma_subset_present = false;
     277            0 :         for (size_t i = 0; i < nss; ++i)
     278              :         {
     279            0 :                 std::string name(pSH->get_subset_name(i));
     280              :                 std::transform(name.begin(), name.end(), name.begin(), ::toupper);
     281            0 :                 if (name.find("SOMA") != std::string::npos)
     282              :                 {
     283              :                         soma_subset_present = true;
     284            0 :                         vType[i] = 1;
     285              :                 }
     286            0 :                 else if (name.find("AXON") != std::string::npos)
     287            0 :                         vType[i] = 2;
     288            0 :                 else if (name.find("APIC") != std::string::npos)
     289            0 :                         vType[i] = 4;
     290            0 :                 else if (name.find("DEND") != std::string::npos)
     291            0 :                         vType[i] = 3;
     292            0 :     else if (name.find("END") != std::string::npos)
     293            0 :       vType[i] = 6;
     294            0 :     else if (name.find("FORK") != std::string::npos)
     295            0 :       vType[i] = 5;
     296            0 :     else if (name.find("CUSTOM") != std::string::npos)
     297            0 :       vType[i] = 7;
     298            0 :                 else vType[i] = 0;
     299              :         }
     300              : 
     301            0 :         if (!soma_subset_present)
     302              :                 UG_LOGN("Warning: No somatic subset could be identified.")
     303              : 
     304            0 :         if (g.begin<Vertex>() == g.end<Vertex>())
     305              :         {
     306              :                 UG_LOGN("Warning: No vertices contained in grid.")
     307              :                 return true;
     308              :         }
     309              : 
     310              :         // find soma vertex (if identifiable)
     311            0 :         Vertex* start = *g.begin<Vertex>();
     312            0 :         if (soma_subset_present)
     313              :         {
     314            0 :                 g.begin_marking();
     315              :                 std::queue<Vertex*> q; // corresponds to breadth-first
     316              :                 q.push(start);
     317            0 :                 while (!q.empty())
     318              :                 {
     319            0 :                         Vertex* v = q.front();
     320            0 :                         if (vType[pSH->get_subset_index(v)] == 1) break;
     321              :                         g.mark(v);
     322              :                         q.pop();
     323              : 
     324              :                         // push neighboring elems to queue
     325              :                         Grid::traits<Edge>::secure_container edges;
     326              :                         g.associated_elements(edges, v);
     327              : 
     328              :                         size_t sz = edges.size();
     329            0 :                         for (size_t e = 0; e < sz; ++e)
     330              :                         {
     331            0 :                                 Vertex* otherEnd = GetOpposingSide(g, edges[e], v);
     332            0 :                                 if (!g.is_marked(otherEnd))
     333              :                                         q.push(otherEnd);
     334              :                         }
     335              :                 }
     336            0 :                 g.end_marking();
     337              : 
     338            0 :                 if (q.empty())
     339              :                         UG_LOGN("Warning: No soma vertex could be found in the requested neuron.")
     340              :                 else
     341            0 :                         start = q.front();
     342              :         }
     343              : 
     344              :         // write the neuron to file
     345            0 :         std::ofstream outFile(fileName, std::ios::out);
     346            0 :         UG_COND_THROW(!outFile.is_open(), "Could not open output file '" << fileName << "'.");
     347              : 
     348              :         outFile << "# This file has been generated by UG4." << std::endl;
     349              : 
     350              :         std::stack<std::pair<Vertex*, int> > stack; // corresponds to depth-first
     351            0 :         stack.push(std::make_pair(start, -1));
     352              : 
     353            0 :         g.begin_marking();
     354              :         int ind = 0;   // by convention, swc starts with index 1
     355              :         bool all_types_identified = true;
     356            0 :         while (!stack.empty())
     357              :         {
     358              :                 // get all infos regarding vertex
     359              :                 std::pair<Vertex*, int>& info = stack.top();
     360            0 :                 Vertex* v = info.first;
     361            0 :                 int conn = info.second;
     362              :                 stack.pop();
     363              : 
     364              :                 // mark curr vrt
     365              :                 g.mark(v);
     366              : 
     367            0 :                 size_t type = vType[pSH->get_subset_index(v)];
     368            0 :                 if (!type) all_types_identified = false;
     369              : 
     370              :                 const vector3& coord = aaPos[v];
     371              : 
     372            0 :                 number radius = 0.5*aaDiam[v];
     373              : 
     374              :                 // write line to file
     375            0 :                 outFile << ++ind << " " << type << " "
     376            0 :                         << coord[0] << " " << coord[1] << " " << coord[2] << " "
     377            0 :                         << radius << " " << conn << std::endl;
     378              : 
     379              :                 // push neighboring elems to queue
     380              :                 Grid::traits<Edge>::secure_container edges;
     381              :                 g.associated_elements(edges, v);
     382              : 
     383              :                 size_t sz = edges.size();
     384            0 :                 for (size_t e = 0; e < sz; ++e)
     385              :                 {
     386            0 :                         Vertex* otherEnd = GetOpposingSide(g, edges[e], v);
     387            0 :                         if (!g.is_marked(otherEnd))
     388            0 :                                 stack.push(std::make_pair(otherEnd, ind));
     389              :                 }
     390              :         }
     391            0 :         g.end_marking();
     392              : 
     393            0 :         if (!all_types_identified)
     394              :                 UG_LOGN("WARNING: Some vertex type(s) - soma, dendrite, axon, etc. -\n"
     395              :                         "could not be identified using the subset names.\n"
     396              :                         << "To ensure correct types in the resulting swc file, the ugx subset names\n"
     397              :                         "need to contain one of the strings \"SOMA\", \"AXON\", \"DEND\", \"APIC\",\n"
     398              :                         "upper/lower case can be ignored.");
     399              : 
     400            0 :         outFile.close();
     401              : 
     402              :         return true;
     403            0 : }
     404              : 
     405              : 
     406              : 
     407              : }//     end of namespace
        

Generated by: LCOV version 2.0-1