Skip to content

Commit

Permalink
Allow SWC and ASC morphologies to be built from std:string (#407)
Browse files Browse the repository at this point in the history
* allow for Morphologies to be constructed from strings
* use unordered_map in SWC parser; good speedup: 1.22 -> 1.01 ms
* don't have unused debugInfo in SWC reader
* tidy up
* Move SWC parsing(!) out of errorMessages.h
  • Loading branch information
mgeplf authored May 23, 2022
1 parent 5512d18 commit d493136
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 122 deletions.
4 changes: 4 additions & 0 deletions binds/python/bind_immutable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ void bind_immutable_module(py::module& m) {
.def(py::init<const std::string&, unsigned int>(),
"filename"_a,
"options"_a = morphio::enums::Option::NO_MODIFIER)
.def(py::init<const std::string&, const std::string&, unsigned int>(),
"filename"_a,
"extension"_a,
"options"_a = morphio::enums::Option::NO_MODIFIER)
.def(py::init<morphio::mut::Morphology&>())
.def(py::init([](py::object arg, unsigned int options) {
return std::make_unique<morphio::Morphology>(py::str(arg), options);
Expand Down
25 changes: 1 addition & 24 deletions include/morphio/errorMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,32 +68,9 @@ static std::set<Warning> _ignoredWarnings;
struct Sample {
Sample() = default;

explicit Sample(const char* line, unsigned int lineNumber_)
: lineNumber(lineNumber_) {
floatType radius = -1.;
int int_type = -1;
#ifdef MORPHIO_USE_DOUBLE
const auto format = "%20u%20d%20lg%20lg%20lg%20lg%20d";
#else
const auto format = "%20u%20d%20f%20f%20f%20f%20d";
#endif
valid = sscanf(line,
format,
&id,
&int_type,
&point[0],
&point[1],
&point[2],
&radius,
&parentId) == 7;

type = static_cast<SectionType>(int_type);
diameter = radius * 2; // The point array stores diameters.
}

floatType diameter = -1.;
bool valid = false;
Point point;
Point point{};
SectionType type = SECTION_UNDEFINED;
int parentId = -1;
unsigned int id = 0;
Expand Down
8 changes: 7 additions & 1 deletion include/morphio/morphology.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,19 @@ class Morphology
Example:
Morphology("neuron.asc", TWO_POINTS_SECTIONS | SOMA_SPHERE);
*/
explicit Morphology(const std::string& source, unsigned int options = NO_MODIFIER);
explicit Morphology(const std::string& path, unsigned int options = NO_MODIFIER);

/** Constructor from an already parsed file */
explicit Morphology(const HighFive::Group& group, unsigned int options = NO_MODIFIER);

/** Constructor from an instance of morphio::mut::Morphology */
explicit Morphology(const mut::Morphology&);

/** Load a morphology from a string */
explicit Morphology(const std::string& contents,
const std::string& extension,
unsigned int options = NO_MODIFIER);

/** Return the soma object */
Soma soma() const;

Expand Down
80 changes: 60 additions & 20 deletions src/morphology.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <cctype> // std::tolower
#include <fstream>
#include <iterator> // std::back_inserter
#include <memory>

#include <morphio/endoplasmic_reticulum.h>
Expand All @@ -15,7 +17,20 @@

namespace {

void buildChildren(const std::shared_ptr<morphio::Property::Properties> properties) {
std::string readCompleteFile(const std::string& path) {
std::ifstream ifs(path);

if (!ifs) {
throw(morphio::RawDataError("File: " + path + " does not exist."));
}

std::ostringstream oss;
oss << ifs.rdbuf();

return oss.str();
}

void buildChildren(const std::shared_ptr<morphio::Property::Properties>& properties) {
{
const auto& sections = properties->get<morphio::Property::Section>();
auto& children = properties->_sectionLevel._children;
Expand Down Expand Up @@ -51,32 +66,52 @@ morphio::SomaType getSomaType(long unsigned int num_soma_points) {
return morphio::SOMA_SIMPLE_CONTOUR;
}

morphio::Property::Properties loadURI(const std::string& source, unsigned int options) {
const size_t pos = source.find_last_of('.');
if (pos == std::string::npos) {
std::string tolower(const std::string& str) {
std::string ret;
std::transform(str.begin(), str.end(), std::back_inserter(ret), [](unsigned char c) {
return std::tolower(c);
});
return ret;
}

morphio::Property::Properties loadFile(const std::string& path, unsigned int options) {
const size_t pos = path.find_last_of('.');
if (pos == std::string::npos || pos == path.length() - 1) {
throw(morphio::UnknownFileType("File has no extension"));
}

// Cross-platform check of file existance
std::ifstream file(source.c_str());
if (!file) {
throw(morphio::RawDataError("File: " + source + " does not exist."));
std::string extension = tolower(path.substr(pos + 1));

if (extension == "h5") {
return morphio::readers::h5::load(path);
} else if (extension == "asc") {
std::string contents = readCompleteFile(path);
return morphio::readers::asc::load(path, contents, options);
} else if (extension == "swc") {
std::string contents = readCompleteFile(path);
return morphio::readers::swc::load(path, contents, options);
}

std::string extension = source.substr(pos);
throw(morphio::UnknownFileType("Unhandled file type: '" + extension +
"' only SWC, ASC and H5 are supported"));
}


morphio::Property::Properties loadString(const std::string& contents,
const std::string& extension,
unsigned int options) {
std::string lower_extension = tolower(extension);

if (extension == ".h5" || extension == ".H5") {
return morphio::readers::h5::load(source);
} else if (extension == ".asc" || extension == ".ASC") {
return morphio::readers::asc::load(source, options);
} else if (extension == ".swc" || extension == ".SWC") {
return morphio::readers::swc::load(source, options);
if (lower_extension == "asc") {
return morphio::readers::asc::load("$STRING$", contents, options);
} else if (lower_extension == "swc") {
return morphio::readers::swc::load("$STRING$", contents, options);
}

throw(morphio::UnknownFileType("Unhandled file type: only SWC, ASC and H5 are supported"));
throw(morphio::UnknownFileType("Unhandled file type: '" + lower_extension +
"' only SWC, ASC and H5 are supported"));
}


} // namespace

namespace morphio {
Expand All @@ -99,17 +134,22 @@ Morphology::Morphology(const Property::Properties& properties, unsigned int opti
}
}

Morphology::Morphology(const std::string& path, unsigned int options)
: Morphology(loadFile(path, options), options) {}

Morphology::Morphology(const HighFive::Group& group, unsigned int options)
: Morphology(readers::h5::load(group), options) {}

Morphology::Morphology(const std::string& source, unsigned int options)
: Morphology(loadURI(source, options), options) {}

Morphology::Morphology(const mut::Morphology& morphology) {
properties_ = std::make_shared<Property::Properties>(morphology.buildReadOnly());
buildChildren(properties_);
}

Morphology::Morphology(const std::string& contents,
const std::string& extension,
unsigned int options)
: Morphology(loadString(contents, extension, options), options) {}

Soma Morphology::soma() const {
return Soma(properties_);
}
Expand Down
1 change: 1 addition & 0 deletions src/mut/morphology.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <cassert>
#include <cctype> // std::tolower
#include <iterator> // std::back_inserter
#include <sstream>
#include <string>

Expand Down
18 changes: 6 additions & 12 deletions src/readers/morphologyASC.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "morphologyASC.h"

#include <fstream>

#include <morphio/mut/morphology.h>
#include <morphio/mut/section.h>

Expand Down Expand Up @@ -69,15 +67,9 @@ class NeurolucidaParser
NeurolucidaParser(NeurolucidaParser const&) = delete;
NeurolucidaParser& operator=(NeurolucidaParser const&) = delete;

morphio::mut::Morphology& parse() {
std::ifstream ifs(uri_);
std::string input((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));

morphio::mut::Morphology& parse(const std::string& input) {
lex_.start_parse(input);

parse_root_sexps();

return nb_;
}

Expand Down Expand Up @@ -376,10 +368,12 @@ class NeurolucidaParser

} // namespace

Property::Properties load(const std::string& uri, unsigned int options) {
NeurolucidaParser parser(uri);
Property::Properties load(const std::string& path,
const std::string& contents,
unsigned int options) {
NeurolucidaParser parser(path);

morphio::mut::Morphology& nb_ = parser.parse();
morphio::mut::Morphology& nb_ = parser.parse(contents);
nb_.applyModifiers(options);

Property::Properties properties = nb_.buildReadOnly();
Expand Down
4 changes: 3 additions & 1 deletion src/readers/morphologyASC.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
namespace morphio {
namespace readers {
namespace asc {
Property::Properties load(const std::string& path, unsigned int options);
Property::Properties load(const std::string& path,
const std::string& contents,
unsigned int options);
} // namespace asc
} // namespace readers
} // namespace morphio
Loading

0 comments on commit d493136

Please sign in to comment.