diff --git a/Serie04/debugging/Makefile b/Serie04/debugging/Makefile new file mode 100644 index 0000000..abea0cf --- /dev/null +++ b/Serie04/debugging/Makefile @@ -0,0 +1,14 @@ +#OPTIM+=-O3 -march=native +DEBUG+=-g -O1 +CXX=g++ +CC=g++ +LD=${CXX} +CXXFLAGS+=$(OPTIM) $(DEBUG) -Wall -Wextra -std=c++11 +LDFLAGS+=$(OPTIM) $(DEBUG) $(CXXFLAGS) -lm + +all: read write + +pi: read.o write.o + +clean: + rm -f read write *.o *~ diff --git a/Serie04/debugging/read.cc b/Serie04/debugging/read.cc new file mode 100644 index 0000000..e84e683 --- /dev/null +++ b/Serie04/debugging/read.cc @@ -0,0 +1,18 @@ +#include +#include + +int main() { + constexpr size_t N = 1000; + std::vector data(N); + + for(size_t i = 0; i < N; ++i) { + data[i] = i; + } + + double sum = 0.; + for(size_t i = 0; i <= N; ++i) { + sum += data[i]; + } + + std::cout << (N * (N-1) / 2.) << " == " << sum << std::endl; +} diff --git a/Serie04/debugging/write.cc b/Serie04/debugging/write.cc new file mode 100644 index 0000000..9c3e30b --- /dev/null +++ b/Serie04/debugging/write.cc @@ -0,0 +1,18 @@ +#include +#include + +int main() { + constexpr size_t N = 1000; + std::vector data; + + for(size_t i = 0; i < N; ++i) { + data[i] = i; + } + + double sum = 0.; + for(size_t i = 0; i < N; ++i) { + sum += data[i]; + } + + std::cout << (N * (N-1) / 2.) << " == " << sum << std::endl; +} diff --git a/Serie04/pi/Makefile b/Serie04/pi/Makefile new file mode 100644 index 0000000..ea00d72 --- /dev/null +++ b/Serie04/pi/Makefile @@ -0,0 +1,12 @@ +OPTIM+=-O3 -march=native +CXX=g++ +CC=g++ +LD=$(CXX) +CXXFLAGS+=-Wall -Wextra -std=c++11 $(OPTIM) +LDFLAGS+= +EXE=pi + +all: clean $(EXE) + +clean: + rm -f $(EXE) *.o *~ diff --git a/Serie04/pi/pi.cc b/Serie04/pi/pi.cc new file mode 100644 index 0000000..b9736e2 --- /dev/null +++ b/Serie04/pi/pi.cc @@ -0,0 +1,68 @@ +/* + This exercise is taken from the class Parallel Programming Workshop (MPI, + OpenMP and Advanced Topics) at HLRS given by Rolf Rabenseifner + */ + +#include +#include +#include + +#ifdef _OPENMP +#include +#endif + +using clk = std::chrono::high_resolution_clock; +using second = std::chrono::duration; +using time_point = std::chrono::time_point; + +inline int digit(double x, int n) { + return std::trunc(x * std::pow(10., n)) - std::trunc(x * std::pow(10., n - 1)) *10.; +} + +inline double f(double a) { return (4. / (1. + a * a)); } + +const int n = 10000000; + +int main(int /* argc */ , char ** /* argv */) { + int i; + double dx, x, sum, pi; + int nthreads; + + + + + +#ifdef _OPENMP + auto omp_t1 = omp_get_wtime(); +#endif + auto t1 = clk::now(); + + /* calculate pi = integral [0..1] 4 / (1 + x**2) dx */ + dx = 1. / n; + sum = 0.0; + for (i = 0; i < n; i++) { + x = 1. * i * dx; + sum = sum + f(x); + } + pi = dx * sum; + + + +#ifdef _OPENMP + auto omp_elapsed = omp_get_wtime() - omp_t1; +#endif + second elapsed = clk::now() - t1; + + + std::printf("computed pi = %.16g\n", pi); +#ifdef _OPENMP + std::printf("wall clock time (omp_get_wtime) = %.4gs in %d threads\n", omp_elapsed, nthreads); +#endif + std::printf("wall clock time (chrono) = %.4gs\n", elapsed.count()); + + for(int d = 1; d <= 15; ++d) { + std::printf("%d", digit(pi, d)); + } + + return 0; +} diff --git a/Serie04/poisson/AUTHORS b/Serie04/poisson/AUTHORS new file mode 100644 index 0000000..9253635 --- /dev/null +++ b/Serie04/poisson/AUTHORS @@ -0,0 +1,4 @@ +Authors: + - Nicolas Richart + - Vincent Keller + . Vittoria Rezzonico diff --git a/Serie04/poisson/COPYING b/Serie04/poisson/COPYING new file mode 100644 index 0000000..e551330 --- /dev/null +++ b/Serie04/poisson/COPYING @@ -0,0 +1,24 @@ +Copyright (c) 2017, Ecole Polytechnique Federal de Lausanne - Scientific IT and +Application Support (SCITAS) All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Serie04/poisson/Makefile b/Serie04/poisson/Makefile new file mode 100644 index 0000000..284fd1e --- /dev/null +++ b/Serie04/poisson/Makefile @@ -0,0 +1,14 @@ +CXX=g++ +LD=$(CXX) +CXXFLAGS+=-Wall -Wextra -Werror -pedantic -std=c++11 +LDFLAGS+=$(CXXFLAGS) + +OBJS=poisson.o simulation.o double_buffer.o grid.o dumpers.o + +all: poisson + +poisson: $(OBJS) + $(LD) -o $@ $(OBJS) $(LDFLAGS) + +clean: + rm -f hello poisson *.o *~ diff --git a/Serie04/poisson/README b/Serie04/poisson/README new file mode 100644 index 0000000..ec24d90 --- /dev/null +++ b/Serie04/poisson/README @@ -0,0 +1,19 @@ +This code is composed of multiple files: + +- poisson.cc + contains the main function and the size of the problem + +- simulation.cc + contains the poisson solver + "compute_step" does the update of the grid for one step + "compute" does the loop with step computation and the swaping of the grids + +- grid.cc + contains a simple 2d grid stored in a 1d array + +- dumpers.cc + contains 2 implementations of a dumper, one generates ascii files + (pgm) the other one writes binary files (bmp) + +- double_buffer.cc + contains a simple tool to swap two grids \ No newline at end of file diff --git a/Serie04/poisson/double_buffer.cc b/Serie04/poisson/double_buffer.cc new file mode 100644 index 0000000..e6ecf0f --- /dev/null +++ b/Serie04/poisson/double_buffer.cc @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +#include "double_buffer.hh" +#include "grid.hh" +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +DoubleBuffer::DoubleBuffer(int m, int n) + : m_current(new Grid(m, n)), m_old(new Grid(m, n)) {} + +/* -------------------------------------------------------------------------- */ +Grid & DoubleBuffer::current() { return *m_current; } + +/* -------------------------------------------------------------------------- */ +Grid & DoubleBuffer::old() { return *m_old; } + +/* -------------------------------------------------------------------------- */ +void DoubleBuffer::swap() { + m_current.swap(m_old); +} diff --git a/Serie04/poisson/double_buffer.hh b/Serie04/poisson/double_buffer.hh new file mode 100644 index 0000000..67a1405 --- /dev/null +++ b/Serie04/poisson/double_buffer.hh @@ -0,0 +1,24 @@ +#ifndef DOUBLE_BUFFER +#define DOUBLE_BUFFER + +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ +#include "grid.hh" +/* -------------------------------------------------------------------------- */ + +class DoubleBuffer { +public: + DoubleBuffer(int m, int n); + + Grid & current(); + Grid & old(); + + void swap(); +private: + + std::unique_ptr m_current; + std::unique_ptr m_old; +}; + +#endif /* DOUBLE_BUFFER */ diff --git a/Serie04/poisson/dumpers.cc b/Serie04/poisson/dumpers.cc new file mode 100644 index 0000000..de7eb79 --- /dev/null +++ b/Serie04/poisson/dumpers.cc @@ -0,0 +1,120 @@ +/* -------------------------------------------------------------------------- */ +#include "dumpers.hh" +#include "grid.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +void Dumper::set_min(float min) { + m_min = min; +} + +void Dumper::set_max(float max) { + m_max = max; +} + +float Dumper::min() const { + return m_min; +} + +float Dumper::max() const { + return m_max; +} + +/* -------------------------------------------------------------------------- */ +void DumperASCII::dump(int step) { + std::ofstream fout; + std::stringstream sfilename; + + sfilename << "output/out_" << std::setfill('0') << std::setw(5) << step << ".pgm"; + fout.open(sfilename.str()); + + int m = m_grid.m(); + int n = m_grid.n(); + + fout << "P2" << std::endl << "# CREATOR: Poisson program" << std::endl; + fout << m << " " << n << std::endl; + fout << 255 << std::endl; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int v = 255. * (m_grid(i, j) - m_min) / (m_max - m_min); + v = std::min(v, 255); + fout << v << std::endl; + } + } +} + +/* -------------------------------------------------------------------------- */ +void DumperBinary::dump(int step) { + std::ofstream fout; + std::stringstream sfilename; + + sfilename << "out_" << std::setfill('0') << std::setw(5) << step << ".bmp"; + fout.open(sfilename.str(), std::ios_base::binary); + + int h = m_grid.m(); + int w = m_grid.n(); + + int row_size = 3 * w; + // if the file width (3*w) is not a multiple of 4 adds enough bytes to make it + // a multiple of 4 + int padding = (4 - (row_size) % 4) % 4; + row_size += padding; + + int filesize = 54 + (row_size)*h; + + std::vector img(row_size*h); + std::fill(img.begin(), img.end(), 0); + + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + float v = ((m_grid(h - 1 - i, j) - m_min) / (m_max - m_min)); + + float r = v * 255; // Red channel + float g = v * 255; // Green channel + float b = v * 255; // Red channel + + r = std::min(r, 255.f); + g = std::min(g, 255.f); + b = std::min(b, 255.f); + + img[row_size * i + 3 * j + 2] = r; + img[row_size * i + 3 * j + 1] = g; + img[row_size * i + 3 * j + 0] = b; + } + } + + std::array bmpfileheader = {'B', 'M', 0, 0, 0, 0, 0, + 0, 0, 0, 54, 0, 0, 0}; + std::array bmpinfoheader = {40, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 24, 0}; + + bmpfileheader[2] = filesize; + bmpfileheader[3] = filesize >> 8; + bmpfileheader[4] = filesize >> 16; + bmpfileheader[5] = filesize >> 24; + + bmpinfoheader[4] = w; + bmpinfoheader[5] = w >> 8; + bmpinfoheader[6] = w >> 16; + bmpinfoheader[7] = w >> 24; + bmpinfoheader[8] = h; + bmpinfoheader[9] = h >> 8; + bmpinfoheader[10] = h >> 16; + bmpinfoheader[11] = h >> 24; + bmpinfoheader[20] = (filesize - 54); + bmpinfoheader[21] = (filesize - 54) >> 8; + bmpinfoheader[22] = (filesize - 54) >> 16; + bmpinfoheader[23] = (filesize - 54) >> 24; + + fout.write(bmpfileheader.data(), 14); + fout.write(bmpinfoheader.data(), 40); + + fout.write(img.data(), h * row_size); +} diff --git a/Serie04/poisson/dumpers.hh b/Serie04/poisson/dumpers.hh new file mode 100644 index 0000000..03a78c5 --- /dev/null +++ b/Serie04/poisson/dumpers.hh @@ -0,0 +1,41 @@ +#ifndef DUMPERS_HH +#define DUMPERS_HH + +/* -------------------------------------------------------------------------- */ +class Grid; + +/* -------------------------------------------------------------------------- */ +class Dumper { +public: + explicit Dumper(const Grid & grid) : m_grid(grid), m_min(-1.), m_max(1.) {} + + virtual void dump(int step) = 0; + + void set_min(float min); + void set_max(float max); + + float min() const; + float max() const; + +protected: + const Grid & m_grid; + float m_min, m_max; +}; + +/* -------------------------------------------------------------------------- */ +class DumperASCII : public Dumper { +public: + explicit DumperASCII(const Grid & grid) : Dumper(grid) {} + + virtual void dump(int step); +}; + +/* -------------------------------------------------------------------------- */ +class DumperBinary : public Dumper { +public: + explicit DumperBinary(const Grid & grid) : Dumper(grid) {} + + virtual void dump(int step); +}; + +#endif /* DUMPERS_HH */ diff --git a/Serie04/poisson/grid.cc b/Serie04/poisson/grid.cc new file mode 100644 index 0000000..4e9fb84 --- /dev/null +++ b/Serie04/poisson/grid.cc @@ -0,0 +1,15 @@ +/* -------------------------------------------------------------------------- */ +#include "grid.hh" +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +Grid::Grid(int m, int n) : m_m(m), m_n(n), m_storage(m * n) { clear(); } + +/* -------------------------------------------------------------------------- */ +void Grid::clear() { std::fill(m_storage.begin(), m_storage.end(), 0.); } + +/* -------------------------------------------------------------------------- */ +int Grid::m() const { return m_m; } +int Grid::n() const { return m_n; } diff --git a/Serie04/poisson/grid.hh b/Serie04/poisson/grid.hh new file mode 100644 index 0000000..ad872cb --- /dev/null +++ b/Serie04/poisson/grid.hh @@ -0,0 +1,29 @@ +#ifndef GRID_HH +#define GRID_HH + +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ + +class Grid { +public: + Grid(int m, int n); + + /// access the value [i][j] of the grid + inline float & operator()(int i, int j) { return m_storage[i * m_n + j]; } + inline const float & operator()(int i, int j) const { + return m_storage[i * m_n + j]; + } + + /// set the grid to 0 + void clear(); + + int m() const; + int n() const; + +private: + int m_m, m_n; + std::vector m_storage; +}; + +#endif /* GRID_HH */ diff --git a/Serie04/poisson/output/.to-keep b/Serie04/poisson/output/.to-keep new file mode 100644 index 0000000..e69de29 diff --git a/Serie04/poisson/poisson.cc b/Serie04/poisson/poisson.cc new file mode 100644 index 0000000..c212bf4 --- /dev/null +++ b/Serie04/poisson/poisson.cc @@ -0,0 +1,28 @@ +/* -------------------------------------------------------------------------- */ +#include "simulation.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +#define N 256 +#define EPSILON 0.005 + +int main() { + + Simulation simu(N, N); + + simu.set_initial_conditions(); + + simu.set_epsilon(EPSILON); + + float l2; + int k; + std::tie(l2, k) = simu.compute(); + + std::cout <<"nb steps " << k << " [l2 = " << l2 << "]" + << std::endl; + + return 0; +} diff --git a/Serie04/poisson/simulation.cc b/Serie04/poisson/simulation.cc new file mode 100644 index 0000000..6dc7c28 --- /dev/null +++ b/Serie04/poisson/simulation.cc @@ -0,0 +1,65 @@ +/* -------------------------------------------------------------------------- */ +#include "simulation.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +Simulation::Simulation(int m, int n) + : m_global_m(m), m_global_n(n), m_epsilon(1e-7), m_h_m(1. / m), + m_h_n(1. / n), m_grids(m, n), m_f(m, n), + m_dumper(new DumperASCII(m_grids.old())) {} + +/* -------------------------------------------------------------------------- */ +void Simulation::set_initial_conditions() { + for (int i = 0; i < m_global_m; i++) { + for (int j = 0; j < m_global_n; j++) { + m_f(i, j) = -2. * 100. * M_PI * M_PI * std::sin(10. * M_PI * i * m_h_m) * + std::sin(10. * M_PI * j * m_h_n); + } + } +} + +/* -------------------------------------------------------------------------- */ +std::tuple Simulation::compute() { + int s = 0; + float l2 = 0; + do { + l2 = compute_step(); + + m_grids.swap(); + + m_dumper->dump(s); + ++s; + } while (l2 > m_epsilon); + + return std::make_tuple(l2, s); +} + +/* -------------------------------------------------------------------------- */ +void Simulation::set_epsilon(float epsilon) { m_epsilon = epsilon; } + +/* -------------------------------------------------------------------------- */ +float Simulation::epsilon() const { return m_epsilon; } + +/* -------------------------------------------------------------------------- */ +float Simulation::compute_step() { + float l2 = 0.; + + Grid & u = m_grids.current(); + Grid & uo = m_grids.old(); + + for (int j = 1; j < m_global_n - 1; j++) { + for (int i = 1; i < m_global_m - 1; i++) { + // computation of the new step + u(i, j) = 0.25 * (uo(i - 1, j) + uo(i + 1, j) + uo(i, j - 1) + + uo(i, j + 1) - m_f(i, j) * m_h_m * m_h_n); + + // L2 norm + l2 += (uo(i, j) - u(i, j)) * (uo(i, j) - u(i, j)); + } + } + + return l2; +} diff --git a/Serie04/poisson/simulation.hh b/Serie04/poisson/simulation.hh new file mode 100644 index 0000000..a64e430 --- /dev/null +++ b/Serie04/poisson/simulation.hh @@ -0,0 +1,52 @@ +#ifndef SIMULATION_HH +#define SIMULATION_HH + +/* -------------------------------------------------------------------------- */ +#include "double_buffer.hh" +#include "dumpers.hh" +#include "grid.hh" +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +class Simulation { +public: + Simulation(int m, int n); + + /// set the initial conditions, Dirichlet and source term + virtual void set_initial_conditions(); + + /// perform the simulation + std::tuple compute(); + + /// access the precision + void set_epsilon(float epsilon); + float epsilon() const; + +protected: + /// compute one step and return an error + virtual float compute_step(); + +private: + /// Global problem size + int m_global_m, m_global_n; + + /// Precision to achieve + float m_epsilon; + + /// grid spacing + float m_h_m; + float m_h_n; + + /// Grids storage + DoubleBuffer m_grids; + + /// source term + Grid m_f; + + /// Dumper to use for outputs + std::unique_ptr m_dumper; +}; + +#endif /* SIMULATION_HH */