openPMD-api
ADIOS2IOHandler.hpp
1 /* Copyright 2017-2021 Fabian Koller and Franz Poeschel
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/IO/AbstractIOHandler.hpp"
24 #include "openPMD/IO/AbstractIOHandlerImpl.hpp"
25 #include "openPMD/IO/AbstractIOHandlerImplCommon.hpp"
26 #include "openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp"
27 #include "openPMD/IO/ADIOS/ADIOS2FilePosition.hpp"
28 #include "openPMD/IO/ADIOS/ADIOS2PreloadAttributes.hpp"
29 #include "openPMD/IO/IOTask.hpp"
30 #include "openPMD/IO/InvalidatableFile.hpp"
31 #include "openPMD/auxiliary/JSON.hpp"
32 #include "openPMD/auxiliary/Option.hpp"
33 #include "openPMD/backend/Writable.hpp"
34 #include "openPMD/config.hpp"
35 #include "openPMD/IterationEncoding.hpp"
36 
37 #if openPMD_HAVE_ADIOS2
38 # include <adios2.h>
39 #endif
40 #if openPMD_HAVE_MPI
41 # include <mpi.h>
42 #endif
43 #include <nlohmann/json.hpp>
44 
45 #include <array>
46 #include <exception>
47 #include <future>
48 #include <iostream>
49 #include <memory> // shared_ptr
50 #include <set>
51 #include <string>
52 #include <unordered_map>
53 #include <utility> // pair
54 #include <vector>
55 
56 
57 namespace openPMD
58 {
59 #if openPMD_HAVE_ADIOS2
60 
61 class ADIOS2IOHandler;
62 
63 namespace detail
64 {
65  template < typename, typename > struct DatasetHelper;
66  struct GetSpan;
67  struct DatasetReader;
68  struct AttributeReader;
69  struct AttributeWriter;
70  struct OldAttributeReader;
71  struct OldAttributeWriter;
72  template < typename > struct AttributeTypes;
73  struct DatasetOpener;
74  struct VariableDefiner;
75  template < typename > struct DatasetTypes;
76  struct WriteDataset;
77  struct BufferedActions;
78  struct BufferedPut;
79  struct BufferedGet;
80  struct BufferedAttributeRead;
82 } // namespace detail
83 
84 
85 namespace ADIOS2Schema
86 {
87  using schema_t = uint64_t;
88  /*
89  * Original ADIOS schema.
90  */
91  constexpr schema_t schema_0000_00_00 = 00000000;
92  /*
93  * This introduces attribute layout via scalar ADIOS variables.
94  */
95  constexpr schema_t schema_2021_02_09 = 20210209;
96 
97  enum class SupportedSchema : char
98  {
99  s_0000_00_00,
100  s_2021_02_09
101  };
102 }
103 using SupportedSchema = ADIOS2Schema::SupportedSchema;
104 
106 : public AbstractIOHandlerImplCommon< ADIOS2FilePosition >
107 {
108  template < typename, typename > friend struct detail::DatasetHelper;
109  friend struct detail::GetSpan;
110  friend struct detail::DatasetReader;
111  friend struct detail::AttributeReader;
112  friend struct detail::AttributeWriter;
113  friend struct detail::OldAttributeReader;
114  friend struct detail::OldAttributeWriter;
115  template < typename > friend struct detail::AttributeTypes;
116  friend struct detail::DatasetOpener;
117  friend struct detail::VariableDefiner;
118  template < typename > friend struct detail::DatasetTypes;
119  friend struct detail::WriteDataset;
120  friend struct detail::BufferedActions;
121  friend struct detail::BufferedAttributeRead;
122 
123  static constexpr bool ADIOS2_DEBUG_MODE = false;
124 
125 
126 public:
127 
128 #if openPMD_HAVE_MPI
129 
132  MPI_Comm,
133  nlohmann::json config,
134  std::string engineType );
135 
136 #endif // openPMD_HAVE_MPI
137 
138  explicit ADIOS2IOHandlerImpl(
140  nlohmann::json config,
141  std::string engineType );
142 
143 
144  ~ADIOS2IOHandlerImpl() override;
145 
146  std::future< void > flush( ) override;
147 
148  void createFile( Writable *,
149  Parameter< Operation::CREATE_FILE > const & ) override;
150 
151  void createPath( Writable *,
152  Parameter< Operation::CREATE_PATH > const & ) override;
153 
154  void
155  createDataset( Writable *,
156  Parameter< Operation::CREATE_DATASET > const & ) override;
157 
158  void
159  extendDataset( Writable *,
160  Parameter< Operation::EXTEND_DATASET > const & ) override;
161 
162  void openFile( Writable *,
163  Parameter< Operation::OPEN_FILE > const & ) override;
164 
165  void closeFile( Writable *,
166  Parameter< Operation::CLOSE_FILE > const & ) override;
167 
168  void openPath( Writable *,
169  Parameter< Operation::OPEN_PATH > const & ) override;
170 
171  void closePath( Writable *,
172  Parameter< Operation::CLOSE_PATH > const & ) override;
173 
174  void openDataset( Writable *,
176 
177  void deleteFile( Writable *,
178  Parameter< Operation::DELETE_FILE > const & ) override;
179 
180  void deletePath( Writable *,
181  Parameter< Operation::DELETE_PATH > const & ) override;
182 
183  void
184  deleteDataset( Writable *,
185  Parameter< Operation::DELETE_DATASET > const & ) override;
186 
187  void deleteAttribute( Writable *,
188  Parameter< Operation::DELETE_ATT > const & ) override;
189 
190  void writeDataset( Writable *,
191  Parameter< Operation::WRITE_DATASET > const & ) override;
192 
193  void writeAttribute( Writable *,
194  Parameter< Operation::WRITE_ATT > const & ) override;
195 
196  void readDataset( Writable *,
198 
199  void getBufferView( Writable *,
201 
202  void readAttribute( Writable *,
204 
205  void listPaths( Writable *, Parameter< Operation::LIST_PATHS > & ) override;
206 
207  void listDatasets( Writable *,
209 
210  void
211  listAttributes( Writable *,
212  Parameter< Operation::LIST_ATTS > & parameters ) override;
213 
214  void
215  advance( Writable*, Parameter< Operation::ADVANCE > & ) override;
216 
217  void
218  availableChunks( Writable*,
224  adios2::Mode adios2AccessMode( std::string const & fullPath );
225 
226 private:
227  adios2::ADIOS m_ADIOS;
228  /*
229  * If the iteration encoding is variableBased, we default to using the
230  * 2021_02_09 schema since it allows mutable attributes.
231  */
232  IterationEncoding m_iterationEncoding = IterationEncoding::groupBased;
236  std::string m_engineType;
237  ADIOS2Schema::schema_t m_schema = ADIOS2Schema::schema_0000_00_00;
238 
239  enum class AttributeLayout : char
240  {
241  ByAdiosAttributes,
242  ByAdiosVariables
243  };
244 
245  inline SupportedSchema schema() const
246  {
247  switch( m_schema )
248  {
249  case ADIOS2Schema::schema_0000_00_00:
250  return SupportedSchema::s_0000_00_00;
251  case ADIOS2Schema::schema_2021_02_09:
252  return SupportedSchema::s_2021_02_09;
253  default:
254  throw std::runtime_error(
255  "[ADIOS2] Encountered unsupported schema version: " +
256  std::to_string( m_schema ) );
257  }
258  }
259 
260  inline AttributeLayout attributeLayout() const
261  {
262  switch( schema() )
263  {
264  case SupportedSchema::s_0000_00_00:
265  return AttributeLayout::ByAdiosAttributes;
266  case SupportedSchema::s_2021_02_09:
267  return AttributeLayout::ByAdiosVariables;
268  }
269  throw std::runtime_error( "Unreachable!" );
270  }
271 
272  struct ParameterizedOperator
273  {
274  adios2::Operator op;
275  adios2::Params params;
276  };
277 
278  std::vector< ParameterizedOperator > defaultOperators;
279 
280  auxiliary::TracingJSON m_config;
281  static auxiliary::TracingJSON nullvalue;
282 
283  void
284  init( nlohmann::json config );
285 
286  template< typename Key >
288  config( Key && key, auxiliary::TracingJSON & cfg )
289  {
290  if( cfg.json().is_object() && cfg.json().contains( key ) )
291  {
292  return cfg[ key ];
293  }
294  else
295  {
296  return nullvalue;
297  }
298  }
299 
300  template< typename Key >
302  config( Key && key )
303  {
304  return config< Key >( std::forward< Key >( key ), m_config );
305  }
306 
315  getOperators( auxiliary::TracingJSON config );
316 
317  // use m_config
319  getOperators();
320 
321  std::string
322  fileSuffix() const;
323 
324  /*
325  * We need to give names to IO objects. These names are irrelevant
326  * within this application, since:
327  * 1) The name of the file written to is decided by the opened Engine's
328  * name.
329  * 2) The IOs are managed by the unordered_map m_fileData, so we do not
330  * need the ADIOS2 internal management.
331  * Since within one m_ADIOS object, the same IO name cannot be used more
332  * than once, we ensure different names by using the name counter.
333  * This allows to overwrite a file later without error.
334  */
335  int nameCounter{0};
336 
337  /*
338  * IO-heavy actions are deferred to a later point. This map stores for
339  * each open file (identified by an InvalidatableFile object) an object
340  * that manages IO-heavy actions, as well as its ADIOS2 objects, i.e.
341  * IO and Engine object.
342  * Not to be accessed directly, use getFileData().
343  */
344  std::unordered_map< InvalidatableFile,
345  std::unique_ptr< detail::BufferedActions >
346  > m_fileData;
347 
348  std::map< std::string, adios2::Operator > m_operators;
349 
350  // Overrides from AbstractIOHandlerImplCommon.
351 
352  std::string
353  filePositionToString( std::shared_ptr< ADIOS2FilePosition > ) override;
354 
355  std::shared_ptr< ADIOS2FilePosition >
356  extendFilePosition( std::shared_ptr< ADIOS2FilePosition > const & pos,
357  std::string extend ) override;
358 
359  // Helper methods.
360 
362  getCompressionOperator( std::string const & compression );
363 
364  /*
365  * The name of the ADIOS2 variable associated with this Writable.
366  * To be used for Writables that represent a dataset.
367  */
368  std::string nameOfVariable( Writable * writable );
369 
379  std::string nameOfAttribute( Writable * writable, std::string attribute );
380 
381  /*
382  * Figure out whether the Writable corresponds with a
383  * group or a dataset.
384  */
385  ADIOS2FilePosition::GD groupOrDataset( Writable * );
386 
387  enum class IfFileNotOpen : bool
388  {
389  OpenImplicitly,
390  ThrowError
391  };
392 
394  getFileData( InvalidatableFile file, IfFileNotOpen );
395 
396  void dropFileData( InvalidatableFile file );
397 
398  /*
399  * Prepare a variable that already exists for an IO
400  * operation, including:
401  * (1) checking that its datatype matches T.
402  * (2) the offset and extent match the variable's shape
403  * (3) setting the offset and extent (ADIOS lingo: start
404  * and count)
405  */
406  template < typename T >
407  adios2::Variable< T > verifyDataset( Offset const & offset,
408  Extent const & extent, adios2::IO & IO,
409  std::string const & var );
410 }; // ADIOS2IOHandlerImpl
411 
412 /*
413  * The following strings are used during parsing of the JSON configuration
414  * string for the ADIOS2 backend.
415  */
416 namespace ADIOS2Defaults
417 {
418  using const_str = char const * const;
419  constexpr const_str str_engine = "engine";
420  constexpr const_str str_type = "type";
421  constexpr const_str str_params = "parameters";
422  constexpr const_str str_usesteps = "usesteps";
423  constexpr const_str str_usesstepsAttribute = "__openPMD_internal/useSteps";
424  constexpr const_str str_adios2Schema =
425  "__openPMD_internal/openPMD2_adios2_schema";
426  constexpr const_str str_isBooleanOldLayout = "__is_boolean__";
427  constexpr const_str str_isBooleanNewLayout =
428  "__openPMD_internal/is_boolean";
429 } // namespace ADIOS2Defaults
430 
431 namespace detail
432 {
433  // Helper structs for calls to the switchType function
434 
436  {
438 
439 
440  explicit DatasetReader( openPMD::ADIOS2IOHandlerImpl * impl );
441 
442 
443  template < typename T >
444  void operator( )( BufferedGet & bp, adios2::IO & IO,
445  adios2::Engine & engine,
446  std::string const & fileName );
447 
448  std::string errorMsg = "ADIOS2: readDataset()";
449  };
450 
452  {
453  template< typename T >
454  Datatype
455  operator()(
456  adios2::IO & IO,
457  std::string name,
458  std::shared_ptr< Attribute::resource > resource );
459 
460  template< int n, typename... Params >
461  Datatype
462  operator()( Params &&... );
463  };
464 
466  {
467  template< typename T >
468  void
469  operator()(
470  ADIOS2IOHandlerImpl * impl,
471  Writable * writable,
472  const Parameter< Operation::WRITE_ATT > & parameters );
473 
474 
475  template< int n, typename... Params >
476  void
477  operator()( Params &&... );
478  };
479 
481  {
482  template< typename T >
483  Datatype
484  operator()(
485  adios2::IO & IO,
486  detail::PreloadAdiosAttributes const & preloadedAttributes,
487  std::string name,
488  std::shared_ptr< Attribute::resource > resource );
489 
490  template < int n, typename... Params >
491  Datatype operator( )( Params &&... );
492  };
493 
495  {
496  template < typename T >
497  void
498  operator()(
500  BufferedActions & fileData );
501 
502 
503  template < int n, typename... Params > void operator( )( Params &&... );
504  };
505 
507  {
508  ADIOS2IOHandlerImpl * m_impl;
509 
510  explicit DatasetOpener( ADIOS2IOHandlerImpl * impl );
511 
512 
513  template < typename T >
514  void operator( )( InvalidatableFile, const std::string & varName,
516 
517 
518  std::string errorMsg = "ADIOS2: openDataset()";
519  };
520 
522  {
523  ADIOS2IOHandlerImpl * m_handlerImpl;
524 
525 
526  WriteDataset( ADIOS2IOHandlerImpl * handlerImpl );
527 
528 
529  template < typename T >
530  void operator( )( BufferedPut & bp, adios2::IO & IO,
531  adios2::Engine & engine );
532 
533  template < int n, typename... Params > void operator( )( Params &&... );
534  };
535 
537  {
553  template < typename T >
554  void operator( )(
555  adios2::IO & IO,
556  std::string const & name,
557  std::vector< ADIOS2IOHandlerImpl::ParameterizedOperator > const &
558  compressions,
559  adios2::Dims const & shape = adios2::Dims(),
560  adios2::Dims const & start = adios2::Dims(),
561  adios2::Dims const & count = adios2::Dims(),
562  bool const constantDims = false );
563 
564  std::string errorMsg = "ADIOS2: defineVariable()";
565  };
566 
568  {
569  template < typename T >
570  void operator( )(
572  adios2::IO & IO,
573  adios2::Engine & engine,
574  std::string const & varName );
575 
576  template < int n, typename... Params >
577  void operator( )( Params &&... );
578  };
579 
580  // Helper structs to help distinguish valid attribute/variable
581  // datatypes from invalid ones
582 
583  /*
584  * This struct's purpose is to have specialisations
585  * for vector and array types, as well as the boolean
586  * type (which is not natively supported by ADIOS).
587  */
588  template< typename T >
589  struct AttributeTypes
590  {
591  static void
592  oldCreateAttribute(
593  adios2::IO & IO,
594  std::string name,
595  T value );
596 
597  static void
598  oldReadAttribute(
599  adios2::IO & IO,
600  std::string name,
601  std::shared_ptr< Attribute::resource > resource );
602 
603  static void
604  createAttribute(
605  adios2::IO & IO,
606  adios2::Engine & engine,
608  T value );
609 
610  static void
611  readAttribute(
613  std::string name,
614  std::shared_ptr< Attribute::resource > resource );
615 
620  static bool
621  attributeUnchanged( adios2::IO & IO, std::string name, T val )
622  {
623  auto attr = IO.InquireAttribute< T >( name );
624  if( !attr )
625  {
626  return false;
627  }
628  std::vector< T > data = attr.Data();
629  if( data.size() != 1 )
630  {
631  return false;
632  }
633  return data[ 0 ] == val;
634  }
635  };
636 
637  template< > struct AttributeTypes< std::complex< long double > >
638  {
639  static void
640  oldCreateAttribute(
641  adios2::IO &,
642  std::string,
643  std::complex< long double > )
644  {
645  throw std::runtime_error(
646  "[ADIOS2] Internal error: no support for long double complex attribute types" );
647  }
648 
649  static void
650  oldReadAttribute(
651  adios2::IO &,
652  std::string,
653  std::shared_ptr< Attribute::resource > )
654  {
655  throw std::runtime_error(
656  "[ADIOS2] Internal error: no support for long double complex attribute types" );
657  }
658 
659  static void
660  createAttribute(
661  adios2::IO &,
662  adios2::Engine &,
664  std::complex< long double > )
665  {
666  throw std::runtime_error(
667  "[ADIOS2] Internal error: no support for long double complex attribute types" );
668  }
669 
670  static void
671  readAttribute(
673  std::string,
674  std::shared_ptr< Attribute::resource > )
675  {
676  throw std::runtime_error(
677  "[ADIOS2] Internal error: no support for long double complex attribute types" );
678  }
679 
680  static bool
682  adios2::IO &, std::string, std::complex< long double > )
683  {
684  throw std::runtime_error(
685  "[ADIOS2] Internal error: no support for long double complex attribute types" );
686  }
687  };
688 
689  template< > struct AttributeTypes< std::vector< std::complex< long double > > >
690  {
691  static void
692  oldCreateAttribute(
693  adios2::IO &,
694  std::string,
695  const std::vector< std::complex< long double > > & )
696  {
697  throw std::runtime_error(
698  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
699  }
700 
701  static void
702  oldReadAttribute(
703  adios2::IO &,
704  std::string,
705  std::shared_ptr< Attribute::resource > )
706  {
707  throw std::runtime_error(
708  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
709  }
710 
711  static void
712  createAttribute(
713  adios2::IO &,
714  adios2::Engine &,
716  const std::vector< std::complex< long double > > & )
717  {
718  throw std::runtime_error(
719  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
720  }
721 
722  static void
723  readAttribute(
725  std::string,
726  std::shared_ptr< Attribute::resource > )
727  {
728  throw std::runtime_error(
729  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
730  }
731 
732  static bool
734  adios2::IO &,
735  std::string,
736  std::vector< std::complex< long double > > )
737  {
738  throw std::runtime_error(
739  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
740  }
741  };
742 
743  template < typename T > struct AttributeTypes< std::vector< T > >
744  {
745  static void
746  oldCreateAttribute(
747  adios2::IO & IO,
748  std::string name,
749  const std::vector< T > & value );
750 
751  static void
752  oldReadAttribute(
753  adios2::IO & IO,
754  std::string name,
755  std::shared_ptr< Attribute::resource > resource );
756 
757  static void
758  createAttribute(
759  adios2::IO & IO,
760  adios2::Engine & engine,
762  const std::vector< T > & value );
763 
764  static void
765  readAttribute(
767  std::string name,
768  std::shared_ptr< Attribute::resource > resource );
769 
770  static bool
772  adios2::IO & IO,
773  std::string name,
774  std::vector< T > val )
775  {
776  auto attr = IO.InquireAttribute< T >( name );
777  if( !attr )
778  {
779  return false;
780  }
781  std::vector< T > data = attr.Data();
782  if( data.size() != val.size() )
783  {
784  return false;
785  }
786  for( size_t i = 0; i < val.size(); ++i )
787  {
788  if( data[ i ] != val[ i ] )
789  {
790  return false;
791  }
792  }
793  return true;
794  }
795  };
796 
797  template<>
798  struct AttributeTypes< std::vector< std::string > >
799  {
800  static void
801  oldCreateAttribute(
802  adios2::IO & IO,
803  std::string name,
804  const std::vector< std::string > & value );
805 
806  static void
807  oldReadAttribute(
808  adios2::IO & IO,
809  std::string name,
810  std::shared_ptr< Attribute::resource > resource );
811 
812  static void
813  createAttribute(
814  adios2::IO & IO,
815  adios2::Engine & engine,
817  const std::vector< std::string > & vec );
818 
819  static void
820  readAttribute(
822  std::string name,
823  std::shared_ptr< Attribute::resource > resource );
824 
825  static bool
827  adios2::IO & IO,
828  std::string name,
829  std::vector< std::string > val )
830  {
831  auto attr = IO.InquireAttribute< std::string >( name );
832  if( !attr )
833  {
834  return false;
835  }
836  std::vector< std::string > data = attr.Data();
837  if( data.size() != val.size() )
838  {
839  return false;
840  }
841  for( size_t i = 0; i < val.size(); ++i )
842  {
843  if( data[ i ] != val[ i ] )
844  {
845  return false;
846  }
847  }
848  return true;
849  }
850  };
851 
852  template < typename T, size_t n >
853  struct AttributeTypes< std::array< T, n > >
854  {
855  static void
856  oldCreateAttribute(
857  adios2::IO & IO,
858  std::string name,
859  const std::array< T, n > & value );
860 
861  static void
862  oldReadAttribute(
863  adios2::IO & IO,
864  std::string name,
865  std::shared_ptr< Attribute::resource > resource );
866 
867  static void
868  createAttribute(
869  adios2::IO & IO,
870  adios2::Engine & engine,
872  const std::array< T, n > & value );
873 
874  static void
875  readAttribute(
877  std::string name,
878  std::shared_ptr< Attribute::resource > resource );
879 
880  static bool
882  adios2::IO & IO,
883  std::string name,
884  std::array< T, n > val )
885  {
886  auto attr = IO.InquireAttribute< T >( name );
887  if( !attr )
888  {
889  return false;
890  }
891  std::vector< T > data = attr.Data();
892  if( data.size() != n )
893  {
894  return false;
895  }
896  for( size_t i = 0; i < n; ++i )
897  {
898  if( data[ i ] != val[ i ] )
899  {
900  return false;
901  }
902  }
903  return true;
904  }
905  };
906 
907  template <> struct AttributeTypes< bool >
908  {
909  using rep = detail::bool_representation;
910 
911  static void
912  oldCreateAttribute( adios2::IO & IO, std::string name, bool value );
913 
914  static void
915  oldReadAttribute(
916  adios2::IO & IO,
917  std::string name,
918  std::shared_ptr< Attribute::resource > resource );
919 
920  static void
921  createAttribute(
922  adios2::IO & IO,
923  adios2::Engine & engine,
925  bool value );
926 
927  static void
928  readAttribute(
930  std::string name,
931  std::shared_ptr< Attribute::resource > resource );
932 
933 
934  static constexpr rep toRep( bool b )
935  {
936  return b ? 1U : 0U;
937  }
938 
939 
940  static constexpr bool fromRep( rep r )
941  {
942  return r != 0;
943  }
944 
945  static bool
946  attributeUnchanged( adios2::IO & IO, std::string name, bool val )
947  {
948  auto attr = IO.InquireAttribute< rep >( name );
949  if( !attr )
950  {
951  return false;
952  }
953  std::vector< rep > data = attr.Data();
954  if( data.size() != 1 )
955  {
956  return false;
957  }
958  return data[ 0 ] == toRep( val );
959  }
960  };
961 
962  // Other datatypes used in the ADIOS2IOHandler implementation
963 
964 
965  struct BufferedActions;
966 
967  /*
968  * IO-heavy action to be executed upon flushing.
969  */
971  {
972  explicit BufferedAction( ) = default;
973  virtual ~BufferedAction( ) = default;
974 
975  BufferedAction( BufferedAction const & other ) = delete;
976  BufferedAction( BufferedAction && other ) = default;
977 
978  BufferedAction & operator=( BufferedAction const & other ) = delete;
979  BufferedAction & operator=( BufferedAction && other ) = default;
980 
981  virtual void run( BufferedActions & ) = 0;
982  };
983 
985  {
986  std::string name;
988 
989  void run( BufferedActions & ) override;
990  };
991 
993  {
994  std::string name;
996 
997  void run( BufferedActions & ) override;
998  };
999 
1001  {
1003  std::string name;
1004 
1005  void run( BufferedActions & ) override;
1006  };
1007 
1009  {
1011  std::string name;
1012 
1013  void
1014  run( BufferedActions & );
1015  };
1016 
1018  {
1019  std::string name;
1020  Datatype dtype;
1021  Attribute::resource resource;
1022  std::vector< char > bufferForVecString;
1023 
1024  void run( BufferedActions & ) override;
1025  };
1026 
1028  {
1029  virtual void *update() = 0;
1030  virtual ~I_UpdateSpan() = default;
1031  };
1032 
1033  template< typename T >
1035  {
1036  adios2::detail::Span< T > span;
1037 
1038  UpdateSpan( adios2::detail::Span< T > );
1039 
1040  void *update() override;
1041  };
1042 
1043  /*
1044  * Manages per-file information about
1045  * (1) the file's IO and Engine objects
1046  * (2) the file's deferred IO-heavy actions
1047  */
1049  {
1050  BufferedActions( BufferedActions const & ) = delete;
1051 
1059  std::string m_file;
1078  std::string const m_IOName;
1079  adios2::ADIOS & m_ADIOS;
1080  adios2::IO m_IO;
1085  std::vector< std::unique_ptr< BufferedAction > > m_buffer;
1096  std::map< std::string, BufferedAttributeWrite > m_attributeWrites;
1102  std::vector< BufferedAttributeRead > m_attributeReads;
1109  std::vector< std::unique_ptr< BufferedAction > > m_alreadyEnqueued;
1110  adios2::Mode m_mode;
1119  std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans;
1120  detail::WriteDataset const m_writeDataset;
1121  detail::DatasetReader const m_readDataset;
1122  detail::AttributeReader const m_attributeReader;
1123  PreloadAdiosAttributes preloadAttributes;
1124 
1125  /*
1126  * We call an attribute committed if the step during which it was
1127  * written has been closed.
1128  * A committed attribute cannot be modified.
1129  */
1130  std::set< std::string > uncommittedAttributes;
1131 
1132  /*
1133  * The openPMD API will generally create new attributes for each
1134  * iteration. This results in a growing number of attributes over time.
1135  * In streaming-based modes, these will be completely sent anew in each
1136  * iteration. If the following boolean is true, old attributes will be
1137  * removed upon CLOSE_GROUP.
1138  * Should not be set to true in persistent backends.
1139  * Will be automatically set by BufferedActions::configure_IO depending
1140  * on chosen ADIOS2 engine and can not be explicitly overridden by user.
1141  */
1142  bool optimizeAttributesStreaming = false;
1143 
1144  using AttributeMap_t = std::map< std::string, adios2::Params >;
1145 
1147 
1148  ~BufferedActions( );
1149 
1154  void
1155  finalize();
1156 
1157  adios2::Engine & getEngine( );
1158  adios2::Engine & requireActiveStep( );
1159 
1160  template < typename BA > void enqueue( BA && ba );
1161 
1162  template < typename BA > void enqueue( BA && ba, decltype( m_buffer ) & );
1163 
1180  template< typename F >
1181  void
1182  flush(
1183  FlushLevel level,
1184  F && performPutsGets,
1185  bool writeAttributes,
1186  bool flushUnconditionally );
1187 
1193  void
1194  flush( FlushLevel, bool writeAttributes = false );
1195 
1203  advance( AdvanceMode mode );
1204 
1205  /*
1206  * Delete all buffered actions without running them.
1207  */
1208  void drop( );
1209 
1210  AttributeMap_t const &
1211  availableAttributes();
1212 
1213  std::vector< std::string >
1214  availableAttributesPrefixed( std::string const & prefix );
1215 
1216  /*
1217  * See description below.
1218  */
1219  void
1220  invalidateAttributesMap();
1221 
1222  AttributeMap_t const &
1223  availableVariables();
1224 
1225  std::vector< std::string >
1226  availableVariablesPrefixed( std::string const & prefix );
1227 
1228  /*
1229  * See description below.
1230  */
1231  void
1232  invalidateVariablesMap();
1233 
1234  private:
1235  ADIOS2IOHandlerImpl * m_impl;
1237 
1240  std::string m_engineType;
1241  /*
1242  * streamStatus is NoStream for file-based ADIOS engines.
1243  * This is relevant for the method BufferedActions::requireActiveStep,
1244  * where a step is only opened if the status is OutsideOfStep, but not
1245  * if NoStream. The rationale behind this is that parsing a Series
1246  * works differently for file-based and for stream-based engines:
1247  * * stream-based: Iterations are parsed as they arrive. For parsing an
1248  * iteration, the iteration must be awaited.
1249  * BufferedActions::requireActiveStep takes care of this.
1250  * * file-based: The Series is parsed up front. If no step has been
1251  * opened yet, ADIOS2 gives access to all variables and attributes
1252  * from all steps. Upon opening a step, only the variables from that
1253  * step are shown which hinders parsing. So, until a step is
1254  * explicitly opened via ADIOS2IOHandlerImpl::advance, do not open
1255  * one.
1256  * This is to enable use of ADIOS files without the Streaming API
1257  * (i.e. all iterations should be visible to the user upon opening
1258  * the Series.)
1259  * @todo Add a workflow without up-front parsing of all iterations
1260  * for file-based engines.
1261  * (This would merely be an optimization since the streaming
1262  * API still works with files as intended.)
1263  *
1264  */
1265  enum class StreamStatus
1266  {
1270  DuringStep,
1274  OutsideOfStep,
1278  StreamOver,
1295  NoStream,
1322  Parsing,
1328  Undecided
1329  };
1330  StreamStatus streamStatus = StreamStatus::OutsideOfStep;
1331  adios2::StepStatus m_lastStepStatus = adios2::StepStatus::OK;
1332 
1338  bool delayOpeningTheFirstStep = false;
1339 
1340  /*
1341  * ADIOS2 does not give direct access to its internal attribute and
1342  * variable maps, but will instead give access to copies of them.
1343  * In order to avoid unnecessary copies, we buffer the returned map.
1344  * The downside of this is that we need to pay attention to invalidate
1345  * the map whenever an attribute/variable is altered. In that case, we
1346  * fetch the map anew.
1347  * If empty, the buffered map has been invalidated and needs to be
1348  * queried from ADIOS2 again. If full, the buffered map is equivalent to
1349  * the map that would be returned by a call to
1350  * IO::Available(Attributes|Variables).
1351  */
1352  auxiliary::Option< AttributeMap_t > m_availableAttributes;
1353  auxiliary::Option< AttributeMap_t > m_availableVariables;
1354 
1355  /*
1356  * finalize() will set this true to avoid running twice.
1357  */
1358  bool finalized = false;
1359 
1360  inline SupportedSchema schema() const
1361  {
1362  return m_impl->schema();
1363  }
1364 
1365  void
1366  configure_IO( ADIOS2IOHandlerImpl & impl );
1367 
1368  using AttributeLayout = ADIOS2IOHandlerImpl::AttributeLayout;
1369  inline AttributeLayout attributeLayout() const
1370  {
1371  return m_impl->attributeLayout();
1372  }
1373  };
1374 
1375 } // namespace detail
1376 #endif // openPMD_HAVE_ADIOS2
1377 
1378 
1380 {
1381 #if openPMD_HAVE_ADIOS2
1382 
1383 friend class ADIOS2IOHandlerImpl;
1384 
1385 private:
1386  ADIOS2IOHandlerImpl m_impl;
1387 
1388 public:
1389  ~ADIOS2IOHandler( ) override
1390  {
1391  // we must not throw in a destructor
1392  try
1393  {
1394  this->flush( );
1395  }
1396  catch( std::exception const & ex )
1397  {
1398  std::cerr << "[~ADIOS2IOHandler] An error occurred: " << ex.what() << std::endl;
1399  }
1400  catch( ... )
1401  {
1402  std::cerr << "[~ADIOS2IOHandler] An error occurred." << std::endl;
1403  }
1404  }
1405 
1406 #else
1407 public:
1408 #endif
1409 
1410 #if openPMD_HAVE_MPI
1411 
1413  std::string path,
1414  Access,
1415  MPI_Comm,
1416  nlohmann::json options,
1417  std::string engineType );
1418 
1419 #endif
1420 
1422  std::string path,
1423  Access,
1424  nlohmann::json options,
1425  std::string engineType );
1426 
1427  std::string backendName() const override { return "ADIOS2"; }
1428 
1429  std::future< void > flush( ) override;
1430 }; // ADIOS2IOHandler
1431 } // namespace openPMD
openPMD::Parameter< Operation::CLOSE_FILE >
Definition: IOTask.hpp:149
openPMD::Datatype
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
openPMD::Parameter< Operation::LIST_ATTS >
Definition: IOTask.hpp:514
openPMD::Writable
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:64
openPMD::detail::BufferedActions::advance
AdvanceStatus advance(AdvanceMode mode)
Begin or end an ADIOS step.
Definition: ADIOS2IOHandler.cpp:2718
openPMD::Parameter< Operation::GET_BUFFER_VIEW >
Definition: IOTask.hpp:420
openPMD::Parameter< Operation::ADVANCE >
Definition: IOTask.hpp:532
openPMD::detail::PreloadAdiosAttributes
Class that is responsible for scheduling and buffering openPMD attribute loads from ADIOS2,...
Definition: ADIOS2PreloadAttributes.hpp:63
openPMD::AbstractIOHandlerImplCommon
Definition: Writable.hpp:45
openPMD::detail::BufferedActions::finalize
void finalize()
Implementation of destructor, will only run once.
Definition: ADIOS2IOHandler.cpp:2210
openPMD::Parameter< Operation::READ_DATASET >
Definition: IOTask.hpp:373
openPMD::Parameter< Operation::DELETE_FILE >
Definition: IOTask.hpp:163
openPMD::Parameter< Operation::WRITE_ATT >
Definition: IOTask.hpp:467
openPMD::auxiliary::TracingJSON::json
nlohmann::json & json()
Access the underlying JSON value.
Definition: JSON.hpp:64
openPMD::Parameter< Operation::AVAILABLE_CHUNKS >
Definition: IOTask.hpp:555
openPMD::ADIOS2IOHandler::backendName
std::string backendName() const override
The currently used backend.
Definition: ADIOS2IOHandler.hpp:1427
openPMD::Parameter< Operation::CREATE_FILE >
Definition: IOTask.hpp:108
openPMD::IterationEncoding
IterationEncoding
Encoding scheme of an Iterations Series'.
Definition: IterationEncoding.hpp:32
openPMD::detail::BufferedActions
Definition: ADIOS2IOHandler.hpp:1048
openPMD::detail::DatasetReader
Definition: ADIOS2IOHandler.hpp:435
openPMD::detail::BufferedActions::m_attributeReads
std::vector< BufferedAttributeRead > m_attributeReads
Definition: ADIOS2IOHandler.hpp:1102
openPMD::detail::BufferedActions::m_file
std::string m_file
The full path to the file created on disk, including the containing directory and the file extension,...
Definition: ADIOS2IOHandler.hpp:1059
openPMD::InvalidatableFile
Wrapper around a shared pointer to:
Definition: InvalidatableFile.hpp:45
openPMD::Parameter< Operation::DELETE_PATH >
Definition: IOTask.hpp:233
openPMD::Parameter< Operation::WRITE_DATASET >
Definition: IOTask.hpp:344
openPMD::UnitDimension::T
@ T
time
openPMD::detail::DatasetTypes
Definition: ADIOS2IOHandler.hpp:75
openPMD::Parameter< Operation::LIST_PATHS >
Definition: IOTask.hpp:249
openPMD::AdvanceStatus
AdvanceStatus
In step-based mode (i.e.
Definition: Streaming.hpp:20
openPMD::AbstractIOHandlerImplCommon< ADIOS2FilePosition >::fullPath
std::string fullPath(InvalidatableFile)
Definition: AbstractIOHandlerImplCommon.hpp:181
openPMD::AbstractIOHandler
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:98
openPMD::Parameter< Operation::LIST_DATASETS >
Definition: IOTask.hpp:402
openPMD::ADIOS2IOHandler::flush
std::future< void > flush() override
Process operations in queue according to FIFO.
Definition: ADIOS2IOHandler.cpp:2942
openPMD::auxiliary::Option
Simple Option type based on variantSrc::variant.
Definition: Option.hpp:47
openPMD::detail::OldAttributeWriter
Definition: ADIOS2IOHandler.hpp:465
openPMD::detail::WriteDataset
Definition: ADIOS2IOHandler.hpp:521
openPMD::ADIOS2IOHandlerImpl::adios2AccessMode
adios2::Mode adios2AccessMode(std::string const &fullPath)
The ADIOS2 access type to chose for Engines opened within this instance.
Definition: ADIOS2IOHandler.cpp:1062
openPMD::detail::I_UpdateSpan
Definition: ADIOS2IOHandler.hpp:1027
openPMD::ADIOS2IOHandlerImpl
Definition: ADIOS2IOHandler.hpp:105
openPMD::detail::BufferedAttributeWrite
Definition: ADIOS2IOHandler.hpp:1017
openPMD::detail::RetrieveBlocksInfo
Definition: ADIOS2IOHandler.hpp:567
openPMD::detail::BufferedActions::m_alreadyEnqueued
std::vector< std::unique_ptr< BufferedAction > > m_alreadyEnqueued
This contains deferred actions that have already been enqueued into ADIOS2, but not yet performed in ...
Definition: ADIOS2IOHandler.hpp:1109
openPMD::detail::BufferedPut
Definition: ADIOS2IOHandler.hpp:992
openPMD
Public definitions of openPMD-api.
Definition: Date.cpp:29
openPMD::Parameter< Operation::EXTEND_DATASET >
Definition: IOTask.hpp:291
openPMD::Parameter< Operation::DELETE_ATT >
Definition: IOTask.hpp:451
openPMD::detail::BufferedActions::m_buffer
std::vector< std::unique_ptr< BufferedAction > > m_buffer
The default queue for deferred actions.
Definition: ADIOS2IOHandler.hpp:1085
openPMD::Parameter< Operation::OPEN_DATASET >
Definition: IOTask.hpp:307
openPMD::detail::BufferedActions::m_updateSpans
std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans
The base pointer of an ADIOS2 span might change after reallocations.
Definition: ADIOS2IOHandler.hpp:1119
openPMD::detail::BufferedGet
Definition: ADIOS2IOHandler.hpp:984
openPMD::Parameter< Operation::DELETE_DATASET >
Definition: IOTask.hpp:328
openPMD::Parameter< Operation::CREATE_DATASET >
Definition: IOTask.hpp:266
openPMD::detail::DatasetOpener
Definition: ADIOS2IOHandler.hpp:506
openPMD::Parameter< Operation::CREATE_PATH >
Definition: IOTask.hpp:179
openPMD::detail::BufferedAttributeRead
Definition: ADIOS2IOHandler.hpp:1008
openPMD::detail::AttributeTypes::attributeUnchanged
static bool attributeUnchanged(adios2::IO &IO, std::string name, T val)
Is the attribute given by parameters name and val already defined exactly in that way within the give...
Definition: ADIOS2IOHandler.hpp:621
openPMD::detail::DatasetHelper
Definition: ADIOS2IOHandler.hpp:65
openPMD::ADIOS2IOHandler
Definition: ADIOS2IOHandler.hpp:1379
openPMD::AdvanceMode
AdvanceMode
In step-based mode (i.e.
Definition: Streaming.hpp:33
openPMD::detail::BufferedActions::m_attributeWrites
std::map< std::string, BufferedAttributeWrite > m_attributeWrites
Buffer for attributes to be written in the new (variable-based) attribute layout.
Definition: ADIOS2IOHandler.hpp:1096
openPMD::detail::VariableDefiner
Definition: ADIOS2IOHandler.hpp:536
openPMD::detail::OldBufferedAttributeRead
Definition: ADIOS2IOHandler.hpp:1000
openPMD::auxiliary::TracingJSON
Extend nlohmann::json with tracing of which keys have been accessed by operator[]().
Definition: JSON.hpp:52
openPMD::detail::AttributeWriter
Definition: ADIOS2IOHandler.hpp:494
openPMD::detail::GetSpan
Definition: ADIOS2IOHandler.cpp:661
openPMD::detail::BufferedAction
Definition: ADIOS2IOHandler.hpp:970
openPMD::Access
Access
File access mode to use during IO.
Definition: Access.hpp:28
openPMD::detail::AttributeReader
Definition: ADIOS2IOHandler.hpp:480
openPMD::detail::OldAttributeReader
Definition: ADIOS2IOHandler.hpp:451
openPMD::Parameter< Operation::OPEN_PATH >
Definition: IOTask.hpp:217
openPMD::detail::BufferedActions::flush
void flush(FlushLevel level, F &&performPutsGets, bool writeAttributes, bool flushUnconditionally)
Flush deferred IO actions.
Definition: ADIOS2IOHandler.cpp:2590
openPMD::Parameter< Operation::CLOSE_PATH >
Definition: IOTask.hpp:195
openPMD::Parameter< Operation::OPEN_FILE >
Definition: IOTask.hpp:126
openPMD::FlushLevel
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:63
openPMD::Parameter< Operation::READ_ATT >
Definition: IOTask.hpp:486
openPMD::detail::BufferedActions::m_IOName
const std::string m_IOName
ADIOS requires giving names to instances of adios2::IO.
Definition: ADIOS2IOHandler.hpp:1078
openPMD::detail::AttributeTypes
Definition: ADIOS2IOHandler.hpp:72
openPMD::detail::UpdateSpan
Definition: ADIOS2IOHandler.hpp:1034