openPMD-api
BaseRecord.hpp
1 /* Copyright 2017-2020 Fabian Koller
2  *
3  * This file is part of openPMD-api.
4  *
5  * openPMD-api is free software: you can redistribute it and/or modify
6  * it under the terms of of either the GNU General Public License or
7  * the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * openPMD-api is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License and the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * and the GNU Lesser General Public License along with openPMD-api.
19  * If not, see <http://www.gnu.org/licenses/>.
20  */
21 #pragma once
22 
23 #include "openPMD/backend/Container.hpp"
24 #include "openPMD/RecordComponent.hpp"
25 #include "openPMD/UnitDimension.hpp"
26 
27 #include <array>
28 #include <string>
29 #include <stdexcept>
30 
31 
32 namespace openPMD
33 {
34 
35 template< typename T_elem >
36 class BaseRecord : public Container< T_elem >
37 {
38  friend class Iteration;
39  friend class ParticleSpecies;
40 
41 public:
42  using key_type = typename Container< T_elem >::key_type;
43  using mapped_type = typename Container< T_elem >::mapped_type;
44  using value_type = typename Container< T_elem >::value_type;
45  using size_type = typename Container< T_elem >::size_type;
46  using difference_type = typename Container< T_elem >::difference_type;
47  using allocator_type = typename Container< T_elem >::allocator_type;
48  using reference = typename Container< T_elem >::reference;
49  using const_reference = typename Container< T_elem >::const_reference;
50  using pointer = typename Container< T_elem >::pointer;
51  using const_pointer = typename Container< T_elem >::const_pointer;
52  using iterator = typename Container< T_elem >::iterator;
53  using const_iterator = typename Container< T_elem >::const_iterator;
54 
55  BaseRecord(BaseRecord const& b);
56  BaseRecord& operator=(BaseRecord const& b);
57  virtual ~BaseRecord() = default;
58 
59  mapped_type& operator[](key_type const& key) override;
60  mapped_type& operator[](key_type&& key) override;
61  size_type erase(key_type const& key) override;
62  iterator erase(iterator res) override;
64  // iterator erase(const_iterator first, const_iterator last) override;
65 
66  virtual std::array< double, 7 > unitDimension() const;
67 
68 protected:
69  BaseRecord();
70  void readBase();
71 
72  std::shared_ptr< bool > m_containsScalar;
73 
74 private:
75  void flush(std::string const&) final;
76  virtual void flush_impl(std::string const&) = 0;
77  virtual void read() = 0;
78 }; //BaseRecord
79 
80 
81 template< typename T_elem >
84  m_containsScalar{b.m_containsScalar}
85 { }
86 
87 template< typename T_elem >
90  m_containsScalar = b.m_containsScalar;
91  return *this;
92 }
93 
94 template< typename T_elem >
97  m_containsScalar{std::make_shared< bool >(false)}
98 {
99  this->setAttribute("unitDimension",
100  std::array< double, 7 >{{0., 0., 0., 0., 0., 0., 0.}});
101 }
102 
103 
104 template< typename T_elem >
105 inline typename BaseRecord< T_elem >::mapped_type&
106 BaseRecord< T_elem >::operator[](key_type const& key)
107 {
108  auto it = this->find(key);
109  if( it != this->end() )
110  return it->second;
111  else
112  {
113  bool scalar = (key == RecordComponent::SCALAR);
114  if( (scalar && !Container< T_elem >::empty() && !*m_containsScalar) || (*m_containsScalar && !scalar) )
115  throw std::runtime_error("A scalar component can not be contained at "
116  "the same time as one or more regular components.");
117 
118  mapped_type& ret = Container< T_elem >::operator[](key);
119  if( scalar )
120  {
121  *m_containsScalar = true;
122  ret.m_writable->parent = this->m_writable->parent;
123  ret.parent = this->parent;
124  }
125  return ret;
126  }
127 }
128 
129 template< typename T_elem >
130 inline typename BaseRecord< T_elem >::mapped_type&
131 BaseRecord< T_elem >::operator[](key_type&& key)
132 {
133  auto it = this->find(key);
134  if( it != this->end() )
135  return it->second;
136  else
137  {
138  bool scalar = (key == RecordComponent::SCALAR);
139  if( (scalar && !Container< T_elem >::empty() && !*m_containsScalar) || (*m_containsScalar && !scalar) )
140  throw std::runtime_error("A scalar component can not be contained at "
141  "the same time as one or more regular components.");
142 
143  mapped_type& ret = Container< T_elem >::operator[](std::move(key));
144  if( scalar )
145  {
146  *m_containsScalar = true;
147  ret.m_writable->parent = this->m_writable->parent;
148  ret.parent = this->parent;
149  }
150  return ret;
151  }
152 }
153 
154 template< typename T_elem >
155 inline typename BaseRecord< T_elem >::size_type
156 BaseRecord< T_elem >::erase(key_type const& key)
157 {
158  bool scalar = (key == RecordComponent::SCALAR);
159  size_type res;
160  if( !scalar || (scalar && *this->at(key).m_isConstant) )
161  res = Container< T_elem >::erase(key);
162  else
163  {
164  mapped_type& rc = this->find(RecordComponent::SCALAR)->second;
165  if( rc.written )
166  {
168  dDelete.name = ".";
169  this->IOHandler->enqueue(IOTask(&rc, dDelete));
170  this->IOHandler->flush();
171  }
172  res = Container< T_elem >::erase(key);
173  }
174 
175  if( scalar )
176  {
177  this->written = false;
178  this->m_writable->abstractFilePosition.reset();
179  *this->m_containsScalar = false;
180  }
181  return res;
182 }
183 
184 template< typename T_elem >
185 inline typename BaseRecord< T_elem >::iterator
186 BaseRecord< T_elem >::erase(iterator res)
187 {
188  bool scalar = (res->first == RecordComponent::SCALAR);
189  iterator ret;
190  if( !scalar || (scalar && *this->at(res->first).m_isConstant) )
191  ret = Container< T_elem >::erase(res);
192  else
193  {
194  mapped_type& rc = this->find(RecordComponent::SCALAR)->second;
195  if( rc.written )
196  {
198  dDelete.name = ".";
199  this->IOHandler->enqueue(IOTask(&rc, dDelete));
200  this->IOHandler->flush();
201  }
202  ret = Container< T_elem >::erase(res);
203  }
204 
205  if( scalar )
206  {
207  this->written = false;
208  this->m_writable->abstractFilePosition.reset();
209  *this->m_containsScalar = false;
210  }
211  return ret;
212 }
213 
214 template< typename T_elem >
215 inline std::array< double, 7 >
217 {
218  return Attributable::getAttribute("unitDimension").template get< std::array< double, 7 > >();
219 }
220 
221 template< typename T_elem >
222 inline void
224 {
225  using DT = Datatype;
227 
228  aRead.name = "unitDimension";
229  this->IOHandler->enqueue(IOTask(this, aRead));
230  this->IOHandler->flush();
231  if( *aRead.dtype == DT::ARR_DBL_7 )
232  this->setAttribute("unitDimension", Attribute(*aRead.resource).template get< std::array< double, 7 > >());
233  else if( *aRead.dtype == DT::VEC_DOUBLE )
234  {
235  auto vec = Attribute(*aRead.resource).template get< std::vector< double > >();
236  if( vec.size() == 7 )
237  {
238  std::array< double, 7 > arr;
239  std::copy(vec.begin(),
240  vec.end(),
241  arr.begin());
242  this->setAttribute("unitDimension", arr);
243  } else
244  throw std::runtime_error("Unexpected Attribute datatype for 'unitDimension'");
245  }
246  else
247  throw std::runtime_error("Unexpected Attribute datatype for 'unitDimension'");
248 
249  aRead.name = "timeOffset";
250  this->IOHandler->enqueue(IOTask(this, aRead));
251  this->IOHandler->flush();
252  if( *aRead.dtype == DT::FLOAT )
253  this->setAttribute("timeOffset", Attribute(*aRead.resource).template get< float >());
254  else if( *aRead.dtype == DT::DOUBLE )
255  this->setAttribute("timeOffset", Attribute(*aRead.resource).template get< double >());
256  else
257  throw std::runtime_error("Unexpected Attribute datatype for 'timeOffset'");
258 }
259 
260 template< typename T_elem >
261 inline void
262 BaseRecord< T_elem >::flush(std::string const& name)
263 {
264  if( !this->written && this->empty() )
265  throw std::runtime_error("A Record can not be written without any contained RecordComponents: " + name);
266 
267  this->flush_impl(name);
268 }
269 } // openPMD
Attribute getAttribute(std::string const &key) const
Retrieve value of Attribute stored with provided key.
Definition: Attributable.cpp:62
Self-contained description of a single IO operation.
Definition: IOTask.hpp:468
virtual mapped_type & operator[](key_type const &key)
Access the value that is mapped to a key equivalent to key, creating it if such key does not exist al...
Definition: Container.hpp:142
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:35
virtual void enqueue(IOTask const &iotask)
Add provided task to queue according to FIFO.
Definition: AbstractIOHandler.hpp:89
virtual std::future< void > flush()=0
Process operations in queue according to FIFO.
virtual size_type erase(key_type const &key)
Remove a single element from the container and (if written) from disk.
Definition: Container.hpp:215
bool setAttribute(std::string const &key, T const &value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:209
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:38
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard...
Definition: Attribute.hpp:49
Public definitions of openPMD-api.
Definition: Date.cpp:28
Definition: BaseRecord.hpp:36
Definition: ParticleSpecies.hpp:34
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:70
virtual std::array< double, 7 > unitDimension() const
Definition: BaseRecord.hpp:216