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 UseSpan : char
240  {
241  Yes,
242  No,
243  Auto
244  };
245 
246  UseSpan m_useSpanBasedPutByDefault = UseSpan::Auto;
247 
248  enum class AttributeLayout : char
249  {
250  ByAdiosAttributes,
251  ByAdiosVariables
252  };
253 
254  inline SupportedSchema schema() const
255  {
256  switch( m_schema )
257  {
258  case ADIOS2Schema::schema_0000_00_00:
259  return SupportedSchema::s_0000_00_00;
260  case ADIOS2Schema::schema_2021_02_09:
261  return SupportedSchema::s_2021_02_09;
262  default:
263  throw std::runtime_error(
264  "[ADIOS2] Encountered unsupported schema version: " +
265  std::to_string( m_schema ) );
266  }
267  }
268 
269  inline AttributeLayout attributeLayout() const
270  {
271  switch( schema() )
272  {
273  case SupportedSchema::s_0000_00_00:
274  return AttributeLayout::ByAdiosAttributes;
275  case SupportedSchema::s_2021_02_09:
276  return AttributeLayout::ByAdiosVariables;
277  }
278  throw std::runtime_error( "Unreachable!" );
279  }
280 
281  struct ParameterizedOperator
282  {
283  adios2::Operator op;
284  adios2::Params params;
285  };
286 
287  std::vector< ParameterizedOperator > defaultOperators;
288 
289  auxiliary::TracingJSON m_config;
290  static auxiliary::TracingJSON nullvalue;
291 
292  void
293  init( nlohmann::json config );
294 
295  template< typename Key >
297  config( Key && key, auxiliary::TracingJSON & cfg )
298  {
299  if( cfg.json().is_object() && cfg.json().contains( key ) )
300  {
301  return cfg[ key ];
302  }
303  else
304  {
305  return nullvalue;
306  }
307  }
308 
309  template< typename Key >
311  config( Key && key )
312  {
313  return config< Key >( std::forward< Key >( key ), m_config );
314  }
315 
324  getOperators( auxiliary::TracingJSON config );
325 
326  // use m_config
328  getOperators();
329 
330  std::string
331  fileSuffix() const;
332 
333  /*
334  * We need to give names to IO objects. These names are irrelevant
335  * within this application, since:
336  * 1) The name of the file written to is decided by the opened Engine's
337  * name.
338  * 2) The IOs are managed by the unordered_map m_fileData, so we do not
339  * need the ADIOS2 internal management.
340  * Since within one m_ADIOS object, the same IO name cannot be used more
341  * than once, we ensure different names by using the name counter.
342  * This allows to overwrite a file later without error.
343  */
344  int nameCounter{0};
345 
346  /*
347  * IO-heavy actions are deferred to a later point. This map stores for
348  * each open file (identified by an InvalidatableFile object) an object
349  * that manages IO-heavy actions, as well as its ADIOS2 objects, i.e.
350  * IO and Engine object.
351  * Not to be accessed directly, use getFileData().
352  */
353  std::unordered_map< InvalidatableFile,
354  std::unique_ptr< detail::BufferedActions >
355  > m_fileData;
356 
357  std::map< std::string, adios2::Operator > m_operators;
358 
359  // Overrides from AbstractIOHandlerImplCommon.
360 
361  std::string
362  filePositionToString( std::shared_ptr< ADIOS2FilePosition > ) override;
363 
364  std::shared_ptr< ADIOS2FilePosition >
365  extendFilePosition( std::shared_ptr< ADIOS2FilePosition > const & pos,
366  std::string extend ) override;
367 
368  // Helper methods.
369 
371  getCompressionOperator( std::string const & compression );
372 
373  /*
374  * The name of the ADIOS2 variable associated with this Writable.
375  * To be used for Writables that represent a dataset.
376  */
377  std::string nameOfVariable( Writable * writable );
378 
388  std::string nameOfAttribute( Writable * writable, std::string attribute );
389 
390  /*
391  * Figure out whether the Writable corresponds with a
392  * group or a dataset.
393  */
394  ADIOS2FilePosition::GD groupOrDataset( Writable * );
395 
396  enum class IfFileNotOpen : bool
397  {
398  OpenImplicitly,
399  ThrowError
400  };
401 
403  getFileData( InvalidatableFile file, IfFileNotOpen );
404 
405  void dropFileData( InvalidatableFile file );
406 
407  /*
408  * Prepare a variable that already exists for an IO
409  * operation, including:
410  * (1) checking that its datatype matches T.
411  * (2) the offset and extent match the variable's shape
412  * (3) setting the offset and extent (ADIOS lingo: start
413  * and count)
414  */
415  template < typename T >
416  adios2::Variable< T > verifyDataset( Offset const & offset,
417  Extent const & extent, adios2::IO & IO,
418  std::string const & var );
419 }; // ADIOS2IOHandlerImpl
420 
421 /*
422  * The following strings are used during parsing of the JSON configuration
423  * string for the ADIOS2 backend.
424  */
425 namespace ADIOS2Defaults
426 {
427  using const_str = char const * const;
428  constexpr const_str str_engine = "engine";
429  constexpr const_str str_type = "type";
430  constexpr const_str str_params = "parameters";
431  constexpr const_str str_usesteps = "usesteps";
432  constexpr const_str str_usesstepsAttribute = "__openPMD_internal/useSteps";
433  constexpr const_str str_adios2Schema =
434  "__openPMD_internal/openPMD2_adios2_schema";
435  constexpr const_str str_isBooleanOldLayout = "__is_boolean__";
436  constexpr const_str str_isBooleanNewLayout =
437  "__openPMD_internal/is_boolean";
438 } // namespace ADIOS2Defaults
439 
440 namespace detail
441 {
442  // Helper structs for calls to the switchType function
443 
445  {
447 
448 
449  explicit DatasetReader( openPMD::ADIOS2IOHandlerImpl * impl );
450 
451 
452  template < typename T >
453  void operator( )( BufferedGet & bp, adios2::IO & IO,
454  adios2::Engine & engine,
455  std::string const & fileName );
456 
457  std::string errorMsg = "ADIOS2: readDataset()";
458  };
459 
461  {
462  template< typename T >
463  Datatype
464  operator()(
465  adios2::IO & IO,
466  std::string name,
467  std::shared_ptr< Attribute::resource > resource );
468 
469  template< int n, typename... Params >
470  Datatype
471  operator()( Params &&... );
472  };
473 
475  {
476  template< typename T >
477  void
478  operator()(
479  ADIOS2IOHandlerImpl * impl,
480  Writable * writable,
481  const Parameter< Operation::WRITE_ATT > & parameters );
482 
483 
484  template< int n, typename... Params >
485  void
486  operator()( Params &&... );
487  };
488 
490  {
491  template< typename T >
492  Datatype
493  operator()(
494  adios2::IO & IO,
495  detail::PreloadAdiosAttributes const & preloadedAttributes,
496  std::string name,
497  std::shared_ptr< Attribute::resource > resource );
498 
499  template < int n, typename... Params >
500  Datatype operator( )( Params &&... );
501  };
502 
504  {
505  template < typename T >
506  void
507  operator()(
509  BufferedActions & fileData );
510 
511 
512  template < int n, typename... Params > void operator( )( Params &&... );
513  };
514 
516  {
517  ADIOS2IOHandlerImpl * m_impl;
518 
519  explicit DatasetOpener( ADIOS2IOHandlerImpl * impl );
520 
521 
522  template < typename T >
523  void operator( )( InvalidatableFile, const std::string & varName,
525 
526 
527  std::string errorMsg = "ADIOS2: openDataset()";
528  };
529 
531  {
532  ADIOS2IOHandlerImpl * m_handlerImpl;
533 
534 
535  WriteDataset( ADIOS2IOHandlerImpl * handlerImpl );
536 
537 
538  template < typename T >
539  void operator( )( BufferedPut & bp, adios2::IO & IO,
540  adios2::Engine & engine );
541 
542  template < int n, typename... Params > void operator( )( Params &&... );
543  };
544 
546  {
562  template < typename T >
563  void operator( )(
564  adios2::IO & IO,
565  std::string const & name,
566  std::vector< ADIOS2IOHandlerImpl::ParameterizedOperator > const &
567  compressions,
568  adios2::Dims const & shape = adios2::Dims(),
569  adios2::Dims const & start = adios2::Dims(),
570  adios2::Dims const & count = adios2::Dims(),
571  bool const constantDims = false );
572 
573  std::string errorMsg = "ADIOS2: defineVariable()";
574  };
575 
577  {
578  template < typename T >
579  void operator( )(
581  adios2::IO & IO,
582  adios2::Engine & engine,
583  std::string const & varName );
584 
585  template < int n, typename... Params >
586  void operator( )( Params &&... );
587  };
588 
589  // Helper structs to help distinguish valid attribute/variable
590  // datatypes from invalid ones
591 
592  /*
593  * This struct's purpose is to have specialisations
594  * for vector and array types, as well as the boolean
595  * type (which is not natively supported by ADIOS).
596  */
597  template< typename T >
598  struct AttributeTypes
599  {
600  static void
601  oldCreateAttribute(
602  adios2::IO & IO,
603  std::string name,
604  T value );
605 
606  static void
607  oldReadAttribute(
608  adios2::IO & IO,
609  std::string name,
610  std::shared_ptr< Attribute::resource > resource );
611 
612  static void
613  createAttribute(
614  adios2::IO & IO,
615  adios2::Engine & engine,
617  T value );
618 
619  static void
620  readAttribute(
622  std::string name,
623  std::shared_ptr< Attribute::resource > resource );
624 
629  static bool
630  attributeUnchanged( adios2::IO & IO, std::string name, T val )
631  {
632  auto attr = IO.InquireAttribute< T >( name );
633  if( !attr )
634  {
635  return false;
636  }
637  std::vector< T > data = attr.Data();
638  if( data.size() != 1 )
639  {
640  return false;
641  }
642  return data[ 0 ] == val;
643  }
644  };
645 
646  template< > struct AttributeTypes< std::complex< long double > >
647  {
648  static void
649  oldCreateAttribute(
650  adios2::IO &,
651  std::string,
652  std::complex< long double > )
653  {
654  throw std::runtime_error(
655  "[ADIOS2] Internal error: no support for long double complex attribute types" );
656  }
657 
658  static void
659  oldReadAttribute(
660  adios2::IO &,
661  std::string,
662  std::shared_ptr< Attribute::resource > )
663  {
664  throw std::runtime_error(
665  "[ADIOS2] Internal error: no support for long double complex attribute types" );
666  }
667 
668  static void
669  createAttribute(
670  adios2::IO &,
671  adios2::Engine &,
673  std::complex< long double > )
674  {
675  throw std::runtime_error(
676  "[ADIOS2] Internal error: no support for long double complex attribute types" );
677  }
678 
679  static void
680  readAttribute(
682  std::string,
683  std::shared_ptr< Attribute::resource > )
684  {
685  throw std::runtime_error(
686  "[ADIOS2] Internal error: no support for long double complex attribute types" );
687  }
688 
689  static bool
690  attributeUnchanged(
691  adios2::IO &, std::string, std::complex< long double > )
692  {
693  throw std::runtime_error(
694  "[ADIOS2] Internal error: no support for long double complex attribute types" );
695  }
696  };
697 
698  template< > struct AttributeTypes< std::vector< std::complex< long double > > >
699  {
700  static void
701  oldCreateAttribute(
702  adios2::IO &,
703  std::string,
704  const std::vector< std::complex< long double > > & )
705  {
706  throw std::runtime_error(
707  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
708  }
709 
710  static void
711  oldReadAttribute(
712  adios2::IO &,
713  std::string,
714  std::shared_ptr< Attribute::resource > )
715  {
716  throw std::runtime_error(
717  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
718  }
719 
720  static void
721  createAttribute(
722  adios2::IO &,
723  adios2::Engine &,
725  const std::vector< std::complex< long double > > & )
726  {
727  throw std::runtime_error(
728  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
729  }
730 
731  static void
732  readAttribute(
734  std::string,
735  std::shared_ptr< Attribute::resource > )
736  {
737  throw std::runtime_error(
738  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
739  }
740 
741  static bool
742  attributeUnchanged(
743  adios2::IO &,
744  std::string,
745  std::vector< std::complex< long double > > )
746  {
747  throw std::runtime_error(
748  "[ADIOS2] Internal error: no support for long double complex vector attribute types" );
749  }
750  };
751 
752  template < typename T > struct AttributeTypes< std::vector< T > >
753  {
754  static void
755  oldCreateAttribute(
756  adios2::IO & IO,
757  std::string name,
758  const std::vector< T > & value );
759 
760  static void
761  oldReadAttribute(
762  adios2::IO & IO,
763  std::string name,
764  std::shared_ptr< Attribute::resource > resource );
765 
766  static void
767  createAttribute(
768  adios2::IO & IO,
769  adios2::Engine & engine,
771  const std::vector< T > & value );
772 
773  static void
774  readAttribute(
776  std::string name,
777  std::shared_ptr< Attribute::resource > resource );
778 
779  static bool
780  attributeUnchanged(
781  adios2::IO & IO,
782  std::string name,
783  std::vector< T > val )
784  {
785  auto attr = IO.InquireAttribute< T >( name );
786  if( !attr )
787  {
788  return false;
789  }
790  std::vector< T > data = attr.Data();
791  if( data.size() != val.size() )
792  {
793  return false;
794  }
795  for( size_t i = 0; i < val.size(); ++i )
796  {
797  if( data[ i ] != val[ i ] )
798  {
799  return false;
800  }
801  }
802  return true;
803  }
804  };
805 
806  template<>
807  struct AttributeTypes< std::vector< std::string > >
808  {
809  static void
810  oldCreateAttribute(
811  adios2::IO & IO,
812  std::string name,
813  const std::vector< std::string > & value );
814 
815  static void
816  oldReadAttribute(
817  adios2::IO & IO,
818  std::string name,
819  std::shared_ptr< Attribute::resource > resource );
820 
821  static void
822  createAttribute(
823  adios2::IO & IO,
824  adios2::Engine & engine,
826  const std::vector< std::string > & vec );
827 
828  static void
829  readAttribute(
831  std::string name,
832  std::shared_ptr< Attribute::resource > resource );
833 
834  static bool
835  attributeUnchanged(
836  adios2::IO & IO,
837  std::string name,
838  std::vector< std::string > val )
839  {
840  auto attr = IO.InquireAttribute< std::string >( name );
841  if( !attr )
842  {
843  return false;
844  }
845  std::vector< std::string > data = attr.Data();
846  if( data.size() != val.size() )
847  {
848  return false;
849  }
850  for( size_t i = 0; i < val.size(); ++i )
851  {
852  if( data[ i ] != val[ i ] )
853  {
854  return false;
855  }
856  }
857  return true;
858  }
859  };
860 
861  template < typename T, size_t n >
862  struct AttributeTypes< std::array< T, n > >
863  {
864  static void
865  oldCreateAttribute(
866  adios2::IO & IO,
867  std::string name,
868  const std::array< T, n > & value );
869 
870  static void
871  oldReadAttribute(
872  adios2::IO & IO,
873  std::string name,
874  std::shared_ptr< Attribute::resource > resource );
875 
876  static void
877  createAttribute(
878  adios2::IO & IO,
879  adios2::Engine & engine,
881  const std::array< T, n > & value );
882 
883  static void
884  readAttribute(
886  std::string name,
887  std::shared_ptr< Attribute::resource > resource );
888 
889  static bool
890  attributeUnchanged(
891  adios2::IO & IO,
892  std::string name,
893  std::array< T, n > val )
894  {
895  auto attr = IO.InquireAttribute< T >( name );
896  if( !attr )
897  {
898  return false;
899  }
900  std::vector< T > data = attr.Data();
901  if( data.size() != n )
902  {
903  return false;
904  }
905  for( size_t i = 0; i < n; ++i )
906  {
907  if( data[ i ] != val[ i ] )
908  {
909  return false;
910  }
911  }
912  return true;
913  }
914  };
915 
916  template <> struct AttributeTypes< bool >
917  {
918  using rep = detail::bool_representation;
919 
920  static void
921  oldCreateAttribute( adios2::IO & IO, std::string name, bool value );
922 
923  static void
924  oldReadAttribute(
925  adios2::IO & IO,
926  std::string name,
927  std::shared_ptr< Attribute::resource > resource );
928 
929  static void
930  createAttribute(
931  adios2::IO & IO,
932  adios2::Engine & engine,
934  bool value );
935 
936  static void
937  readAttribute(
939  std::string name,
940  std::shared_ptr< Attribute::resource > resource );
941 
942 
943  static constexpr rep toRep( bool b )
944  {
945  return b ? 1U : 0U;
946  }
947 
948 
949  static constexpr bool fromRep( rep r )
950  {
951  return r != 0;
952  }
953 
954  static bool
955  attributeUnchanged( adios2::IO & IO, std::string name, bool val )
956  {
957  auto attr = IO.InquireAttribute< rep >( name );
958  if( !attr )
959  {
960  return false;
961  }
962  std::vector< rep > data = attr.Data();
963  if( data.size() != 1 )
964  {
965  return false;
966  }
967  return data[ 0 ] == toRep( val );
968  }
969  };
970 
971  // Other datatypes used in the ADIOS2IOHandler implementation
972 
973 
974  struct BufferedActions;
975 
976  /*
977  * IO-heavy action to be executed upon flushing.
978  */
980  {
981  explicit BufferedAction( ) = default;
982  virtual ~BufferedAction( ) = default;
983 
984  BufferedAction( BufferedAction const & other ) = delete;
985  BufferedAction( BufferedAction && other ) = default;
986 
987  BufferedAction & operator=( BufferedAction const & other ) = delete;
988  BufferedAction & operator=( BufferedAction && other ) = default;
989 
990  virtual void run( BufferedActions & ) = 0;
991  };
992 
994  {
995  std::string name;
997 
998  void run( BufferedActions & ) override;
999  };
1000 
1002  {
1003  std::string name;
1005 
1006  void run( BufferedActions & ) override;
1007  };
1008 
1010  {
1012  std::string name;
1013 
1014  void run( BufferedActions & ) override;
1015  };
1016 
1018  {
1020  std::string name;
1021 
1022  void
1023  run( BufferedActions & );
1024  };
1025 
1027  {
1028  std::string name;
1029  Datatype dtype;
1030  Attribute::resource resource;
1031  std::vector< char > bufferForVecString;
1032 
1033  void run( BufferedActions & ) override;
1034  };
1035 
1037  {
1038  virtual void *update() = 0;
1039  virtual ~I_UpdateSpan() = default;
1040  };
1041 
1042  template< typename T >
1044  {
1045  adios2::detail::Span< T > span;
1046 
1047  UpdateSpan( adios2::detail::Span< T > );
1048 
1049  void *update() override;
1050  };
1051 
1052  /*
1053  * Manages per-file information about
1054  * (1) the file's IO and Engine objects
1055  * (2) the file's deferred IO-heavy actions
1056  */
1058  {
1059  BufferedActions( BufferedActions const & ) = delete;
1060 
1068  std::string m_file;
1087  std::string const m_IOName;
1088  adios2::ADIOS & m_ADIOS;
1089  adios2::IO m_IO;
1094  std::vector< std::unique_ptr< BufferedAction > > m_buffer;
1105  std::map< std::string, BufferedAttributeWrite > m_attributeWrites;
1111  std::vector< BufferedAttributeRead > m_attributeReads;
1118  std::vector< std::unique_ptr< BufferedAction > > m_alreadyEnqueued;
1119  adios2::Mode m_mode;
1128  std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans;
1129  detail::WriteDataset const m_writeDataset;
1130  detail::DatasetReader const m_readDataset;
1131  detail::AttributeReader const m_attributeReader;
1132  PreloadAdiosAttributes preloadAttributes;
1133 
1134  /*
1135  * We call an attribute committed if the step during which it was
1136  * written has been closed.
1137  * A committed attribute cannot be modified.
1138  */
1139  std::set< std::string > uncommittedAttributes;
1140 
1141  /*
1142  * The openPMD API will generally create new attributes for each
1143  * iteration. This results in a growing number of attributes over time.
1144  * In streaming-based modes, these will be completely sent anew in each
1145  * iteration. If the following boolean is true, old attributes will be
1146  * removed upon CLOSE_GROUP.
1147  * Should not be set to true in persistent backends.
1148  * Will be automatically set by BufferedActions::configure_IO depending
1149  * on chosen ADIOS2 engine and can not be explicitly overridden by user.
1150  */
1151  bool optimizeAttributesStreaming = false;
1152 
1153  using AttributeMap_t = std::map< std::string, adios2::Params >;
1154 
1156 
1157  ~BufferedActions( );
1158 
1163  void
1164  finalize();
1165 
1166  adios2::Engine & getEngine( );
1167  adios2::Engine & requireActiveStep( );
1168 
1169  template < typename BA > void enqueue( BA && ba );
1170 
1171  template < typename BA > void enqueue( BA && ba, decltype( m_buffer ) & );
1172 
1189  template< typename F >
1190  void
1191  flush(
1192  FlushLevel level,
1193  F && performPutsGets,
1194  bool writeAttributes,
1195  bool flushUnconditionally );
1196 
1202  void
1203  flush( FlushLevel, bool writeAttributes = false );
1204 
1212  advance( AdvanceMode mode );
1213 
1214  /*
1215  * Delete all buffered actions without running them.
1216  */
1217  void drop( );
1218 
1219  AttributeMap_t const &
1220  availableAttributes();
1221 
1222  std::vector< std::string >
1223  availableAttributesPrefixed( std::string const & prefix );
1224 
1225  /*
1226  * See description below.
1227  */
1228  void
1229  invalidateAttributesMap();
1230 
1231  AttributeMap_t const &
1232  availableVariables();
1233 
1234  std::vector< std::string >
1235  availableVariablesPrefixed( std::string const & prefix );
1236 
1237  /*
1238  * See description below.
1239  */
1240  void
1241  invalidateVariablesMap();
1242 
1243  private:
1244  ADIOS2IOHandlerImpl * m_impl;
1246 
1249  std::string m_engineType;
1250  /*
1251  * streamStatus is NoStream for file-based ADIOS engines.
1252  * This is relevant for the method BufferedActions::requireActiveStep,
1253  * where a step is only opened if the status is OutsideOfStep, but not
1254  * if NoStream. The rationale behind this is that parsing a Series
1255  * works differently for file-based and for stream-based engines:
1256  * * stream-based: Iterations are parsed as they arrive. For parsing an
1257  * iteration, the iteration must be awaited.
1258  * BufferedActions::requireActiveStep takes care of this.
1259  * * file-based: The Series is parsed up front. If no step has been
1260  * opened yet, ADIOS2 gives access to all variables and attributes
1261  * from all steps. Upon opening a step, only the variables from that
1262  * step are shown which hinders parsing. So, until a step is
1263  * explicitly opened via ADIOS2IOHandlerImpl::advance, do not open
1264  * one.
1265  * This is to enable use of ADIOS files without the Streaming API
1266  * (i.e. all iterations should be visible to the user upon opening
1267  * the Series.)
1268  * @todo Add a workflow without up-front parsing of all iterations
1269  * for file-based engines.
1270  * (This would merely be an optimization since the streaming
1271  * API still works with files as intended.)
1272  *
1273  */
1274  enum class StreamStatus
1275  {
1279  DuringStep,
1283  OutsideOfStep,
1287  StreamOver,
1304  NoStream,
1331  Parsing,
1337  Undecided
1338  };
1339  StreamStatus streamStatus = StreamStatus::OutsideOfStep;
1340  adios2::StepStatus m_lastStepStatus = adios2::StepStatus::OK;
1341 
1347  bool delayOpeningTheFirstStep = false;
1348 
1349  /*
1350  * ADIOS2 does not give direct access to its internal attribute and
1351  * variable maps, but will instead give access to copies of them.
1352  * In order to avoid unnecessary copies, we buffer the returned map.
1353  * The downside of this is that we need to pay attention to invalidate
1354  * the map whenever an attribute/variable is altered. In that case, we
1355  * fetch the map anew.
1356  * If empty, the buffered map has been invalidated and needs to be
1357  * queried from ADIOS2 again. If full, the buffered map is equivalent to
1358  * the map that would be returned by a call to
1359  * IO::Available(Attributes|Variables).
1360  */
1361  auxiliary::Option< AttributeMap_t > m_availableAttributes;
1362  auxiliary::Option< AttributeMap_t > m_availableVariables;
1363 
1364  /*
1365  * finalize() will set this true to avoid running twice.
1366  */
1367  bool finalized = false;
1368 
1369  inline SupportedSchema schema() const
1370  {
1371  return m_impl->schema();
1372  }
1373 
1374  void
1375  configure_IO( ADIOS2IOHandlerImpl & impl );
1376 
1377  using AttributeLayout = ADIOS2IOHandlerImpl::AttributeLayout;
1378  inline AttributeLayout attributeLayout() const
1379  {
1380  return m_impl->attributeLayout();
1381  }
1382  };
1383 
1384 } // namespace detail
1385 #endif // openPMD_HAVE_ADIOS2
1386 
1387 
1389 {
1390 #if openPMD_HAVE_ADIOS2
1391 
1392 friend class ADIOS2IOHandlerImpl;
1393 
1394 private:
1395  ADIOS2IOHandlerImpl m_impl;
1396 
1397 public:
1398  ~ADIOS2IOHandler( ) override
1399  {
1400  // we must not throw in a destructor
1401  try
1402  {
1403  this->flush( );
1404  }
1405  catch( std::exception const & ex )
1406  {
1407  std::cerr << "[~ADIOS2IOHandler] An error occurred: " << ex.what() << std::endl;
1408  }
1409  catch( ... )
1410  {
1411  std::cerr << "[~ADIOS2IOHandler] An error occurred." << std::endl;
1412  }
1413  }
1414 
1415 #else
1416 public:
1417 #endif
1418 
1419 #if openPMD_HAVE_MPI
1420 
1422  std::string path,
1423  Access,
1424  MPI_Comm,
1425  nlohmann::json options,
1426  std::string engineType );
1427 
1428 #endif
1429 
1431  std::string path,
1432  Access,
1433  nlohmann::json options,
1434  std::string engineType );
1435 
1436  std::string backendName() const override { return "ADIOS2"; }
1437 
1438  std::future< void > flush( ) override;
1439 }; // ADIOS2IOHandler
1440 } // namespace openPMD
Definition: ADIOS2IOHandler.hpp:65
Wrapper around a shared pointer to:
Definition: InvalidatableFile.hpp:45
Definition: ADIOS2IOHandler.hpp:576
Definition: ADIOS2IOHandler.hpp:1036
std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans
The base pointer of an ADIOS2 span might change after reallocations.
Definition: ADIOS2IOHandler.hpp:1128
Definition: ADIOS2IOHandler.hpp:1017
Definition: ADIOS2IOHandler.hpp:474
Definition: ADIOS2IOHandler.hpp:489
Access
File access mode to use during IO.
Definition: Access.hpp:28
Definition: ADIOS2IOHandler.hpp:545
STL namespace.
std::string m_file
The full path to the file created on disk, including the containing directory and the file extension...
Definition: ADIOS2IOHandler.hpp:1068
Definition: ADIOS2IOHandler.hpp:105
Definition: ADIOS2IOHandler.hpp:1057
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:63
Definition: ADIOS2IOHandler.hpp:1001
Definition: ADIOS2IOHandler.cpp:669
AdvanceStatus
In step-based mode (i.e.
Definition: Streaming.hpp:20
Definition: ADIOS2IOHandler.hpp:75
AdvanceMode
In step-based mode (i.e.
Definition: Streaming.hpp:33
std::vector< std::unique_ptr< BufferedAction > > m_buffer
The default queue for deferred actions.
Definition: ADIOS2IOHandler.hpp:1094
Definition: ADIOS2IOHandler.hpp:1009
std::string const m_IOName
ADIOS requires giving names to instances of adios2::IO.
Definition: ADIOS2IOHandler.hpp:1087
Definition: ADIOS2IOHandler.hpp:993
Definition: ADIOS2IOHandler.hpp:1026
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
Definition: Container.cpp:51
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:98
Simple Option type based on variantSrc::variant.
Definition: Option.hpp:47
Public definitions of openPMD-api.
Definition: Date.cpp:29
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:64
Definition: ADIOS2IOHandler.hpp:1388
Definition: ADIOS2IOHandler.hpp:530
std::string backendName() const override
The currently used backend.
Definition: ADIOS2IOHandler.hpp:1436
Class that is responsible for scheduling and buffering openPMD attribute loads from ADIOS2...
Definition: ADIOS2PreloadAttributes.hpp:63
std::vector< BufferedAttributeRead > m_attributeReads
Definition: ADIOS2IOHandler.hpp:1111
Definition: ADIOS2IOHandler.hpp:503
Extend nlohmann::json with tracing of which keys have been accessed by operator[]().
Definition: JSON.hpp:52
IterationEncoding
Encoding scheme of an Iterations Series&#39;.
Definition: IterationEncoding.hpp:32
Definition: Writable.hpp:45
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:630
Definition: ADIOS2IOHandler.hpp:515
Definition: ADIOS2IOHandler.hpp:444
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:1118
std::map< std::string, BufferedAttributeWrite > m_attributeWrites
Buffer for attributes to be written in the new (variable-based) attribute layout. ...
Definition: ADIOS2IOHandler.hpp:1105
Definition: ADIOS2IOHandler.hpp:1043
nlohmann::json & json()
Access the underlying JSON value.
Definition: JSON.hpp:64
Definition: ADIOS2IOHandler.hpp:72
Definition: ADIOS2IOHandler.hpp:979
Definition: ADIOS2IOHandler.hpp:460