diff --git a/examples/groupless/compound/.#writer.cpp b/examples/groupless/compound/.#writer.cpp new file mode 120000 index 0000000000000000000000000000000000000000..1482a7f96e96d1614f9286b076547b90a97ea279 --- /dev/null +++ b/examples/groupless/compound/.#writer.cpp @@ -0,0 +1 @@ +eisen@inferno.cc.gatech.edu.274 \ No newline at end of file diff --git a/examples/groupless/compound/Makefile b/examples/groupless/compound/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1fc69407c352f75f74bee1bcdc588ea00463cb4e --- /dev/null +++ b/examples/groupless/compound/Makefile @@ -0,0 +1,26 @@ +# Makefile for testing purposes, will build writer_mpi (make or make mpi) or writer_nompi (make nompi) +# Created on: Feb 13, 2017 +# Author: pnorbert + +#COMPILERS +CC=g++ +MPICC=mpic++ + +#ADIOS LOCATION +ADIOS_DIR=../../.. +ADIOS_INCLUDE=-I$(ADIOS_DIR)/include +ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a +ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a + +#FLAGS +CFLAGS=-Wall -Wpedantic -Woverloaded-virtual -std=c++11 -O0 -g +LDFLAGS= + +all: writer reader + +writer reader: $(ADIOS_LIB) $(ADIOS_HFiles) + $(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $@.cpp -o $@ $(ADIOS_LIB) $(LDFLAGS) -lpthread \ + +clean: + rm -f writer reader + diff --git a/examples/groupless/compound/reader.cpp b/examples/groupless/compound/reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16c78cd7a1238fc23f219b608b4159c9e93cf41e --- /dev/null +++ b/examples/groupless/compound/reader.cpp @@ -0,0 +1,202 @@ +/* + * reader.cpp + * + * Created on: Feb 21, 2017 + * Author: eisen, modified from basic by pnorbert + */ + +#include <vector> +#include <iostream> + +#include <mpi.h> +#include "ADIOS_CPP.h" + + +int main( int argc, char* argv [] ) +{ + int rank, nproc; + MPI_Init( &argc, &argv ); + MPI_Comm_rank( MPI_COMM_WORLD, &rank ); + MPI_Comm_size( MPI_COMM_WORLD, &nproc); + const bool adiosDebug = true; + + adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug ); + + // Application variable + // GSE === user-defined structure + // + // Like HDF5 example, read with a subset of the structure that was written. + // Easily handled by FFS and HDF5, but ambitious for ADIOS + typedef struct s2_t { + double c; + int a; + }; + unsigned int Nx; + int Nparts; + int Nwriters; + + try + { + //Define method for engine creation + // 1. Get method def from config file or define new one + adios::Method& bpReaderSettings = adios.GetMethod( "input" ); + if( bpReaderSettings.undeclared() ) + { + // if not defined by user, we can change the default settings + bpReaderSettings.SetEngine( "BP" ); // BP is the default engine + } + + //Create engine smart pointer due to polymorphism, + // Default behavior + // auto bpReader = adios.Open( "myNumbers.bp", "r" ); + // this would just open with a default transport, which is "BP" + auto bpReader = adios.Open( "myNumbers.bp", "r", bpReaderSettings ); + + // All the above is same as default use: + //auto bpReader = adios.Open( "myNumbers.bp", "r"); + + if( bpReader == nullptr ) + throw std::ios_base::failure( "ERROR: failed to open ADIOS bpReader\n" ); + + + /* Variable names are available as a vector of strings */ + std::cout << "List of variables in file: " << bpReader->VariableNames << "\n"; + + /* NX */ + bpReader->Read<unsigned int>( "NX", Nx ); // read a Global scalar which has a single value in a step + + /* nproc */ + bpReader->Read<int>( "nproc", Nwriters ); // also a global scalar + + + /* Nparts */ + // Nparts local scalar is presented as a 1D array of Nwriters elements. + // We need to read a specific value the same way as reading from any 1D array. + // Make a single-value selection to describe our rank's position in the + // 1D array of Nwriters values. + if( rank < Nwriters ) + { + std::shared_ptr<adios::Variable> varNparts = bpReader.InquiryVariable("Nparts"); + std::unique_ptr<adios::Selection> selNparts = adios.SelectionBoundingBox( {1}, {rank} ); + varNparts->SetSelection( selNparts ); + bpReader->Read<int>( varNparts, Nparts ); + } + // or we could just read the whole array by every process + std::vector<int> partsV( Nwriters ); + bpReader->Read<int>( "Nparts", partsV.data() ); // read with string name, no selection => read whole array + + std::vector<int> partsV; + bpReader->Read<int>( "Nparts", partsV); // read with string name, no selection => read whole array + (Nwriters == partsV.size()) + + /* Nice */ + // inquiry about a variable, whose name we know + /* GSE === compound type declaration borrowed heavily from HDF5 style */ + adios::CompType mtype( sizeof(s2_t) ); + mtype.insertMember( "c_name", OFFSET(s2_t, c), PredType::NATIVE_DOUBLE); + mtype.insertMember( "a_name", OFFSET(s2_t, a), PredType::NATIVE_INT); + + /* + * GSE === this is a bit conceptually different. There was no real + * check in the prior API that the variable in the file was in any way + * "compatible" with how we planned to read it. This could be done + * here, by providing the details of the structure that we are + * prepared to read in the inquiryVariable, or if we had an API that + * allowed more introspection, we could perhaps support a query on the + * adios::Variable and a later operation that informed it of the data + * type that we were prepared to extract from it. + */ + std::shared_ptr<adios::Variable> varNice = bpReader.InquiryVariable("Nice", mtype); + + if( varNice == nullptr ) + throw std::ios_base::failure( "ERROR: failed to find variable 'myDoubles' in input file\n" ); + + // ? how do we know about the type? std::string varNice->m_Type + uint64_t gdim = varNice->m_GlobalDimensions[0]; // ?member var or member func? + uint64_t ldim = gdim / nproc; + uint64_t offs = rank * ldim; + if( rank == nproc-1 ) + { + ldim = gdim - (ldim * gdim); + } + + NiceArray.reserve(ldim); + + // Make a 1D selection to describe the local dimensions of the variable we READ and + // its offsets in the global spaces + std::unique_ptr<adios::Selection> bbsel = adios.SelectionBoundingBox( {ldim}, {offs} ); // local dims and offsets; both as list + varNice->SetSelection( bbsel ); + // GSE === Again, templated here? + bpReader->Read<s2_t>( varNice, NiceArray.data() ); + + + + /* Ragged */ + // inquiry about a variable, whose name we know + std::shared_ptr<adios::Variable<void> > varRagged = bpReader.InquiryVariable("Ragged"); + if( varRagged->m_GlobalDimensions[1] != adios::VARYING_DIMENSION) + { + throw std::ios_base::failure( "Unexpected condition: Ragged array's fast dimension " + "is supposed to be VARYING_DIMENSION\n" ); + } + // We have here varRagged->sum_nblocks, nsteps, nblocks[], global + if( rank < varRagged->nblocks[0] ) // same as rank < Nwriters in this example + { + // get per-writer size information + varRagged->InquiryBlocks(); + // now we have the dimensions per block + + unsigned long long int ldim = varRagged->blockinfo[rank].m_Dimensions[1]; + RaggedArray.resize( ldim ); + + std::unique_ptr<adios::Selection> wbsel = adios.SelectionWriteblock( rank ); + varRagged->SetSelection( wbsel ); + bpReader->Read<float>( varRagged, RaggedArray.data() ); + + // We can use bounding box selection as well + std::unique_ptr<adios::Selection> rbbsel = adios.SelectionBoundingBox( {1,ldim}, {rank,0} ); + varRagged->SetSelection( rbbsel ); + bpReader->Read<float>( varRagged, RaggedArray.data() ); + } + + /* Extra help to process Ragged */ + int maxRaggedDim = varRagged->GetMaxGlobalDimensions(1); // contains the largest + std::vector<int> raggedDims = varRagged->GetVaryingGlobalDimensions(1); // contains all individual sizes in that dimension + + + // Close file/stream + bpReader->Close(); + } + catch( std::invalid_argument& e ) + { + if( rank == 0 ) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + catch( std::ios_base::failure& e ) + { + if( rank == 0 ) + { + std::cout << "System exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + catch( std::exception& e ) + { + if( rank == 0 ) + { + std::cout << "Exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + + MPI_Finalize( ); + + return 0; + +} + + + diff --git a/examples/groupless/compound/writer.cpp b/examples/groupless/compound/writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5d7e7307855fd0cacde452bfadc03a28aefd32a --- /dev/null +++ b/examples/groupless/compound/writer.cpp @@ -0,0 +1,153 @@ +/* + * writer.cpp + * + * Created on: Feb 13, 2017 + * Author: pnorbert + */ + +#include <vector> +#include <iostream> + +#include <mpi.h> +#include "ADIOS_CPP.h" + +namespace adios { + typedef enum { + VARYING_DIMENSION = -1, + LOCAL_VALUE = 0, + GLOBAL_VALUE = 1 + }; +} + +int main( int argc, char* argv [] ) +{ + int rank, nproc; + MPI_Init( &argc, &argv ); + MPI_Comm_rank( MPI_COMM_WORLD, &rank); + MPI_Comm_size( MPI_COMM_WORLD, &nproc); + const bool adiosDebug = true; + + adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug ); + + //Application variable + const unsigned int Nx = 10; + // GSE === user-defined structure + typedef struct s1_t { + int a; + float b; + double c; + }; + const int Nparts = rand()%6 + 5; // random size per process, 5..10 each + + std::vector<s1_t> NiceArray( Nx ); + for( int i=0; i < Nx; i++ ) + { + NiceArray.push_back(ss1_t()); + NiceArray[i].a = rank*Nx + (double)i; + NiceArray[i].b = 100.0*rank*Nx + 100.0*(double)i; + NiceArray[i].c = 10000.0*rank*Nx + 10000.0*(double)i; + } + + + try + { + /* GSE === compound type declaration borrowed heavily from HDF5 style */ + adios::CompType mtype( sizeof(s1_t) ); + mtype.insertMember( "a_name", OFFSET(s1_t, a), PredType::NATIVE_INT); + mtype.insertMember( "c_name", OFFSET(s1_t, c), PredType::NATIVE_DOUBLE); + mtype.insertMember( "b_name", OFFSET(s1_t, b), PredType::NATIVE_FLOAT); + + //Define group and variables with transforms, variables don't have functions, only group can access variables + adios::Variable<unsigned int>& varNX = adios.DefineVariable<unsigned int>( "NX" ); // global single-value across processes + adios::Variable<int>& varNproc = adios.DefineVariable<int>( "nproc", adios::GLOBAL_VALUE ); // same def for global value + adios::Variable<int>& varNparts = adios.DefineVariable<int>( "Nparts", adios::LOCAL_VALUE ); // a single-value different on every process + + // GSE === template necessary or useful here? Extra argument for previously-built compound type information */ + adios::Variable<s1_t>& varNice = adios.DefineVariable<s1_t>( "Nice", {nproc*Nx}, mtype ); // 1D global array + + //add transform to variable in group...not executed (just testing API) + adios::Transform bzip2 = adios::transform::BZIP2( ); + varNice->AddTransform( bzip2, 1 ); + + //Define method for engine creation + // 1. Get method def from config file or define new one + adios::Method& bpWriterSettings = adios.GetMethod( "output" ); + if( bpWriterSettings.undeclared() ) + { + // if not defined by user, we can change the default settings + bpWriterSettings.SetEngine( "BP" ); // BP is the default engine + bpWriterSettings.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport + // Passing parameters to the transport + bpWriterSettings.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine + bpWriterSettings.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators + } + + //Open returns a smart pointer to Engine containing the Derived class Writer + // "w" means we overwrite any existing file on disk, but AdvanceStep will append steps later. + auto bpWriter = adios.Open( "myNumbers.bp", "w", bpWriterSettings ); + + if( bpWriter == nullptr ) + throw std::ios_base::failure( "ERROR: failed to open ADIOS bpWriter\n" ); + + if( rank == 0 ) + { + // Writing a global scalar from only one process + bpWriter->Write<unsigned int>( varNX, Nx ); + } + // Writing a local scalar on every process. Will be shown at reading as a 1D array + bpWriter->Write<int>( varNparts, Nparts ); + + // Writing a global scalar on every process is useless. Information will be thrown away + // and only rank 0's data will be in the output + bpWriter->Write<int>( varNproc, nproc ); + + // Make a 1D selection to describe the local dimensions of the variable we write and + // its offsets in the global spaces + adios::Selection& sel = adios.SelectionBoundingBox( {Nx}, {rank*Nx} ); // local dims and offsets; both as list + varNice.SetSelection( sel ); + + // GSE === Template useful or necessary here? We have to treat this as a void* inside ADIOS... + bpWriter->Write<sl_t>( varNice, NiceArray.data() ); + + // Indicate we are done for this step + // N-to-M Aggregation, disk I/O will be performed during this call, unless + // time aggregation postpones all of that to some later step + bpWriter->Advance( ); + bpWriter->AdvanceAsync( callback_func_to_notify_me ); + + // Called once: indicate that we are done with this output for the run + bpWriter->Close( ); + } + catch( std::invalid_argument& e ) + { + if( rank == 0 ) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + catch( std::ios_base::failure& e ) + { + if( rank == 0 ) + { + std::cout << "System exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + catch( std::exception& e ) + { + if( rank == 0 ) + { + std::cout << "Exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + } + + MPI_Finalize( ); + + return 0; + +} + + +