Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for netCDF4 and padding with NaN values. #77

Open
wants to merge 5 commits into
base: toolchain-2.8
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions reporting/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ IF ( BUILD_REPORTING )
find_package(RTTPlugin REQUIRED rtt-marshalling)

# This gathers all the .cpp files into the variable 'SRCS'
SET( SRCS ConsoleReporting.cpp FileReporting.cpp ReportingComponent.cpp )
SET( HPPS ConsoleReporting.hpp FileReporting.hpp NiceHeaderMarshaller.hpp ReportingComponent.hpp TableMarshaller.hpp)
SET( SRCS ConsoleReporting.cpp FileReporting.cpp ReportingComponent.cpp TSVReporting.cpp )
SET( HPPS ConsoleReporting.hpp FileReporting.hpp NiceHeaderMarshaller.hpp ReportingComponent.hpp TableMarshaller.hpp TSVReporting.hpp TSVMarshaller.hpp )

# Reporting to a socket
SET( SOCKET_SRCS command.cpp datasender.cpp socket.cpp socketmarshaller.cpp TcpReporting.cpp)
Expand Down
12 changes: 11 additions & 1 deletion reporting/NetcdfHeaderMarshaller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <boost/lexical_cast.hpp>

#include <netcdf.h>
#include <cmath>

#define DIMENSION_VAR 1
#define DIMENSION_ARRAY 2
Expand All @@ -25,10 +26,14 @@ namespace RTT
int ncid;
int dimsid;
int ncopen;
float fNaN;
double dNaN;

public:

NetcdfHeaderMarshaller(int ncid, int dimsid) : ncid( ncid ), dimsid(dimsid), ncopen(0) {}
NetcdfHeaderMarshaller(int ncid, int dimsid) :
ncid( ncid ), dimsid(dimsid), ncopen(0),
fNaN(nanf("")), dNaN(nan("")) {}

virtual ~NetcdfHeaderMarshaller() {}

Expand Down Expand Up @@ -150,6 +155,7 @@ namespace RTT
log(Error) << "Could not create variable " << sname << ", error " << retval <<endlog();
else
log(Info) << "Variable "<< sname << " successfully created" <<endlog();

}

/**
Expand Down Expand Up @@ -210,6 +216,8 @@ namespace RTT
log(Error) << "Could not create variable " << sname << ", error " << retval <<endlog();
else
log(Info) << "Variable "<< sname << " successfully created" <<endlog();

nc_def_var_fill(ncid, varid, NC_FILL, &fNaN);
}

/**
Expand All @@ -231,6 +239,8 @@ namespace RTT
log(Error) << "Could not create variable " << sname << ", error " << retval <<endlog();
else
log(Info) << "Variable "<< sname << " successfully created" <<endlog();

nc_def_var_fill(ncid, varid, NC_FILL, &dNaN);
}

/**
Expand Down
20 changes: 14 additions & 6 deletions reporting/NetcdfReporting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ namespace OCL

NetcdfReporting::NetcdfReporting(const std::string& fr_name)
: ReportingComponent( fr_name ),
repfile("ReportFile","Location on disc to store the reports.", "reports.nc")
repfile("ReportFile","Location on disc to store the reports.", "reports.nc"),
useNetCDF4("useNetCDF4", "This flag controls whether to use the newer netCDF4 format.\n"
"The new format supports writing NaN values where there are missing values in the reported values arrays\n"
"but does not support shared access to the netCDF (e.g. your visualizer can not read from the file while orocos writes to it.",
true)
{
this->properties()->addProperty( repfile );
this->properties()->addProperty( useNetCDF4 );

if(types::TypeInfoRepository::Instance()->getTypeInfo<short>() == 0 )
{
Expand All @@ -36,9 +41,12 @@ namespace OCL
* Create a new netcdf dataset in the NC_CLOBBER mode.
* This means that the nc_create function overwrites any existing dataset.
*/
retval = nc_create(repfile.get().c_str(), NC_CLOBBER | NC_SHARE, &ncid);
int cmode = NC_CLOBBER | NC_SHARE;
if(useNetCDF4.get())
cmode |= NC_NETCDF4;
retval = nc_create(repfile.get().c_str(), cmode, &ncid);
if ( retval ) {
log(Error) << "Could not create "+repfile.get()+" for reporting."<<endlog();
log(Error) << "Could not create " << repfile.get() << " for reporting."<<endlog();
return false;
}

