13
13
namespace scream {
14
14
namespace scorpio {
15
15
16
- struct OffsetsVec {
17
- OffsetsVec (int n) : vec(n,-1 ) {}
18
- std::vector<PIO_Offset> vec;
19
- };
20
-
21
16
// This class is an implementation detail, and therefore it is hidden inside
22
17
// a cpp file. All customers of IO capabilities must use the common interfaces
23
18
// exposed in the header file of this source file.
@@ -348,11 +343,9 @@ void init_subsystem(const ekat::Comm& comm, const int atm_id)
348
343
// Unused in standalone mode
349
344
(void ) atm_id;
350
345
#endif
351
- static_assert (std::is_same<PIO_Offset,int >::value or
352
- std::is_same<PIO_Offset,long >::value or
353
- std::is_same<PIO_Offset,long long >::value,
354
- " Error! PIO was configured with PIO_OFFSET not in [int, long, long long]. EAMxx does not support that\n " );
355
346
347
+ static_assert (sizeof (offset_t )==sizeof (PIO_Offset),
348
+ " Error! PIO was configured with PIO_OFFSET not a 64-bit int.\n " );
356
349
}
357
350
358
351
bool is_subsystem_inited () {
@@ -369,19 +362,19 @@ void finalize_subsystem ()
369
362
EKAT_REQUIRE_MSG (s.pio_sysid !=-1 ,
370
363
" Error! PIO subsystem was already finalized.\n " );
371
364
372
- for (const auto & [filename,file] : s.files ) {
373
- EKAT_REQUIRE_MSG (file .num_customers ==0 ,
365
+ for (auto & it : s.files ) {
366
+ EKAT_REQUIRE_MSG (it. second .num_customers ==0 ,
374
367
" Error! ScorpioSession::finalize called, but a file is still in use elsewhere.\n "
375
- " - filename: " + filename + " \n " );
368
+ " - filename: " + it. first + " \n " );
376
369
}
377
370
s.files .clear ();
378
371
379
- for (const auto & [dimname,decomp] : s.decomps ) {
380
- EKAT_REQUIRE_MSG (decomp .use_count ()==1 ,
372
+ for (auto & it : s.decomps ) {
373
+ EKAT_REQUIRE_MSG (it. second .use_count ()==1 ,
381
374
" Error! ScorpioSession::finalize called, but a decomp is still stored elsewhere.\n "
382
- " - decomp name: " + dimname + " \n " );
375
+ " - decomp name: " + it. first + " \n " );
383
376
384
- int err = PIOc_freedecomp (s.pio_sysid ,decomp ->ncid );
377
+ int err = PIOc_freedecomp (s.pio_sysid ,it. second ->ncid );
385
378
check_scorpio_noerr (err," finalize_subsystem" ," freedecomp" );
386
379
}
387
380
s.decomps .clear ();
@@ -464,9 +457,9 @@ void register_file (const std::string& filename,
464
457
465
458
auto find_dim = [&](int dimid) -> std::shared_ptr<const PIODim> {
466
459
std::shared_ptr<const PIODim> d;
467
- for (auto & [dimname,dim] : f.dims ) {
468
- if (dim ->ncid ==dimid) {
469
- d = dim ;
460
+ for (auto it : f.dims ) {
461
+ if (it. second ->ncid ==dimid) {
462
+ d = it. second ;
470
463
}
471
464
}
472
465
EKAT_REQUIRE_MSG (d!=nullptr ,
@@ -685,7 +678,7 @@ int get_dimlen_local (const std::string& filename, const std::string& dimname)
685
678
" - dimname : " + dimname + " \n " );
686
679
687
680
const auto & dim = pf.file ->dims .at (dimname);
688
- return dim->decomposed ? dim->offsets . size () : dim->length ;
681
+ return dim->offsets == nullptr ? dim->length : dim->offsets -> size () ;
689
682
}
690
683
691
684
bool has_time_dim (const std::string& filename)
@@ -737,9 +730,10 @@ void reset_time_dim_len (const std::string& filename, const int new_length)
737
730
f.time_dim ->length = new_length;
738
731
739
732
// Reset number of records counter for each time dep var
740
- for (auto & [varname,var] : f.vars ) {
741
- if (var->time_dep ) {
742
- var->num_records = new_length;
733
+ for (auto it : f.vars ) {
734
+ auto & v = *it.second ;
735
+ if (v.time_dep ) {
736
+ v.num_records = new_length;
743
737
}
744
738
}
745
739
}
@@ -752,31 +746,28 @@ void reset_time_dim_len (const std::string& filename, const int new_length)
752
746
void set_var_decomp (PIOVar& var,
753
747
const std::string& filename)
754
748
{
749
+ for (size_t i=1 ; i<var.dims .size (); ++i) {
750
+ EKAT_REQUIRE_MSG (var.dims [i]->offsets ==nullptr ,
751
+ " Error! We currently only allow decomposition on slowest-striding dimension.\n "
752
+ " Generalizing is not complicated, but it was not a priority.\n "
753
+ " - filename: " + filename + " \n "
754
+ " - varname : " + var.name + " \n "
755
+ " - var dims: " + ekat::join (var.dims ,get_entity_name," ," ) + " \n "
756
+ " - bad dim : " + var.dims [i]->name + " \n " );
757
+ }
758
+ EKAT_REQUIRE_MSG (var.dims [0 ]->offsets !=nullptr ,
759
+ " Error! Calling set_var_decomp, but the var first dimension does not appear to be decomposed.\n "
760
+ " - filename: " + filename + " \n "
761
+ " - varname : " + var.name + " \n "
762
+ " - var dims: " + ekat::join (var.dims ,get_entity_name," ," ) + " \n " );
755
763
EKAT_REQUIRE_MSG (var.decomp ==nullptr ,
756
764
" Error! You should have invalidated var.decomp before attempting to reset it.\n "
757
765
" - filename : " + filename + " \n "
758
766
" - varname : " + var.name + " \n "
759
767
" - var decomp: " + var.decomp ->name + " \n " );
760
768
761
- std::shared_ptr<const PIODim> decomp_dim;
762
- for (const auto & d : var.dims ) {
763
- if (d->decomposed ) {
764
- EKAT_REQUIRE_MSG (decomp_dim==nullptr ,
765
- " Error! Variable has multiple decomposed dimensions.\n "
766
- " - file: " + filename + " \n "
767
- " - var : " + var.name + " \n "
768
- " - 1st decomp dim: " + decomp_dim->name + " \n "
769
- " - 2nd decomp dim: " + d->name + " \n " );
770
- decomp_dim = d;
771
- }
772
- }
773
- EKAT_REQUIRE_MSG (decomp_dim!=nullptr ,
774
- " Error! Calling set_var_decomp, but the var does not have any decomposde dimension.\n "
775
- " - filename: " + filename + " \n "
776
- " - varname : " + var.name + " \n "
777
- " - var dims: " + ekat::join (var.dims ,get_entity_name," ," ) + " \n " );
778
-
779
769
// Create decomp name: dtype-dim1<len1>_dim2<len2>_..._dimk<lenN>
770
+ std::shared_ptr<const PIODim> decomp_dim;
780
771
std::string decomp_tag = var.dtype + " -" ;
781
772
for (auto d : var.dims ) {
782
773
decomp_tag += d->name + " <" + std::to_string (d->length ) + " >_" ;
@@ -806,55 +797,34 @@ void set_var_decomp (PIOVar& var,
806
797
// We haven't create this decomp yet. Go ahead and create one
807
798
decomp = std::make_shared<PIODecomp>();
808
799
decomp->name = decomp_tag;
809
- decomp->dim = decomp_dim ;
800
+ decomp->dim = var. dims [ 0 ] ;
810
801
811
802
int ndims = var.dims .size ();
812
803
813
- // Get local and global dim lengths
814
- std::vector<int > dimlen_glb (ndims),dimlen_lcl (ndims);
815
- int decomp_idx = -1 ;
816
- for (int idim=0 ; idim<ndims; ++idim) {
817
- dimlen_glb[idim] = dimlen_lcl[idim] = var.dims [idim]->length ;
818
- if (var.dims [idim]->decomposed ) {
819
- decomp_idx = idim;
820
- dimlen_lcl[idim] = var.dims [idim]->offsets .size ();
821
- }
804
+ // Get ALL dims global lengths, and compute prod of *non-decomposed* dims
805
+ std::vector<int > gdimlen = {decomp->dim ->length };
806
+ int non_decomp_dim_prod = 1 ;
807
+ for (int idim=1 ; idim<ndims; ++idim) {
808
+ auto d = var.dims [idim];
809
+ gdimlen.push_back (d->length );
810
+ non_decomp_dim_prod *= d->length ;
822
811
}
823
812
824
- // Compute global strides and local var size
825
- std::vector<int > strides (ndims,1 );
826
- int ndofs_lcl = dimlen_lcl.back ();
827
- for (int idim=ndims-2 ; idim>=0 ; --idim) {
828
- strides[idim] = strides[idim+1 ]*dimlen_glb[idim+1 ];
829
- ndofs_lcl *= dimlen_lcl[idim];
830
- }
831
-
832
- std::vector<int > idx (ndims,0 );
833
-
834
- // Helper lambda, to update an Nd index by adding 1 the the right, and handling carries
835
- auto inc_idx = [&] () {
836
- for (int i=ndims-1 ; i>=0 ; --i) {
837
- ++idx[i];
838
- if (idx[i]<dimlen_lcl[i])
839
- break ;
840
- idx[i] = 0 ;
841
- }
842
- };
843
-
844
- decomp->offsets = std::make_shared<OffsetsVec>(ndofs_lcl);
845
- for (int ldof=0 ; ldof<ndofs_lcl; ++ldof, inc_idx ()) {
846
- int bkp = idx[decomp_idx];
847
- idx[decomp_idx] = decomp_dim->offsets [bkp];
848
- int gdof = std::inner_product (idx.begin (),idx.end (),strides.begin (),0 );
849
-
850
- decomp->offsets ->vec [ldof] = gdof;
851
- idx[decomp_idx] = bkp;
813
+ // Create offsets list
814
+ const auto & dim_offsets = *decomp->dim ->offsets ;
815
+ int dim_loc_len = dim_offsets.size ();
816
+ decomp->offsets .resize (non_decomp_dim_prod*dim_loc_len);
817
+ for (int idof=0 ; idof<dim_loc_len; ++idof) {
818
+ auto dof_offset = dim_offsets[idof];
819
+ auto beg = decomp->offsets .begin ()+ idof*non_decomp_dim_prod;
820
+ auto end = beg + non_decomp_dim_prod;
821
+ std::iota (beg,end,non_decomp_dim_prod*dof_offset);
852
822
}
853
823
854
824
// Create PIO decomp
855
- int maplen = decomp->offsets -> vec .size ();
856
- PIO_Offset* compmap = decomp->offsets -> vec .data ();
857
- int err = PIOc_init_decomp (s.pio_sysid ,nctype (var.dtype ),ndims,dimlen_glb .data (),
825
+ int maplen = decomp->offsets .size ();
826
+ PIO_Offset* compmap = reinterpret_cast <PIO_Offset*>( decomp->offsets .data () );
827
+ int err = PIOc_init_decomp (s.pio_sysid ,nctype (var.dtype ),ndims,gdimlen .data (),
858
828
maplen,compmap, &decomp->ncid ,s.pio_rearranger ,
859
829
nullptr ,nullptr );
860
830
@@ -867,7 +837,7 @@ void set_var_decomp (PIOVar& var,
867
837
868
838
void set_dim_decomp (const std::string& filename,
869
839
const std::string& dimname,
870
- const std::vector<int >& my_offsets,
840
+ const std::vector<offset_t >& my_offsets,
871
841
const bool allow_reset)
872
842
{
873
843
auto & s = ScorpioSession::instance ();
@@ -879,16 +849,17 @@ void set_dim_decomp (const std::string& filename,
879
849
" - filename: " + filename + " \n "
880
850
" - dimname : " + dimname + " \n " );
881
851
882
- if (dim.decomposed ) {
852
+ if (dim.offsets != nullptr ) {
883
853
if (allow_reset) {
884
854
// We likely won't need the previously created decomps that included this dimension.
885
855
// So, as we remove decomps from vars that have this dim, keep track of their name,
886
856
// so that we can free them later *if no other users of them remain*.
887
857
std::set<std::string> decomps_to_remove;
888
- for (auto & [varname,var] : f.vars ) {
889
- if (var->decomp !=nullptr and var->decomp ->dim ->name ==dimname) {
890
- decomps_to_remove.insert (var->decomp ->name );
891
- var->decomp = nullptr ;
858
+ for (auto it : f.vars ) {
859
+ auto v = it.second ;
860
+ if (v->decomp !=nullptr and v->decomp ->dim ->name ==dimname) {
861
+ decomps_to_remove.insert (v->decomp ->name );
862
+ v->decomp = nullptr ;
892
863
}
893
864
}
894
865
for (const auto & dn : decomps_to_remove) {
@@ -902,7 +873,7 @@ void set_dim_decomp (const std::string& filename,
902
873
}
903
874
} else {
904
875
// Check that the offsets are (globally) the same
905
- int same = dim.offsets ==my_offsets;
876
+ int same = * dim.offsets ==my_offsets;
906
877
const auto & comm = ScorpioSession::instance ().comm ;
907
878
comm.all_reduce (&same,1 ,MPI_MIN);
908
879
EKAT_REQUIRE_MSG (same==1 ,
@@ -916,47 +887,33 @@ void set_dim_decomp (const std::string& filename,
916
887
}
917
888
}
918
889
919
- #ifndef NDEBUG
920
- std::vector<int > all_offsets (dim.length );
921
- const auto & comm = ScorpioSession::instance ().comm ;
922
- // TODO: if you impl Comm::all_gather_v, use that.
923
- for (int pid=0 , pos=0 ; pid<comm.size (); ++pid) {
924
- int n = my_offsets.size ();
925
- comm.broadcast (&n,1 ,pid);
926
- auto buf = all_offsets.data ()+pos;
927
- if (pid==comm.rank ())
928
- std::copy (my_offsets.data (),my_offsets.data ()+n,buf);
929
- comm.broadcast (buf,n,pid);
930
- pos += n;
890
+ // Check that offsets are less than the global dimension length
891
+ for (auto o : my_offsets) {
892
+ EKAT_REQUIRE_MSG (o>=0 && o<dim.length ,
893
+ " Error! Offset for dimension decomposition is out of bounds.\n "
894
+ " - filename: " + filename + " \n "
895
+ " - dimname : " + dimname + " \n "
896
+ " - dim glen: " + std::to_string (dim.length ) + " \n "
897
+ " - offset : " + std::to_string (o) + " \n " );
931
898
}
932
899
933
- std::sort (all_offsets.begin (),all_offsets.end ());
934
- std::vector<int > range (dim.length );
935
- std::iota (range.begin (),range.end (),0 );
936
- EKAT_REQUIRE_MSG (range==all_offsets,
937
- " Error! The decomposition does not cover the global dim length.\n "
938
- " - filename: " + filename + " \n "
939
- " - dimname : " + dimname + " \n "
940
- " - all offsets (sorted): " + ekat::join (all_offsets," ," ) + " \n " );
941
- #endif
942
- dim.offsets = my_offsets;
943
- dim.decomposed = true ;
900
+ dim.offsets = std::make_shared<std::vector<offset_t >>(my_offsets);
944
901
945
902
// If vars were already defined, we need to process them,
946
903
// and create the proper PIODecomp objects.
947
- for (auto [varname,var] : f.vars ) {
948
- if (ekat::contains (var ->dim_names (),dimname)) {
949
- set_var_decomp (*var ,filename);
904
+ for (auto it : f.vars ) {
905
+ if (ekat::contains (it. second ->dim_names (),dimname)) {
906
+ set_var_decomp (*it. second ,filename);
950
907
}
951
908
}
952
909
}
953
910
954
911
void set_dim_decomp (const std::string& filename,
955
912
const std::string& dimname,
956
- const int start, const int count,
913
+ const offset_t start, const offset_t count,
957
914
const bool allow_reset)
958
915
{
959
- std::vector<int > offsets (count);
916
+ std::vector<offset_t > offsets (count);
960
917
std::iota (offsets.begin (),offsets.end (),start);
961
918
set_dim_decomp (filename,dimname,offsets,allow_reset);
962
919
}
@@ -973,7 +930,7 @@ void set_dim_decomp (const std::string& filename,
973
930
++len;
974
931
}
975
932
976
- int offset = len;
933
+ offset_t offset = len;
977
934
comm.scan (&offset,1 ,MPI_SUM);
978
935
offset -= len; // scan is inclusive, but we need exclusive
979
936
@@ -1041,12 +998,8 @@ void define_var (const std::string& filename, const std::string& varname,
1041
998
set_attribute (filename,varname," units" ,units);
1042
999
}
1043
1000
1044
- // Check if we need to setup at decomp for this var
1045
- for (const auto & d : var->dims ) {
1046
- if (d->decomposed ) {
1047
- set_var_decomp (*var,filename);
1048
- break ;
1049
- }
1001
+ if (var->dims .size ()>0 and var->dims [0 ]->offsets !=nullptr ) {
1002
+ set_var_decomp (*var,filename);
1050
1003
}
1051
1004
} else {
1052
1005
const auto & var = f.vars .at (varname);
@@ -1174,11 +1127,12 @@ void mark_dim_as_time (const std::string& filename, const std::string& dimname)
1174
1127
// If a var has "time" in its dims (must be the 1st dim!),
1175
1128
// remove it. Recall that we only store non-time dims in
1176
1129
// the list of var dims.
1177
- for (auto & [varname,var] : f.vars ) {
1178
- if (var->dims .size ()>0 and var->dims [0 ]->name ==dimname) {
1179
- var->dims .erase (var->dims .begin ());
1180
- var->size = -1 ;
1181
- var->time_dep = true ;
1130
+ for (auto & it : f.vars ) {
1131
+ auto & v = it.second ;
1132
+ if (v->dims .size ()>0 and v->dims [0 ]->name ==dimname) {
1133
+ v->dims .erase (v->dims .begin ());
1134
+ v->size = -1 ;
1135
+ v->time_dep = true ;
1182
1136
}
1183
1137
}
1184
1138
} else {
@@ -1258,7 +1212,7 @@ void read_var (const std::string &filename, const std::string &varname, T* buf,
1258
1212
std::string pioc_func;
1259
1213
if (var.decomp ) {
1260
1214
// A decomposed variable, requires read_darray
1261
- err = PIOc_read_darray (f.ncid ,var.ncid ,var.decomp ->ncid ,var.decomp ->offsets -> vec .size (),buf);
1215
+ err = PIOc_read_darray (f.ncid ,var.ncid ,var.decomp ->ncid ,var.decomp ->offsets .size (),buf);
1262
1216
pioc_func = " read_darray" ;
1263
1217
} else {
1264
1218
// A non-decomposed variable, use PIOc_get_var(a)
@@ -1340,7 +1294,7 @@ void write_var (const std::string &filename, const std::string &varname, const T
1340
1294
std::string pioc_func;
1341
1295
if (var.decomp ) {
1342
1296
// A decomposed variable, requires write_darray
1343
- err = PIOc_write_darray (f.ncid ,var.ncid ,var.decomp ->ncid ,var.decomp ->offsets -> vec .size (),buf,fillValue);
1297
+ err = PIOc_write_darray (f.ncid ,var.ncid ,var.decomp ->ncid ,var.decomp ->offsets .size (),buf,fillValue);
1344
1298
pioc_func = " write_darray" ;
1345
1299
} else {
1346
1300
// A non-decomposed variable, use PIOc_put_var(a)
0 commit comments