Skip to content
Snippets Groups Projects
Commit 334d8a2b authored by wfg's avatar wfg
Browse files

Merge branch 'groupless' of https://github.com/williamfgc/ADIOSPP.git into groupless

parents 0f3d4d5d 3430e0af
No related branches found
No related tags found
1 merge request!8Integrate groupless
eisen@inferno.cc.gatech.edu.274
\ No newline at end of file
# 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
/*
* 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;
}
/*
* 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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment