Unverified Commit 22f9dc7d authored by Floris Berendsen's avatar Floris Berendsen Committed by GitHub
Browse files

Merge branch 'develop' into SELX-126-Make-compilation-logs-public

parents 9e017bd0 c476f698
..\SuperElastix.exe --conf ..\Configuration\itkv4_SVF_MSD_missingController.json --graphout 2B_graph_itkv4_MSD_missingController.dot --in FixedImage=..\Data\coneA2d64.mhd MovingImage=..\Data\coneB2d64.mhd --out ResultImage=2B_image_itkv4_MSD_missingController.mhd ResultDisplacementField=2B_deformation_itkv4_MSD_missingController.mhd
CALL graphviz_to_png 2B_graph_itkv4_MSD.dot
\ No newline at end of file
......@@ -72,43 +72,58 @@ main( int ac, char * av[] )
{
selx::Logger::Pointer logger = selx::Logger::New();
typedef std::vector< std::string > VectorOfStringsType;
typedef std::vector< boost::filesystem::path > VectorOfPathsType;
try
{
typedef std::vector< std::string > VectorOfStringsType;
typedef std::vector< boost::filesystem::path > VectorOfPathsType;
boost::filesystem::path logPath;
// default log level
selx::LogLevel logLevel = selx::LogLevel::WRN;
boost::filesystem::path logPath;
// default log level
selx::LogLevel logLevel = selx::LogLevel::WRN;
boost::filesystem::path configurationPath;
VectorOfPathsType configurationPaths;
boost::filesystem::path configurationPath;
VectorOfPathsType configurationPaths;
VectorOfStringsType inputPairs;
VectorOfStringsType outputPairs;
VectorOfStringsType inputPairs;
VectorOfStringsType outputPairs;
boost::program_options::variables_map vm;
try
{
boost::program_options::options_description desc("Allowed options");
desc.add_options()
( "help", "produce help message" )
("conf", boost::program_options::value< VectorOfPathsType >(&configurationPaths)->required()->multitoken(), "Configuration file")
("in", boost::program_options::value< VectorOfStringsType >(&inputPairs)->multitoken(), "Input data: images, labels, meshes, etc. Usage <name>=<path>")
("out", boost::program_options::value< VectorOfStringsType >(&outputPairs)->multitoken(), "Output data: images, labels, meshes, etc. Usage <name>=<path>")
("conf", boost::program_options::value< VectorOfPathsType >(&configurationPaths)->required()->multitoken(), "Configuration file: single or multiple Blueprints [.xml|.json]")
("in", boost::program_options::value< VectorOfStringsType >(&inputPairs)->multitoken(), "Input data: images, labels, meshes, etc. Usage arg: <name>=<path> (or multiple pairs)")
("out", boost::program_options::value< VectorOfStringsType >(&outputPairs)->multitoken(), "Output data: images, labels, meshes, etc. Usage arg: <name>=<path> (or multiple pairs)")
("graphout", boost::program_options::value< boost::filesystem::path >(), "Output Graphviz dot file")
("logfile", boost::program_options::value< boost::filesystem::path >(&logPath), "Log output file")
("loglevel", boost::program_options::value< selx::LogLevel >(&logLevel), "Log level")
("loglevel", boost::program_options::value< selx::LogLevel >(&logLevel), "Log level [off|critical|error|warning|info|debug|trace]")
;
boost::program_options::variables_map vm;
boost::program_options::store(boost::program_options::parse_command_line(ac, av, desc), vm);
boost::program_options::notify(vm);
if( vm.count( "help" ) )
{
std::cout << desc << "\n";
return 0;
}
boost::program_options::notify(vm);
}
catch (std::exception& e)
{
std::cerr << "Error: " << e.what() << "\n";
std::cerr << "See 'SuperElastix --help' for help" << "\n";
return 1;
}
catch (...)
{
std::cerr << "Unknown error!" << "\n";
return 1;
}
try
{
// optionally, stream to log file
std::ofstream outfile;
if ( vm.count("logfile") )
......@@ -149,7 +164,6 @@ main( int ac, char * av[] )
if( vm.count( "in" ) )
{
logger->Log( selx::LogLevel::INF, "Preparing input data ... ");
int index = 0;
for( const auto & inputPair : inputPairs )
{
VectorOfStringsType nameAndPath;
......@@ -159,15 +173,12 @@ main( int ac, char * av[] )
// since we do not know which reader type we should instantiate for input "name",
// we ask SuperElastix for a reader that matches the type of the source component "name"
logger->Log( selx::LogLevel::INF, "Preparing input " + name + " ..." );
logger->Log( selx::LogLevel::INF, "Preparing input '" + name + "': " + path + " ..." );
selx::AnyFileReader::Pointer reader = superElastixFilter->GetInputFileReader( name );
reader->SetFileName( path );
superElastixFilter->SetInput( name, reader->GetOutput() );
fileReaders.push_back( reader );
logger->Log( selx::LogLevel::INF, "Preparing input " + name + "... Done" );
std::cout << "Input data " << index << " " << name << " : " << path << "\n";
++index;
logger->Log( selx::LogLevel::INF, "Preparing input '" + name + "': " + path + " ... Done" );
}
logger->Log( selx::LogLevel::INF, "Preparing input data ... Done");
}
......@@ -179,7 +190,6 @@ main( int ac, char * av[] )
if( vm.count( "out" ) )
{
logger->Log( selx::LogLevel::INF, "Preparing output data ... ");
int index = 0;
for( const auto & outputPair : outputPairs )
{
VectorOfStringsType nameAndPath;
......@@ -189,16 +199,12 @@ main( int ac, char * av[] )
// since we do not know which writer type we should instantiate for output "name",
// we ask SuperElastix for a writer that matches the type of the sink component "name"
logger->Log( selx::LogLevel::INF, "Preparing output " + name + " ..." );
logger->Log( selx::LogLevel::INF, "Preparing output '" + name + "': " + path + " ..." );
selx::AnyFileWriter::Pointer writer = superElastixFilter->GetOutputFileWriter( name );
//ImageWriter2DType::Pointer writer = ImageWriter2DType::New();
writer->SetFileName( path );
//writer->SetInput(superElastixFilter->GetOutput<Image2DType>(name));
writer->SetInput( superElastixFilter->GetOutput( name ) );
fileWriters.push_back( writer );
logger->Log( selx::LogLevel::INF, "Preparing output " + name + " ... Done" );
++index;
logger->Log( selx::LogLevel::INF, "Preparing output '" + name + "': " + path + " ... Done" );
}
}
else
......@@ -216,14 +222,17 @@ main( int ac, char * av[] )
}
catch( std::exception & e )
{
logger->Log( selx::LogLevel::ERR, "Executing ... Error");
std::cerr << "error: " << e.what() << "\n";
logger->Log( selx::LogLevel::CRT, "Executing ... Error");
logger->Log( selx::LogLevel::CRT, e.what());
std::cerr << e.what();
return 1;
}
catch( ... )
{
logger->Log( selx::LogLevel::ERR, "Executing ... Error");
std::cerr << "Exception of unknown type!\n";
logger->Log( selx::LogLevel::CRT, "Executing ... Error");
logger->Log( selx::LogLevel::CRT, "Exception of unknown type!");
std::cerr << "Exception of unknown type!";
return 1;
}
return 0;
......
......@@ -55,9 +55,12 @@ public:
typedef std::map< ParameterKeyType, ParameterValueType > ParameterMapType;
typedef std::string ComponentNameType;
typedef std::vector< ComponentNameType > ComponentNamesType;
typedef std::string ConnectionNameType;
typedef std::vector< ConnectionNameType > ConnectionNamesType;
/* m_Blueprint is initialized in the default constructor */
Blueprint();
~Blueprint();
/** The actual blueprint is a pimpled member variable */
typedef std::unique_ptr< BlueprintImpl > BlueprintImplPointer;
......@@ -75,18 +78,18 @@ public:
// Returns a vector of the all Component names in the graph.
ComponentNamesType GetComponentNames( void ) const;
bool SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap );
bool SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap, ConnectionNameType name = "" );
ParameterMapType GetConnection( ComponentNameType upstream, ComponentNameType downstream ) const;
ParameterMapType GetConnection( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name = "" ) const;
bool DeleteConnection( ComponentNameType upstream, ComponentNameType downstream );
bool DeleteConnection( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name = "" );
bool ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const;
bool ConnectionExists( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name = "" ) const;
//std::unique_ptr<BlueprintImpl> Clone(BlueprintImpl const &other );
// "functional" composition of blueprints is done by adding settings of other to this blueprint. Redefining/overwriting properties is not allowed and returns false.
bool ComposeWith( Blueprint::ConstPointer other );
bool ComposeWith( const Blueprint * other );
// Returns a vector of the Component names at the incoming direction
ComponentNamesType GetInputNames( const ComponentNameType name ) const;
......@@ -103,10 +106,13 @@ public:
void MergeFromFile(const std::string& filename);
void SetLogger( Logger::Pointer logger );
private:
BlueprintImplPointer m_Blueprint;
// The order of the logger and the blueprint matters, since the lifetime of the logger should always exceed that of the blueprint.
Logger::Pointer m_Logger;
BlueprintImplPointer m_BlueprintImpl;
};
}
......
......@@ -24,25 +24,28 @@ namespace selx
{
Blueprint
::Blueprint()
::Blueprint() :
m_Logger( Logger::New() ), // Create default logger which redirects to std::cout
m_BlueprintImpl( new BlueprintImpl( this->m_Logger->GetLoggerImpl() ) )
{
// Create default logger which redirects to std::cout
this->m_Logger = Logger::New();
//TODO: cannot have independent loggers redirecting to cout.
//this->m_Logger->AddStream("cout", std::cout);
//TODO: this seems to affect other instantiated loggers too.
//this->m_Logger->SetLogLevel(selx::LogLevel::INF);
this->m_Blueprint = BlueprintImplPointer( new BlueprintImpl( this->m_Logger->GetLoggerImpl() ) );
}
// This class uses the pimpl idiom and therefore needs to implement the destructor explicitly: Effective Modern C++, Scott Meyers, item 22
Blueprint
::~Blueprint()
{
}
const BlueprintImpl &
Blueprint
::GetBlueprintImpl( void ) const
{
return *this->m_Blueprint;
return *this->m_BlueprintImpl;
}
......@@ -51,7 +54,7 @@ Blueprint
::SetComponent( ComponentNameType name, ParameterMapType parameterMap )
{
this->Modified();
return this->m_Blueprint->SetComponent( name, parameterMap );
return this->m_BlueprintImpl->SetComponent( name, parameterMap );
}
......@@ -59,7 +62,7 @@ Blueprint::ParameterMapType
Blueprint
::GetComponent( ComponentNameType componentName ) const
{
return this->m_Blueprint->GetComponent( componentName );
return this->m_BlueprintImpl->GetComponent( componentName );
}
......@@ -68,40 +71,40 @@ Blueprint
::DeleteComponent( ComponentNameType componentName )
{
this->Modified();
return this->m_Blueprint->DeleteComponent( componentName );
return this->m_BlueprintImpl->DeleteComponent( componentName );
}
Blueprint::ComponentNamesType
Blueprint::GetComponentNames( void ) const
{
return this->m_Blueprint->GetComponentNames();
return this->m_BlueprintImpl->GetComponentNames();
}
bool
Blueprint
::SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap )
::SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap, ConnectionNameType name )
{
this->Modified();
return this->m_Blueprint->SetConnection( upstream, downstream, parameterMap );
return this->m_BlueprintImpl->SetConnection( upstream, downstream, parameterMap, name );
}
Blueprint::ParameterMapType
Blueprint
::GetConnection( ComponentNameType upstream, ComponentNameType downstream ) const
::GetConnection( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name ) const
{
return this->m_Blueprint->GetConnection( upstream, downstream );
return this->m_BlueprintImpl->GetConnection( upstream, downstream, name );
}
bool
Blueprint
::DeleteConnection( ComponentNameType upstream, ComponentNameType downstream )
::DeleteConnection( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name )
{
this->Modified();
return this->m_Blueprint->DeleteConnection( upstream, downstream );
return this->m_BlueprintImpl->DeleteConnection( upstream, downstream, name );
}
......@@ -109,24 +112,24 @@ bool
Blueprint
::ComponentExists( ComponentNameType componentName ) const
{
return this->m_Blueprint->ComponentExists( componentName );
return this->m_BlueprintImpl->ComponentExists( componentName );
}
bool
Blueprint
::ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const
::ConnectionExists( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name ) const
{
return this->m_Blueprint->ConnectionExists( upstream, downstream );
return this->m_BlueprintImpl->ConnectionExists( upstream, downstream, name );
}
bool
Blueprint
::ComposeWith( Blueprint::ConstPointer other)
::ComposeWith( const Blueprint * other)
{
this->Modified();
return this->m_Blueprint->ComposeWith( other->GetBlueprintImpl() );
return this->m_BlueprintImpl->ComposeWith( other->GetBlueprintImpl() );
}
......@@ -134,7 +137,7 @@ Blueprint::ComponentNamesType
Blueprint
::GetOutputNames( const ComponentNameType name ) const
{
return this->m_Blueprint->GetOutputNames( name );
return this->m_BlueprintImpl->GetOutputNames( name );
}
......@@ -142,7 +145,7 @@ Blueprint::ComponentNamesType
Blueprint
::GetInputNames( const ComponentNameType name ) const
{
return this->m_Blueprint->GetInputNames( name );
return this->m_BlueprintImpl->GetInputNames( name );
}
......@@ -150,14 +153,14 @@ void
Blueprint
::Write( const std::string filename )
{
this->m_Blueprint->Write( filename );
this->m_BlueprintImpl->Write( filename );
}
void
Blueprint
::MergeFromFile( const std::string& filename )
{
this->m_Blueprint->MergeFromFile( filename );
this->m_BlueprintImpl->MergeFromFile( filename );
}
void
......@@ -165,7 +168,7 @@ Blueprint
::SetLogger( Logger::Pointer logger )
{
this->m_Logger = logger;
this->m_Blueprint->SetLoggerImpl( logger->GetLoggerImpl() );
this->m_BlueprintImpl->SetLoggerImpl( logger->GetLoggerImpl() );
}
......
......@@ -94,10 +94,6 @@ make_edge_label_writer( ParameterMapType p )
return edge_label_writer< ParameterMapType >( p );
}
// TODO: remove this argumentless constructor
BlueprintImpl::BlueprintImpl( void ) : m_LoggerImpl(&(Logger::New()->GetLoggerImpl()))
{
}
BlueprintImpl::BlueprintImpl( LoggerImpl & loggerImpl ) : m_LoggerImpl(&loggerImpl)
{
......@@ -128,6 +124,7 @@ BlueprintImpl
{
std::stringstream msg;
msg << "BlueprintImpl does not contain component " << name << std::endl;
this->m_LoggerImpl->Log(LogLevel::CRT, msg.str());
throw std::runtime_error( msg.str() );
}
......@@ -164,44 +161,80 @@ BlueprintImpl
bool
BlueprintImpl
::SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap )
::SetConnection( ComponentNameType upstream, ComponentNameType downstream, ParameterMapType parameterMap, ConnectionNameType name )
{
if( !this->ComponentExists( upstream ) || !this->ComponentExists( downstream ) )
{
this->m_LoggerImpl->Log(LogLevel::WRN, "Setting a connection between components '{}' and '{}' failed: one or more components do not exist");
return false;
}
if( !this->ConnectionExists( upstream, downstream ) )
{
boost::add_edge_by_label( upstream, downstream, { parameterMap }, this->m_Graph );
}
else
{
this->m_Graph[ this->GetConnectionIndex( upstream, downstream ) ].parameterMap = parameterMap;
}
// Multiple parallel connections are allowed. If a connection with the name "name" exists it should be overridden, otherwise just added.
boost::graph_traits<GraphType>::out_edge_iterator ei, ei_end;
// too bad edge_range_by_label doesn't exist
boost::tie(ei, ei_end) = boost::edge_range(this->m_Graph.vertex(upstream), this->m_Graph.vertex(downstream), this->m_Graph.graph());
for (; ei != ei_end; ++ei)
{
auto existingName = boost::get(&ConnectionPropertyType::name, this->m_Graph.graph(), *ei);
if (name == existingName)
{
// override previous parameterMap
boost::put(&ConnectionPropertyType::parameterMap, this->m_Graph.graph(), *ei, parameterMap);
return true;
}
}// no existing connections named "name" were found.
boost::add_edge_by_label(upstream, downstream, { name, parameterMap }, this->m_Graph);
return true;
}
BlueprintImpl::ParameterMapType
BlueprintImpl
::GetConnection( ComponentNameType upstream, ComponentNameType downstream ) const
::GetConnection( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name ) const
{
return this->m_Graph[ this->GetConnectionIndex( upstream, downstream ) ].parameterMap;
}
// This function assumes the connection exists.
boost::graph_traits<GraphType>::out_edge_iterator ei, ei_end;
// too bad edge_range_by_label doesn't exist
boost::tie(ei, ei_end) = boost::edge_range(this->m_Graph.vertex(upstream), this->m_Graph.vertex(downstream), this->m_Graph.graph());
for (; ei != ei_end; ++ei)
{
auto existingName = boost::get(&ConnectionPropertyType::name, this->m_Graph.graph(), *ei);
if (name == existingName)
{
return boost::get(&ConnectionPropertyType::parameterMap, this->m_Graph.graph(), *ei);
}
} // no existing connections named "name" were found.
throw std::runtime_error( "BlueprintImpl does not contain connection from component " + upstream + " to " + downstream + " by name " + name );
// assert(false);
return ParameterMapType();
}
bool
BlueprintImpl
::DeleteConnection( BlueprintImpl::ComponentNameType upstream, BlueprintImpl::ComponentNameType downstream )
::DeleteConnection( BlueprintImpl::ComponentNameType upstream, BlueprintImpl::ComponentNameType downstream, ConnectionNameType name )
{
if( this->ConnectionExists( upstream, downstream ) )
if( this->ConnectionExists( upstream, downstream, name ) )
{
boost::remove_edge_by_label( upstream, downstream, this->m_Graph );
boost::graph_traits<GraphType>::out_edge_iterator ei, ei_end;
// too bad edge_range_by_label doesn't exist
boost::tie(ei, ei_end) = boost::edge_range(this->m_Graph.vertex(upstream), this->m_Graph.vertex(downstream), this->m_Graph.graph());
for (; ei != ei_end; ++ei) {
auto existingName = boost::get(&ConnectionPropertyType::name, this->m_Graph.graph(), *ei);
if (name == existingName)
{
boost::remove_edge(*ei, this->m_Graph.graph());
return true;
}
}
}
return !this->ConnectionExists( upstream, downstream );
return false;
}
......@@ -215,7 +248,7 @@ BlueprintImpl
bool
BlueprintImpl
::ConnectionExists( ComponentNameType upstream, ComponentNameType downstream ) const
::ConnectionExists( ComponentNameType upstream, ComponentNameType downstream, ConnectionNameType name ) const
{
if( !this->ComponentExists( upstream ) )
{
......@@ -226,7 +259,23 @@ BlueprintImpl
return false;
}
return boost::edge_by_label( upstream, downstream, this->m_Graph ).second;
if (boost::edge_by_label( upstream, downstream, this->m_Graph ).second)
{
boost::graph_traits<GraphType>::out_edge_iterator ei, ei_end;
// too bad edge_range_by_label doesn't exist
boost::tie(ei, ei_end) = boost::edge_range(this->m_Graph.vertex(upstream), this->m_Graph.vertex(downstream), this->m_Graph.graph());
for (; ei != ei_end; ++ei)
{
auto existingName = boost::get(&ConnectionPropertyType::name, this->m_Graph.graph(), *ei);
if (name == existingName)
{
return true;
}
}
} // no existing connections named "name" were found.
return false;
}
......@@ -296,60 +345,64 @@ BlueprintImpl
{
for( auto incomingName : other.GetInputNames( componentName ) )
{
// Does other blueprint have a connection that already exists?
if( this->ConnectionExists( incomingName, componentName ) )
for (auto connectionName : other.GetConnectionNames(incomingName, componentName ) )
{
// Connection exists, check if properties can be merged
auto ownProperties = this->GetConnection( incomingName, componentName );
auto othersProperties = other.GetConnection( incomingName, componentName );
for( auto const & othersEntry : othersProperties )
// Does other blueprint have a connection that already exists?
if (this->ConnectionExists(incomingName, componentName, connectionName ))
{
// Does other use a property key that already exists in this component?
if( ownProperties.count( othersEntry.first ) )
// Connection exists, check if properties can be merged
auto ownProperties = this->GetConnection( incomingName, componentName, connectionName );
auto othersProperties = other.GetConnection( incomingName, componentName, connectionName );
for( auto const & othersEntry : othersProperties )
{
auto && ownValues = ownProperties[ othersEntry.first ];
auto && otherValues = othersEntry.second;
// Are the property values equal?
if( ownValues.size() != otherValues.size() )
// Does other use a property key that already exists in this component?
if( ownProperties.count( othersEntry.first ) )
{
// No, based on the number of values we see that it is different. Blueprints cannot be Composed
this->m_Graph = graph_backup;
return false;
}
else
{
ParameterValueType::const_iterator ownValue;
ParameterValueType::const_iterator otherValue;
for( ownValue = ownValues.begin(), otherValue = otherValues.begin(); ownValue != ownValues.end(); ++ownValue, ++otherValue )
auto && ownValues = ownProperties[ othersEntry.first ];
auto && otherValues = othersEntry.second;
// Are the property values equal?
if( ownValues.size() != otherValues.size() )
{
if( *otherValue != *ownValue )
// No, based on the number of values we see that it is different. Blueprints cannot be Composed
this->m_Graph = graph_backup;
return false;
}
else
{
ParameterValueType::const_iterator ownValue;
ParameterValueType::const_iterator otherValue;
for( ownValue = ownValues.begin(), otherValue = otherValues.begin(); ownValue != ownValues.end(); ++ownValue, ++otherValue )
{
// No, at least one value is different. Blueprints cannot be Composed
this->m_Graph = graph_backup;
return false;