Expand All @@ -48,7 +56,7 @@ namespace OCL
*/
retval = nc_def_dim(ncid, "time", NC_UNLIMITED, &dimsid);
if ( retval ) {
log(Error) << "Could not create time dimension "+repfile.get() <<endlog();
log(Error) << "Could not create time dimension " << repfile.get() <<endlog();
return false;
}

Expand All @@ -57,7 +65,7 @@ namespace OCL
*/
retval = nc_enddef( ncid );
if ( retval ) {
log(Error) << "Could not leave define mode in "+repfile.get() <<endlog();
log(Error) << "Could not leave define mode in " << repfile.get() <<endlog();
return false;
}

Expand All @@ -83,7 +91,7 @@ namespace OCL
if ( ncid )
retval = nc_close (ncid);
if ( retval )
log(Error) << "Could not close file "+repfile.get()+" for reporting."<<endlog();
log(Error) << "Could not close file " << repfile.get() << " for reporting."<<endlog();
}

}
6 changes: 6 additions & 0 deletions reporting/NetcdfReporting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ namespace OCL
*/
RTT::Property<std::string> repfile;

/**
* Flag to toggle the usage of the newer netCDF4 format.
* Beware that the new format does not shared access to the .nc file.
*/
RTT::Property<bool> useNetCDF4;

/**
* Netcdf ID
*/
Expand Down
3 changes: 2 additions & 1 deletion reporting/ReportingComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,8 @@ namespace OCL
Ports ports = comp->ports()->getPorts();
for (Ports::iterator it = ports.begin(); it != ports.end() ; ++it) {
log(Debug) << "Checking port " << (*it)->getName()<<"."<<endlog();
this->reportPort( component, (*it)->getName() );
if(!dynamic_cast<base::InputPortInterface*>(*it)) //Don't try to report input ports
this->reportPort( component, (*it)->getName() );
}
return true;
}
Expand Down
129 changes: 129 additions & 0 deletions reporting/TSVMarshaller.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/***************************************************************************
tag: Peter Soetens Mon Jan 19 14:11:20 CET 2004 TSVMarshaller.hpp

TSVMarshaller.hpp - description
-------------------
begin : Mon January 19 2004
copyright : (C) 2004 Peter Soetens
email : [email protected]

***************************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public *
* License as published by the Free Software Foundation; *
* version 2 of the License. *
* *
* As a special exception, you may use this file as part of a free *
* software library without restriction. Specifically, if other files *
* instantiate templates or use macros or inline functions from this *
* file, or you compile this file and link it with other files to *
* produce an executable, this file does not by itself cause the *
* resulting executable to be covered by the GNU General Public *
* License. This exception does not however invalidate any other *
* reasons why the executable file might be covered by the GNU General *
* Public License. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307 USA *
* *
***************************************************************************/

#ifndef PI_PROPERTIES_TABLESERIALIZER
#define PI_PROPERTIES_TABLESERIALIZER

#include <fstream>
#include <map>
#include <rtt/Property.hpp>
#include <rtt/base/PropertyIntrospection.hpp>
#include <rtt/marsh/MarshallInterface.hpp>

