Skip to content
Snippets Groups Projects
Commit 2623089b authored by Atkins, Charles Vernon's avatar Atkins, Charles Vernon Committed by GitHub
Browse files

Merge pull request #155 from williamfgc/doc

Updating documentation files
parents 7943ef35 fd3382d7
No related branches found
No related tags found
No related merge requests found
# Contributor's Guide
This guide will walk you through how to submit changes to ADIOS and interact
with the project as a developer.
This guide will walk you through how to submit changes to ADIOS 2.0 and interact
with the project as a developer. Information found on ADIOS 2.0 wiki: https://github.com/ornladios/ADIOS2/wiki under the Contributing to ADIOS section.
Table of Contents
=================
......
......@@ -17,77 +17,96 @@ Copyright.txt for more details.
## Getting Started
ADIOS 2.0 uses CMake for it's build environment. CMake expects projects to use "out-of-source" builds, which means keeping a separate build and source directory (different from autotools, which usually uses an in-source build). To build ADIOS:
ADIOS 2.0 uses CMake for it's build environment. CMake expects projects to use "out-of-source" builds, which means keeping a separate build and source directory (different from autotools, which usually uses an in-source build). To build ADIOS:
1. Clone the repository:
```
$ mkdir adios
$ cd adios
$ git clone https://github.com/ornladios/adios2.git source
```
```
$ mkdir ADIOS2
$ cd ADIOS2
$ git clone https://github.com/ornladios/adios2.git source
```
2. Create a separate build directory:
```
$ mkdir build
```
3. Configure the project with CMake. The following options can be specified as `ON` or `OFF` with cmake's `-DVAR=VALUE` syntax:
* `ADIOS_BUILD_SHARED_LIBS` - Build shared libraries (`OFF` for static)
* `ADIOS_BUILD_EXAMPLES ` - Build examples
* `ADIOS_BUILD_TESTING ` - Build test code
* `ADIOS_USE_MPI ` - Enable MPI
* `ADIOS_USE_BZip2 ` - Enable BZip2 compression
* `ADIOS_USE_ADIOS1 ` - Enable the ADIOS 1.x engine
* `ADIOS_USE_DataMan ` - Enable the DataMan engine
```
$ cd build
$ cmake -DADIOS_USE_MPI=OFF ../source
-- The C compiler identification is GNU 6.3.1
-- The CXX compiler identification is GNU 6.3.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found BZip2: /usr/lib64/libbz2.so (found version "1.0.6")
-- Looking for BZ2_bzCompressInit
-- Looking for BZ2_bzCompressInit - found
ADIOS2 build configuration:
C++ Compiler: GNU 6.3.1
/usr/bin/c++
Installation prefix: /usr/local
Features:
Library Type: shared
Build Type: Debug
Testing: ON
MPI: OFF
BZip2: ON
ADIOS1: OFF
DataMan: OFF
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/adios/build
$
```
You can also use CMake's curses-base UI with `ccmake ../source`.
3. Compile:
```
$ make -j8
```
4. Run tests:
```
$ make test
```
```
$ mkdir build
```
3. ***Configure the project with CMake***. The following options can be specified as `ON` or `OFF` with cmake's `-DVAR=VALUE` syntax, where VAR options are:
* `ADIOS_BUILD_SHARED_LIBS` - Build shared libraries (`OFF` for static)
* `ADIOS_BUILD_EXAMPLES ` - Build examples
* `ADIOS_BUILD_TESTING ` - Build test code
* `ADIOS_USE_MPI ` - Enable MPI
* `ADIOS_USE_BZip2 ` - Enable [BZip2](http://www.bzip.org/) compression
* `ADIOS_USE_ZFP ` - Enable [ZFP](https://github.com/LLNL/zfp) compression
* `ADIOS_USE_ADIOS1 ` - Enable the [ADIOS 1.x](https://www.olcf.ornl.gov/center-projects/adios/) engine
* `ADIOS_USE_DataMan ` - Enable the DataMan engine for WAN transports
* `ADIOS_USE_Python ` - Enable the Python bindings
***Important, automatic discovery***: ADIOS 2.0 CMake has an AUTO discovery "ON" default option. If a certain dependency is found in the system installation path (_e.g._ /usr/), not a custom one (_e.g._ /home , /opt ) it will turn on installation for that dependency automatically
In addition, the -DCMAKE_VAR frequent options can be selected:
* `CMAKE_INSTALL_PREFIX ` - Prefix location for installation with `make install`, default depends on system (_e.g._ /usr/local)
* `CMAKE_BUILD_TYPE ` - Debug (default, debugging symbols), or Release (compiler optimizations)
Example:
```
$ cd build
$ cmake -DADIOS_USE_MPI=ON -DADIOS_USE_BZip2=ON -DCMAKE_BUILD_TYPE=Debug ../ADIOS2
-- The C compiler identification is GNU 6.3.1
-- The CXX compiler identification is GNU 6.3.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found BZip2: /usr/lib64/libbz2.so (found version "1.0.6")
-- Looking for BZ2_bzCompressInit
-- Looking for BZ2_bzCompressInit - found
ADIOS2 build configuration:
C++ Compiler: GNU 6.3.1
/usr/bin/c++
Installation prefix: /usr/local
Features:
Library Type: shared
Build Type: Debug
Testing: ON
MPI: OFF
BZip2: ON
ADIOS1: OFF
DataMan: OFF
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/adios/build
$
```
You can also use CMake's curses-base UI with `ccmake ../source`.
4. Compile:
```
$ make -j8
```
5. Run tests:
```
$ make test
```
## Developers
Please see the [Contributors Guide](Contributing.md) for how to submit changes
to ADIOS.
To summit changes to ADIOS 2.0: please see the wiki https://github.com/ornladios/ADIOS2/wiki Contributing to ADIOS section, or the local [Contributors Guide](Contributing.md).
/* Fake example for Current API by design, incorrect as code but describes most
* of the ideas */
#include <mpi.h>
#include "../../source/adios2/core/ADIOS.h"
void cb_AsyncWriteAdvanceCompleted(std::shared_ptr<adios::Engine> writer)
{
std::cout << "AdvanceAsync() completed. We can modify our zero-copy "
"variables\n";
}
void cb_AsyncReadAdvanceCompleted(std::shared_ptr<adios::Engine> writer)
{
std::cout
<< "AdvanceAsync() completed. We have new data to read and we have "
"the lock on it\n";
}
int main(int argc, char *argv[])
{
// Application variables
MPI_Comm comm = MPI_COMM_WORLD;
const unsigned int NX = 10;
double Temperature[1][NX + 2]; // We will want to write only Nx elements,
// skipping the first and last (think ghost
// cells)
std::vector<float> RaggedArray;
int Nparts, nproc;
// Global class/object that serves for init, finalize and provides ADIOS
// functions
adios::ADIOS adios("config.xml", comm, /*verbose=*/adios::Verbose::INFO,
/*debugflag=*/false);
/*************
* WRITE API
*************/
/* Method
* We associate Engines and Transports and user settings into an object
* called
* Method.
* ADIOS checks if it is defined by the user in the config file, and fills
* it
* out if it is.
*/
adios::Method &wmethod = adios.DeclareMethod("WriteMethod");
if (!wmethod.isUserDefined())
{
// if not defined by user, we can change the default settings
wmethod.SetEngine("BP"); // BP is the default engine
wmethod.AllowThreads(
1); // no threading for data processing (except for staging)
wmethod.AddTransport(
"File", "lucky=yes"); // ISO-POSIX file is the default transport
wmethod.AddTransport("Staging"); //"The" staging method developed in ECP
wmethod.SetParameters("have_metadata_file",
"yes"); // Passing parameters to the engine
wmethod.SetParameters("Aggregation",
(nproc + 1) / 2); // number of aggregators
wmethod.SetParameters("verbose",
adios::Verbose::WARN); // Verbosity level
// for this engine
// and what it calls
}
// Define variables with transformations.
adios::Variable<unsigned int> &varNX = adios.DefineVariable<unsigned int>(
"NX"); // global single-value across processes
auto &varNproc = adios.DefineVariable<int>(
"nproc", adios::Dims{adios::GLOBAL_VALUE}); // same def for global value
adios::Variable<int> &varNparts = adios.DefineVariable<int>(
"Nparts", adios::Dims{adios::LOCAL_VALUE}); // a single-value
// different on every
// process
adios::Variable<double> &var2D = adios.DefineVariable<double>(
"Temperature",
adios::Dims{nproc, NX}); // 2D global array, 1D decomposition
adios::Variable<float> &varRagged = adios.DefineVariable<float>(
"Ragged", adios::Dims{nproc, adios::VARYING_DIMENSION}); // ragged array
// add transform to variable
adios::Transform compress = adios::transform::BZip2();
var2D.AddTransform(compress, "level=5");
// open...write.write.write...advance...write.write.write...advance...
// ...close cycle
// "w" create/overwrite on open, "a" append at open, "u" open for update
// (does
// not increase step), "r" open for read.
std::shared_ptr<adios::Engine> writer = adios.Open(
"myNumbers.bp", "w", comm, wmethod, adios::IOMode::INDEPENDENT);
if (writer == nullptr)
throw std::ios_base::failure("ERROR: failed to open ADIOS writer\n");
// Zero-Copy API: Define a variable with local dimensions now, and make
// ADIOS
// allocate it inside its buffers
// This requires an engine created. The variable will be deallocated in
// writer->Close()
// Calling varZeroCopy.SetSelection() later should throw an exception, i.e.
// modification is not allowed
// 2D global array, 1D decomposition
adios::Variable<double> &varZeroCopy = adios.DefineVariable<double>(
"ZC", adios::Dims{nproc, NX}, adios::Dims{1, NX}, adios::Dims{rank, 0});
double fillValue = -1.0;
double *const myVarZC =
writer->AllocateVariable<double>(varZeroCopy, fillValue);
for (int step = 0; step < 10; ++step)
{
// write scalar value
writer->Write<int>(varNparts, Nparts);
// Make a selection to describe the local dimensions of the variable we
// write and
// its offsets in the global spaces. This could have been done in
// adios.DefineVariable()
adios::SelectionBoundingBox sel = adios::SelectionBoundingBox(
{1, NX}, {rank, NX}); // local dims and offsets; both as list
var2D.SetSelection(
sel); // Shall we call it SetSpaceSelection, SetOutputSelection?
// Select the area that we want to write from the data pointer we pass
// to
// the writer
// Think HDF5 memspace, just not hyperslabs yet, only a bounding box
// selection
// Engine will copy this bounding box from the data pointer into the
// buffer.
// Size of the bounding box should match the
// "space" selection which was given above. Default memspace is the full
// selection.
adios::SelectionBoundingBox memspace = adios::SelectionBoundingBox(
{1, NX}, {0, 1}); // local dims and offsets; both as list
var2D.SetMemorySelection(memspace);
writer->Write<double>(var2D, *Temperature);
// 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.
// When Advance() returns, user can overwrite its Zero Copy variables.
// Internal buffer is freed only if there are no Zero Copy variables and
// there is no time aggregation going on
writer->Advance(); // same as AppendMode
writer->Advance(adios::APPEND, 0.0); // append new step at next write
writer->Advance(adios::UPDATE); // do not increase step;
// When AdvanceAsync returns, user need to wait for notification that he
// can
// overwrite the Zero Copy variables.
writer->AdvanceAsync(adios::APPEND, cb_AsyncWriteAdvanceCompleted);
}
// Called once: indicate that we are done with this output for the run
// Zero Copy variables will be deallocated
writer->Close();
/*************
* READ API
*************/
adios::Method &rmethod = adios.DeclareMethod("ReadMethod");
if (!rmethod.isUserDefined())
{
// if not defined by user, we can change the default settings
rmethod.SetEngine("BP"); // BP is the default engine
rmethod.AddTransport("Staging"); //"The" staging method developed in ECP
rmethod.SetParameters("Aggregation",
(nproc + 1) / 2); // number of aggregators
rmethod.SetParameters("verbose",
adios::Verbose::WARN); // Verbosity level
// for this engine
// and what it calls
}
// 1. Open a stream, where every reader can see everything in a stream (so
// that they can read a global array)
// Blocking read of a variable
try
{
// These method settings are developer-only, not available to the user
rmethod.SetReadMultiplexPattern(adios::GLOBAL_READERS); // Each reader
// process sees
// everything from
// the stream
rmethod.SetStreamOpenMode(
adios::WAITFORSTREAM); // In Open(), wait for the
// first step appear
// (default)
// Open a stream
std::shared_ptr<adios::Engine> reader = adios.Open(
"filename.bp", "r", comm, rmethod, adios::IOMode::COLLECTIVE,
/*timeout_sec=*/300.0); // wait this long for the stream,
// return error afterwards
/* Variable names are available as a vector of strings */
std::cout << "List of variables in file: " << reader->VariableNames()
<< "\n";
/* read a Global scalar which has a single value in a step */
reader->Read<unsigned int>("NX", NX);
// inquiry about a variable, whose name we know
adios::Variable<double> var2D =
reader->InquireVariableDouble("Temperature");
std::vector<std::size_t> gdims = var2D.GetGlobalDimensions();
int nsteps = var2D.GetSteps();
struct adios::BlockInfo blocks = reader.InquiryVariableBlockInfo(
reader, var2D); // get per-writer size info
// this is adios1 ADIOS_VARBLOCK
struct adios::Statistics stats =
reader.InquiryVariableStat(reader, var2D, perstepstat,
perblockstat); // get min/max statistics
// this is adios1 ADIOS_VARSTAT
while (true)
{
// Make a selection to describe the local dimensions of the variable
// we
// READ and
// its offsets in the global spaces
adios::SelectionBoundingBox bbsel = adios::SelectionBoundingBox(
{1, NX}, {0, 0}); // local dims and offsets; both as list
var2D.SetSelection(bbsel);
adios::SelectionBoundingBox memspace = adios::SelectionBoundingBox(
{1, NX}, {0, 1}); // local dims and offsets; both as list
var2D.SetMemorySelection(memspace);
reader->Read<double>(var2D, *Temperature);
// var2D, Temperature );
// Better for staging to schedule several reads at once
reader->ScheduleRead<double>(var2D, *Temperature);
reader->PerformReads(adios::BLOCKINGREAD);
// promise to not read more from this step/item
reader->Release();
// want to move on to the next available step/item
reader->Advance(adios::NEXT_AVAILABLE); // default
reader->Advance(adios::LATEST_AVAILABLE); // interested only in the
// latest data
}
// Close file/stream
reader->Close();
}
catch (adios::end_of_stream &e)
{
// Reached end of stream, end processing loop
// Close file/stream
reader->Close();
}
catch (adios::file_not_found &e)
{
// File/stream does not exist, quit
}
// 2. Open a stream, where each item from the writers will get to a single
// reader only
// If the writers are collective, that means a whole steps go to different
// readers
// If the writers are independent, that means each writer's output goes to
// different readers
// Also show here ScheduleRead/PerformRead
// try
{
rmethod.SetReadMultiplexPattern(
adios::FIFO_READERS); // Each reader process
// sees everything
// from the stream
rmethod.SetStreamOpenMode(
adios::WAITFORSTREAM); // In Open(), wait for the
// first step appear
// (default)
// Open a stream
std::shared_ptr<adios::Engine> reader = adios.Open(
"filename.bp", "r", comm, rmethod, adios::IOMode::INDEPENDENT,
/*timeout_sec=*/300.0); // wait this long for the stream, return
// error
// afterwards
while (true)
{
// Make a selection to describe the local dimensions of the variable
// we
// READ and
// its offsets in the global spaces if we know this somehow
adios::SelectionBoundingBox bbsel = adios::SelectionBoundingBox(
{1, NX}, {0, 0}); // local dims and offsets; both as list
var2D.SetSelection(bbsel);
reader->Read<double>(var2D, *Temperature);
// Let ADIOS allocate space for the incoming (per-writer) item
double *data = reader->Read<double>(var2D);
// promise to not read more from this step/item
reader->Release();
// want to move on to the next available step/item
reader->Advance(); // default
reader->Advance(
adios::LATEST_AVAILABLE); // This should be an error, or
// could it make sense?
}
reader->Close();
}
// 3. Open a stream and return immediately, not waiting for data to appear
// In this mode we cannot inquiry variables, but can schedule reads
// try
{
rmethod.SetReadMultiplexPattern(adios::GLOBAL_READERS); // Each reader
// process sees
// everything from
// the stream
rmethod.SetStreamOpenMode(
adios::NOWAITFORSTREAM); // In Open(), wait for
// the first step appear
// (default)
// Open a stream
std::shared_ptr<adios::Engine> reader = adios.Open(
"filename.bp", "r", comm, rmethod, adios::IOMode::INDEPENDENT);
while (true)
{
// Let ADIOS allocate space for the incoming (per-writer) item
reader->ScheduleRead(); // read whatever comes
// One way is to handle the incoming data through a callback (which
// will
// be called in a thread)
// void cb( const void *data, std::string doid, std::string var,
// std::string dtype, std::vector<std::size_t> varshape );
// void cb( adios::VARCHUNK * chunk ); // see adios1 for VARCHUNK
reader->SetReadCallback(cb);
reader->PerformReads(adios::NONBLOCKINGREAD);
// Another way is checking back manually like in adios1 and
// processing
// chunks
reader->PerformReads(adios::NONBLOCKINGREAD);
int ck;
adios::VARCHUNK *chunk;
try
{
while ((ck = reader->CheckReads(&chunk)) > 0)
{
if (chunk)
{
// process the chunk first
// ...
// free memory of chunk (not the data!)
adios::FreeChunk(chunk);
}
else
{
// no chunk was returned, slow down a little
sleep(1);
}
}
}
catch (std::exception &e)
{
// some error happened while getting a chunk
}
reader->Release();
// When AdvanceAsync returns new data is not yet available.
// A callback will tell us when we have the new data (and we have
// the lock
// on it to read)
writer->AdvanceAsync(adios::NEXT_AVAILABLE,
cb_AsyncReadAdvanceCompleted);
// Do we need more fine grained control? Like this function does not
// get
// the lock and so
// do we need to call Advance() to get the lock?
}
reader->Close();
}
// Note: chunk reading also works if scheduling reads for specific variables
// 4. Open it as file and see all steps at once.
// Allow for reading multiple steps of a variable into a contiguous array
try
{
rmethod.AddTransport("BP"); // Set a file engine here. Shall we have
// RemoveTransport() too?
// Open a file with all steps immediately available
std::shared_ptr<adios::Engine> reader = adios.OpenFileReader(
"filename.bp", comm, rmethod, adios::IOMode::COLLECTIVE);
/* NX */
/* There is a single value for each step. We can read all into a 1D
* array
* with a step selection.
* Steps are not automatically presented as an array dimension and read
* does
* not read it as array.
*/
// We can also just conveniently get the first step with a simple read
// statement.
reader->Read<unsigned int>(
"NX",
&NX); // read a Global scalar which has a single value in a step
reader->Read<unsigned int>(
varNX,
&NX); // read a Global scalar which has a single value in a step
adios::Variable<void> varNXread = reader->InquireVariable("NX");
adios::Variable<unsigned int> varNXreadint =
reader->InquireVariableInt("NX");
std::vector<unsigned int> Nxs(
varNXread.GetSteps()); // number of steps available
// make a StepSelection to select multiple steps. Args: From, #of
// consecutive steps
adios::StepSelection stepsNx(0, varNXread.GetSteps());
// ? How do we make a selection for an arbitrary list of steps ?
varNXread.SetStepSelection(stepsNx);
reader->Read<unsigned int>(varNXreadint, Nxs.data());
reader->Read<void>(varNXread, Nxs.data());
auto itmax = std::max_element(std::begin(Nxs), std::end(Nxs));
auto itmin = std::min_element(std::begin(Nxs), std::end(Nxs));
if (*itmin != *itmax)
{
throw std::ios_base::failure(
"ERROR: NX is not the same at all steps!\n");
}
/* Nparts */
// Nparts local scalar is presented as a 1D array of nproc elements.
// We can read all steps into a 2D array of nproc * nsteps
adios::Variable<void> varNpartsread = reader->InquireVariable("Nparts");
std::vector<int> partsV(Nproc * varNpartsread->GetSteps());
varNpartsread->SetStepSelection(
adios.StepSelection(0, varNpartsread.GetSteps()));
reader->Read<int>("Nparts", partsV.data());
reader->Read<void>(varNpartsread,
partsV.data()); // missing spatial selection = whole
// array at each step
// Close file/stream
reader->Close();
}
catch (adios::file_not_found &e)
{
// File/stream does not exist, quit
}
return 0;
}
This diff is collapsed.
CodingGuidelines
Created on: Sep 30, 2016
Rev: 0.1
Author: William F Godoy, godoywf@ornl.gov
This document introduces coding guidelines that all developers must follow as standard practice.
This list is open as corrections and new ideas/suggestions come in place.
Take them as mandatory to improve ADIOS development and collaboration.
Many items from this list are taken from Stroustrup, Sutter, and Meyers books.
Objectives:
1) Improve collaboration:
1.a. Reduce new code development and integration times for developers and users, by making code easy to understand
1.b. Allocate more time for discussion and pathfinding rather than understanding developers' coding
1.c. Expand developers and users base
2) Execute new ideas faster
3) Allocate more time to research and publication from new ideas
4) Improve quality of final software product: reduce potential security risks (segmentation faults, core dumps, overflows)
and ease the integration of customers' products with ADIOS
C++ coding guidelines, all mandatory in no particular order:
Text style for readability ( using clang-format, 80 columns line width )
1) Use meaningful English words (time not t, rank not r or rk), well-known acronyms (MPI, XML, CFD, GMRES, etc.)
or well-known short names (Config, Comm, 2D, 3D).
Examples: timeInitial instead of tIni, or work instead of wrk
One Exception: when redefining long types with the keyword "using" some mnemonics and short names is allowed, document scope of using
2) Avoid "_" in names, adds unnecessary length (specially when mixed with STL containers) to the variable name and could conflict with name mangling.
Reserve it for prefix of special cases (see class members and lambda functions).
Use upper case letter instead:
Don't: std::vector< std::vector<double> >
this_is_my_very_very_long_two_dimensional_vector_name;
Do: std::vector< std::vector<double> >
thisIsMyVeryVeryLongTwoDimensionalVectorName;
3) Prefer the keyword "using" over "typedef". Only rename very long complex or custom types,
do not rename standard types (int, double, std::vector)
Don't: typedef std::vector<std::vector< std::map<std::string,double> >> MapIn2DVector;
Do: using std::vector<std::vector< std::map<std::string,double> >> = MapIn2DVector;
See 1) for Exception: when redefining long types with the keyword "using"
some mnemonics and short names are allowed, document scope of using (local, class, file, etc.), though
4) The project uses ADIOS2 clang-format: http://releases.llvm.org/3.8.0/tools/clang/docs/ClangFormatStyleOptions.html
See Contributing.md for more information. In summary:
Lines no longer than 80 characters.
Always use braces { and }, even for 1 line "if" blocks and loops ("for", "while", etc.)
Use 4 spaces for indentation.
Documentation/Comments
1) Use Doxygen as the official API documentation tool.
Eclipse has a template autocomplete option for function declarations.
2) Only use Doxygen function documentation in header declaration (.h) files,
never in source definition (.cpp). Use informative // comments in the latter, see next.
3) Use meaningful comments that are not redundant in the definition. Add context instead.
Example: Don't: int size; // define the size of the MPI processes
Do: int size; // global size for tracking purposes at close()
Variable scope and Namespaces
1) Local scope variables and function arguments passed by value: first letter must be lower case ( int rank, int size ).
2) Functions: start with an upper case letter ( e.g. void Transform ( ), double Fourier( ), etc. )
3) Lambda functions: use hungarian notation with prefix lf_ in the function name. ( e.g. auto lf_Fourier = []( const double argument ) )
4) Avoid the "using namespace foo" clause, instead use the namespace explicitly.
(e.g. std::cout not cout, adios::CHDF5 not CHDF5 )
This prevents name conflict and allows identifying the function/variable source.
5) Declare variables right before they are needed, not at the beginning (Fortran style).
e.g. Don't ---> int rank; ...Many Lines of code... ; rank = SomeFunction( );
Do---> ...Many Lines of code... ; int rank = SomeFunction( );
6) Always pass by value primitives ( const int, double, const std::string ) if only a copy if needed.
The latter allows compiler optimization hints.
For bigger objects and STL containers pass by reference always
( CNETCDF& netcdf, std::vector<std::string>& names )
7) Use auto keyword only when it doesn't interfere with understanding the logic of the code (don't abuse its use).
Don't use it to replace primitives (int, unsigned int, double) or well-known types (std::vector).
Use it for iterators, when the container is well-known and comes from a STL member function.
e.g. auto itMap = myMap.find("William"); (we know it is an iterator from find in map)
Classes / Structs
1) Classes will be initialized with an upper case letter, example: ( ADIOS, NETCDF, PHDF5, Transform, Group, etc. )
2) Class member variables will use hungarian notation "m_" prefix followed an upper case letter: m_XMLConfig, m_GlobalSize. While member functions will have the same rules as regular functions (e.g. start with an upper case letter).
3) Reserve structs for public member variables only, Structs should not have member functions, inheritance or private members. Structs will be initialized with an upper case letter and member variables won't use hungarian notation as classes.
4) Only allow one header and one source file per class ( e.g. class Transport in Transport.h and Transport.cpp), do not define several classes in the same file.
Structs are always define in one header file, ( e.g. Attribute in Attribute.h )
One EXCEPTION: structs with static member variables, which must be defined in a source (*.cpp) file
Memory Management: Pointers, Smart Pointers, References and STL Containers
1) Avoid bare pointers (*p) at all cost for memory management (new/delete). Prefer smart pointers
unique_ptr, shared_ptr. Also, use smart pointers for polymorphism as objects are a dynamic (runtime) concept.
ONE Exception: MPI Data_TYPE that require pointers
2) Prefer references (&) over pointers in passing by reference or for members of a class.
ONE Exception: Use a bare pointer only if a reference to an object can be nullptr
(NEVER use it for memory management).
3) Prefer the STL for memory management to minimize new structs/object (new/delete) creation
(e.g. std::vector<double> instead of double* )
4) Avoid storing bare pointers in STL containers, they must be deallocated manually if so.
The STL is already taking care of object memory management.
Do: std::vector<double>
Don't: std::vector<double*>
5) Use reference and pointer identifiers attached to the type not the variable name,
Do: double* numbers , Don't: double * numbers
Do: std::vector<double>& vector, Don't: std::vector<double> &vector
6) Use RAII: resource allocation is initialization.
A good design should allocate memory resources at the constructor stage,
or as soon as the required information is available.
Fine tuning memory should be used only if it causes a big impact.
const / constexpr correctness, macro, and include statements
1) Always use const or constexpr when it is due as they are optimized and caught at compilation time
2) Do not use pre-processor macros (#define) unless it's a must (e.g. #ifdef __cplusplus or #pragma )
3) Use const in functions that don't change the state of an Object or its members
4) Use const in function arguments (value or references) if the state of the argument is not changed.
5) Always use include guards in headers (*.h), Eclipse does it automatically at file creation
using the file name.
(e.g. in ADIOS.h start with #ifndef ADIOS_H_
#define ADIOS_H_ )
6) Only include header files at the beginning of the file (#include <cmath>). Make each *.h file self-contained.
Don't include the same header file in *.cpp already defined in an included *.h file.
Example: if cmath is included in ADIOS.h, which is included by ADIOS.cpp,
then don't include cmath in ADIOS.cpp
Avoid mixing C-like equivalents
1) Use exclusive C++ header versions of their C-counterpart ( cmath over math.h, cstdlib over stdlib.h ).
Only use C-headers in these cases:
a. If there is no C++ equivalent (e.g. unistd.h )
b. When C++ libraries are deprecated or not fully supported ( MPI, CUDA_C, PETSc )
c. When interoperability is required with another language, C++ --> C ---> Fortran, or C++ --> C ---> JNI ---> Java
2) Do not use C functions if there is a C++ equivalent ( use std::cout instead of printf, new instead of malloc )
C++ Exceptions
1) Throw C++ standard exceptions for error handling, do not throw integers. This is helpful as it allows handling of different exception types in different ways. In rare cases a custom exceptions must be defined/declared.
2) All error exceptions must be caught at main (program stops) and must start with "ERROR: ". Use informative messages for exception handling to complement the nature of the exception. Help the user fix the error/warning.
3) Exceptions thrown by the code (no by STL functions) must be inside a debug mode condition set in the ADIOS class constructor.
\ No newline at end of file
# Documentation for the Adaptable Input / Output System (ADIOS) v2.0
# Generate Doxygen API
1. Requirements (on Linux install them from your package manager):
* doxygen http://www.stack.nl/~dimitri/doxygen/
* graphviz http://www.graphviz.org/
2. To generate the Doxygen API documentation under doc/html format (default) from the existing Doxyfile (edit Doxyfile to change options):
```
$ cd ADIOS2/doc
$ doxygen
```
# Documentation links
For a Quick Start, and Contributing to ADIOS 2.0: https://github.com/ornladios/ADIOS2/wiki
\ No newline at end of file
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