26 #include "goby/common/logger.h" 30 void* plugin_handle = 0;
35 int main(
int argc,
char* argv[])
38 const char* plugin_path = getenv(
"GOBY_HDF5_PLUGIN");
41 std::cerr <<
"Loading plugin library: " << plugin_path << std::endl;
42 plugin_handle = dlopen(plugin_path, RTLD_LAZY);
45 std::cerr <<
"Failed to open library: " << plugin_path << std::endl;
51 std::cerr <<
"Environmental variable GOBY_HDF5_PLUGIN must be set with name of the dynamic " 52 "library containing the specific frontend plugin to use." 58 return goby::run<goby::common::hdf5::Writer>(argc, argv, &cfg);
63 const std::string& msg_name = entry.msg->GetDescriptor()->full_name();
64 typedef std::map<std::string, MessageCollection>::iterator It;
65 It it = entries.find(msg_name);
66 if (it == entries.end())
68 std::pair<It, bool> itpair =
69 entries.insert(std::make_pair(msg_name, MessageCollection(msg_name)));
72 it->second.entries.insert(std::make_pair(entry.time, entry.msg));
75 H5::Group& goby::common::hdf5::GroupFactory::fetch_group(
const std::string& group_path)
77 std::deque<std::string> nodes;
78 std::string clean_path = boost::trim_copy_if(group_path, boost::algorithm::is_space() ||
79 boost::algorithm::is_any_of(
"/"));
80 boost::split(nodes, clean_path, boost::is_any_of(
"/"));
81 return root_group_.fetch_group(nodes);
85 goby::common::hdf5::GroupFactory::GroupWrapper::fetch_group(std::deque<std::string>& nodes)
93 typedef std::map<std::string, GroupWrapper>::iterator It;
94 It it = children_.find(nodes[0]);
95 if (it == children_.end())
97 std::pair<It, bool> itpair =
98 children_.insert(std::make_pair(nodes[0], GroupWrapper(nodes[0], group_)));
102 return it->second.fetch_group(nodes);
107 : ApplicationBase(cfg), cfg_(*cfg), h5file_(cfg_.output_file(), H5F_ACC_TRUNC),
108 group_factory_(h5file_)
116 void goby::common::hdf5::Writer::load()
119 plugin_func plugin_ptr = (plugin_func)dlsym(plugin_handle,
"goby_hdf5_load");
123 glog <<
"Function goby_hdf5_load in library defined in GOBY_HDF5_PLUGIN does not exist." 126 plugin_.reset((*plugin_ptr)(&cfg_));
129 glog.is(DIE) &&
glog <<
"Function goby_hdf5_load in library defined in GOBY_HDF5_PLUGIN " 130 "returned a null pointer." 134 void goby::common::hdf5::Writer::collect()
137 while (plugin_->provide_entry(&entry))
139 boost::trim_if(entry.channel,
140 boost::algorithm::is_space() || boost::algorithm::is_any_of(
"/"));
142 typedef std::map<std::string, goby::common::hdf5::Channel>::iterator It;
143 It it = channels_.find(entry.channel);
144 if (it == channels_.end())
146 std::pair<It, bool> itpair = channels_.insert(
147 std::make_pair(entry.channel, goby::common::hdf5::Channel(entry.channel)));
151 it->second.add_message(entry);
156 void goby::common::hdf5::Writer::write()
158 for (std::map<std::string, goby::common::hdf5::Channel>::const_iterator it = channels_.begin(),
159 end = channels_.end();
161 write_channel(
"/" + it->first, it->second);
164 void goby::common::hdf5::Writer::write_channel(
const std::string& group,
165 const goby::common::hdf5::Channel& channel)
167 for (std::map<std::string, goby::common::hdf5::MessageCollection>::const_iterator
168 it = channel.entries.begin(),
169 end = channel.entries.end();
171 write_message_collection(group +
"/" + it->first, it->second);
174 void goby::common::hdf5::Writer::write_message_collection(
175 const std::string& group,
const goby::common::hdf5::MessageCollection& message_collection)
177 write_time(group, message_collection);
179 const google::protobuf::Descriptor* desc =
180 message_collection.entries.begin()->second->GetDescriptor();
181 for (
int i = 0, n = desc->field_count(); i < n; ++i)
183 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
185 std::vector<const google::protobuf::Message*> messages;
187 boost::shared_ptr<google::protobuf::Message> >::const_iterator
188 it = message_collection.entries.begin(),
189 end = message_collection.entries.end();
191 { messages.push_back(it->second.get()); } std::vector<hsize_t> hs;
192 hs.push_back(messages.size());
193 write_field_selector(group, field_desc, messages, hs);
197 void goby::common::hdf5::Writer::write_embedded_message(
198 const std::string& group,
const google::protobuf::FieldDescriptor* field_desc,
199 const std::vector<const google::protobuf::Message*> messages, std::vector<hsize_t>& hs)
201 const google::protobuf::Descriptor* sub_desc = field_desc->message_type();
202 if (field_desc->is_repeated())
204 int max_field_size = 0;
205 for (
unsigned i = 0, n = messages.size(); i < n; ++i)
209 const google::protobuf::Reflection* refl = messages[i]->GetReflection();
210 int field_size = refl->FieldSize(*messages[i], field_desc);
211 if (field_size > max_field_size)
212 max_field_size = field_size;
216 hs.push_back(max_field_size);
218 for (
int i = 0, n = sub_desc->field_count(); i < n; ++i)
220 const google::protobuf::FieldDescriptor* sub_field_desc = sub_desc->field(i);
222 std::vector<const google::protobuf::Message*> sub_messages(
225 for (
unsigned i = 0, n = messages.size(); i < n; ++i)
229 const google::protobuf::Reflection* refl = messages[i]->GetReflection();
230 int field_size = refl->FieldSize(*messages[i], field_desc);
232 for (
int j = 0; j < field_size; ++j)
235 refl->GetRepeatedMessage(*messages[i], field_desc, j);
236 sub_messages[i * max_field_size + j] = &sub_msg;
240 write_field_selector(group +
"/" + field_desc->name(), sub_field_desc, sub_messages,
247 for (
int i = 0, n = sub_desc->field_count(); i < n; ++i)
249 const google::protobuf::FieldDescriptor* sub_field_desc = sub_desc->field(i);
250 std::vector<const google::protobuf::Message*> sub_messages;
251 for (std::vector<const google::protobuf::Message*>::const_iterator
252 it = messages.begin(),
253 end = messages.end();
258 const google::protobuf::Reflection* refl = (*it)->GetReflection();
260 sub_messages.push_back(&sub_msg);
264 sub_messages.push_back(0);
267 write_field_selector(group +
"/" + field_desc->name(), sub_field_desc, sub_messages,
273 void goby::common::hdf5::Writer::write_field_selector(
274 const std::string& group,
const google::protobuf::FieldDescriptor* field_desc,
275 const std::vector<const google::protobuf::Message*>& messages, std::vector<hsize_t>& hs)
277 switch (field_desc->cpp_type())
279 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
280 write_embedded_message(group, field_desc, messages, hs);
283 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
286 write_field<goby::int32>(group, field_desc, messages, hs);
287 write_enum_attributes(group, field_desc);
291 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
292 write_field<goby::int32>(group, field_desc, messages, hs);
295 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
296 write_field<goby::int64>(group, field_desc, messages, hs);
299 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
300 write_field<goby::uint32>(group, field_desc, messages, hs);
303 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
304 write_field<goby::uint64>(group, field_desc, messages, hs);
307 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
308 write_field<unsigned char>(group, field_desc, messages, hs);
311 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
312 if (cfg_.include_string_fields())
313 write_field<std::string>(group, field_desc, messages, hs);
316 write_vector(group, field_desc->name(), std::vector<unsigned char>(),
317 std::vector<hsize_t>(1, 0), (
unsigned char)0);
320 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
321 write_field<float>(group, field_desc, messages, hs);
324 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
325 write_field<double>(group, field_desc, messages, hs);
330 void goby::common::hdf5::Writer::write_enum_attributes(
331 const std::string& group,
const google::protobuf::FieldDescriptor* field_desc)
334 H5::Group& grp = group_factory_.fetch_group(group);
335 H5::DataSet ds = grp.openDataSet(field_desc->name());
337 const google::protobuf::EnumDescriptor* enum_desc = field_desc->enum_type();
339 std::vector<const char*> names(enum_desc->value_count(), (
const char*)(0));
340 std::vector<goby::int32> values(enum_desc->value_count(), 0);
342 for (
int i = 0, n = enum_desc->value_count(); i < n; ++i)
344 names[i] = enum_desc->value(i)->name().c_str();
345 values[i] = enum_desc->value(i)->number();
350 hsize_t hs[] = {names.size()};
351 H5::DataSpace att_space(rank, hs, hs);
352 H5::StrType att_type(H5::PredType::C_S1, H5T_VARIABLE);
353 H5::Attribute att = ds.createAttribute(
"enum_names", att_type, att_space);
354 att.write(att_type, &names[0]);
358 hsize_t hs[] = {values.size()};
359 H5::DataSpace att_space(rank, hs, hs);
360 H5::IntType att_type(predicate<goby::int32>());
361 H5::Attribute att = ds.createAttribute(
"enum_values", att_type, att_space);
362 att.write(att_type, &values[0]);
366 void goby::common::hdf5::Writer::write_time(
367 const std::string& group,
const goby::common::hdf5::MessageCollection& message_collection)
369 std::vector<goby::uint64> utime(message_collection.entries.size(), 0);
370 std::vector<double> datenum(message_collection.entries.size(), 0);
372 for (std::multimap<
goby::uint64, boost::shared_ptr<google::protobuf::Message> >::const_iterator
373 it = message_collection.entries.begin(),
374 end = message_collection.entries.end();
377 utime[i] = it->first;
379 const double datenum_unix_epoch = 719529;
380 const double seconds_in_day = 86400;
382 goby::uint64 utime_frac = utime[i] - utime_sec * 1000000;
383 datenum[i] = datenum_unix_epoch +
static_cast<double>(utime_sec) / seconds_in_day +
384 static_cast<double>(utime_frac) / 1000000 / seconds_in_day;
388 std::vector<hsize_t> hs;
389 hs.push_back(message_collection.entries.size());
390 write_vector(group,
"_utime_", utime, hs, (
goby::uint64)0);
391 write_vector(group,
"_datenum_", datenum, hs, (
double)0);
394 void goby::common::hdf5::Writer::write_vector(
const std::string& group,
395 const std::string dataset_name,
396 const std::vector<std::string>& data,
397 const std::vector<hsize_t>& hs,
398 const std::string& default_value)
400 std::vector<const char*> data_c_str;
401 for (
unsigned i = 0, n = data.size(); i < n; ++i) data_c_str.push_back(data[i].c_str());
403 H5::DataSpace dataspace(hs.size(), hs.data(), hs.data());
404 H5::StrType datatype(H5::PredType::C_S1, H5T_VARIABLE);
405 H5::Group& grp = group_factory_.fetch_group(group);
406 H5::DataSet dataset = grp.createDataSet(dataset_name, datatype, dataspace);
408 if (data_c_str.size())
409 dataset.write(data_c_str.data(), datatype);
412 hsize_t att_hs[] = {1};
413 H5::DataSpace att_space(rank, att_hs, att_hs);
414 H5::StrType att_datatype(H5::PredType::C_S1, default_value.size() + 1);
415 H5::Attribute att = dataset.createAttribute(
"default_value", att_datatype, att_space);
416 const H5std_string strbuf(default_value);
417 att.write(att_datatype, strbuf);
void quit()
Requests a clean (return 0) exit.
common::FlexOstream glog
Access the Goby logger through this object.
google::protobuf::uint64 uint64
an unsigned 64 bit integer