Operators ========= .. _sec:tutorials_basics_operators: In the previous tutorial we learned how to write and read attributes. For this example to work, you would need to have a compression library installed, which ADIOS automatically detects. The easiest way to install SZ or SZ3 is with Spack, and you can do that as follows: .. code-block:: bash git clone https://github.com/spack/spack.git ~/spack cd ~/spack . share/spack/setup-env.sh spack install sz # for SZ (SZ2) # or spack install sz3 # for SZ3 spack load sz # or sz3 In this tutorial we will learn how to use operators. Operators are used for Data compression/decompression, lossy and lossless. They act upon the user application data, either from a variable or a set of variables in a IO object. Additionally, we will explore how to simply write variables across multiple steps. So, let's dig in! Start editing the skeleton file `ADIOS2/examples/hello/bpOperatorSZWriter/bpOperatorSZWriter_tutorialSkeleton.cpp `_. 1. In an MPI application first we need to always initialize MPI. We do that with the following lines: .. code-block:: cpp int rank, size; int rank, size; int provided; // MPI_THREAD_MULTIPLE is only required if you enable the SST MPI_DP MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); 2. This application has command line arguments for the size of the data, and the compression accuracy, which we can read as follows: .. code-block:: cpp const std::size_t Nx = static_cast(std::stoull(argv[1])); const double accuracy = std::stod(argv[2]); 3. Now we need to create some application variables which will be used to define ADIOS2 variables. .. code-block:: cpp std::vector myFloats(Nx); std::vector myDoubles(Nx); std::iota(myFloats.begin(), myFloats.end(), 0.); std::iota(myDoubles.begin(), myDoubles.end(), 0.); 4. Now we need to create an ADIOS2 instance and IO object. .. code-block:: cpp adios2::ADIOS adios(MPI_COMM_WORLD); adios2::IO bpIO = adios.DeclareIO("BPFile_SZ"); 5. Now we need to define the variables we want to write. .. code-block:: cpp adios2::Variable bpFloats = bpIO.DefineVariable( "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims); adios2::Variable bpDoubles = bpIO.DefineVariable( "bpDoubles", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims); 6. Now we need to define the compression operator we want to use. In this case we will use the SZ compressor. .. code-block:: cpp adios2::Operator op = bpIO.DefineOperator("SZCompressor", "sz"); varFloats.AddOperation(op, {{"accuracy", std::to_string(accuracy)}}); varDoubles.AddOperation(op, {{"accuracy", std::to_string(accuracy)}}); .. note:: ``DefineOperator()``'s second parameter can be ``zfp``, ``sz``, or ``sz3``. For more information regarding operators and their properties you can look at :ref:`Basics: Interface Components: Operator `. 7. Let's also create an attribute to store the accuracy value. .. code-block:: cpp adios2::Attribute attribute = bpIO.DefineAttribute("accuracy", accuracy); 8. Now we need to open the file for writing. .. code-block:: cpp adios2::Engine bpWriter = bpIO.Open("SZexample.bp", adios2::Mode::Write); 9. Now we need to write the data. We will write the data for 3 steps, and edit them in between. .. code-block:: cpp for (unsigned int step = 0; step < 3; ++step) { bpWriter.BeginStep(); bpWriter.Put(bpDoubles, myDoubles.data()); bpWriter.Put(bpFloats, myFloats.data()); bpWriter.EndStep(); // here you can modify myFloats, myDoubles per step std::transform(myFloats.begin(), myFloats.end(), myFloats.begin(), [&](float v) -> float { return 2 * v; }); std::transform(myDoubles.begin(), myDoubles.end(), myDoubles.begin(), [&](double v) -> double { return 3 * v; }); } 10. Now we need to close the file. .. code-block:: cpp bpWriter.Close(); 11. Finally we need to finalize MPI. .. code-block:: cpp MPI_Finalize(); 12. The final code should look as follows (excluding try/catch and optional usage of MPI), and it was derived from the example `ADIOS2/examples/hello/bpOperatorSZWriter/bpOperatorSZWriter.cpp `_. .. literalinclude:: ../../../../examples/hello/bpOperatorSZWriter/bpOperatorSZWriter.cpp :language: cpp 13. You can compile and run it as follows: .. code-block:: bash cd Path-To-ADIOS2/examples/hello/bpOperatorSZWriter mkdir build cd build cmake -DADIOS2_DIR=Path-To-ADIOS2/build/ .. cmake --build . mpirun -np 2 ./adios2_hello_bpOperatorSZWriter_mpi 20 0.000001 12. You can check the content of the output file "SZexample.bp" using *bpls* as follows: .. code-block:: bash Path-To-ADIOS2/build/bin/bpls ./SZexample.bp double bpDoubles 3*{40} float bpFloats 3*{40}