namespace RTT {

/**
* @brief The TSVMarshaller class writes the serialized properties to a
* collection of TSV (tab separated values) files.
*/
class TSVMarshaller : public marsh::MarshallInterface {
std::string msep;
std::map<std::string, std::ofstream*> streams;
typedef std::map<std::string, std::ofstream*>::iterator stream_it;
double current_reporting_timestamp;

std::ofstream* getStream(const std::string& key, base::PropertyBase* v) {
if (streams.count(key) == 0) {
streams[key] =
new std::ofstream((key + ".txt").c_str(), std::ofstream::out);
(*streams[key]) << "ReportingTimestamp";
serialize(v, *streams[key], "", true);
(*streams[key]) << std::endl;
}
return streams[key];
}

public:

TSVMarshaller(std::string sep = "\t") : msep(sep) {}

virtual ~TSVMarshaller() {
for (stream_it it = streams.begin(); it != streams.end(); ++it) {
it->second->close();
delete it->second;
}
}

virtual void serialize(base::PropertyBase* v) {
if (v->getName() == "TimeStamp") {
Property<double>* timestamp = dynamic_cast<Property<double>*>(v);
current_reporting_timestamp = timestamp->rvalue();
} else {
std::ofstream& stream = *getStream(v->getName(), v);
stream << current_reporting_timestamp;
serialize(v, stream);
stream << std::endl;
}
}

void serialize(base::PropertyBase* v, std::ofstream& stream,
const std::string& prefix = "", bool header = false) {
Property<PropertyBag>* bag = dynamic_cast<Property<PropertyBag>*>(v);
if (bag) {
serialize(bag->rvalue(), stream, bag->getName(), header);
} else {
if (header) {
stream << msep << v->getName();
} else {
stream << msep << v->getDataSource();
}
}
}

virtual void serialize(const PropertyBag& v) {
for (PropertyBag::const_iterator i = v.getProperties().begin();
i != v.getProperties().end(); i++) {
serialize(*i);
}
}

virtual void serialize(const PropertyBag& v, std::ofstream& stream,
const std::string& prefix = "", bool header = false) {
for (PropertyBag::const_iterator i = v.getProperties().begin();
i != v.getProperties().end(); i++) {
this->serialize(*i, stream, prefix, header);
}
}

virtual void flush() {
for (stream_it it = streams.begin(); it != streams.end(); ++it) {
it->second->flush();
}
}
};
}
#endif
35 changes: 35 additions & 0 deletions reporting/TSVReporting.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <rtt/Logger.hpp>
#include <rtt/RTT.hpp>

#include "TSVReporting.hpp"
#include "TSVMarshaller.hpp"

#include "ocl/Component.hpp"
ORO_LIST_COMPONENT_TYPE(OCL::TSVReporting)

namespace OCL {
using namespace RTT;
using namespace std;

TSVReporting::TSVReporting(const std::string& fr_name)
: ReportingComponent(fr_name) {
this->onlyNewData = true;
}

bool TSVReporting::startHook() {
this->addMarshaller(0, new RTT::TSVMarshaller());
return ReportingComponent::startHook();
}

void TSVReporting::stopHook() {
ReportingComponent::stopHook();
this->removeMarshallers();
}

bool TSVReporting::screenComponent(const std::string& comp) {
Logger::In in("TSVReporting::screenComponent");
ofstream file((comp + ".screen").c_str());
if (!file) return false;
return this->screenImpl(comp, file);
}
}
36 changes: 36 additions & 0 deletions reporting/TSVReporting.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef ORO_COMP_TSV_REPORTING_HPP
#define ORO_COMP_TSV_REPORTING_HPP

#include <fstream>
#include "ReportingComponent.hpp"

#include <ocl/OCL.hpp>

namespace OCL {

/**
* @brief The TSVReporting class writes the reported values to a collection of
* TSV (Tab Separated Values) files.
* Each reported port ends up in its own TSV file, named after the port. This
* solves the problem of ports, that emit data on different frequencies. It also
* makes any header writing obsolete, enabling us to add new reported ports
* during runtime. By default reportOnlyNewData is set to true.
*/
class TSVReporting : public ReportingComponent {
protected:
public:
TSVReporting(const std::string& fr_name);

bool startHook();

void stopHook();

/**
* Writes the interface status of \a comp to
* a file 'comp.screen'.
*/
bool screenComponent(const std::string& comp);
};
}

#endif