FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
NetThreads.h
1#pragma once
2
3#include <algorithm>
4#include <exception>
5#include <fhsim/simobject/ISimObjectCreator.h>
6#include <stdexcept>
7#include <string>
8#include <vector>
9
10#ifdef _OPENMP
11# include <omp.h>
12#endif
13
22namespace net_threads
23{
28inline int ReadNumThreads(ISimObjectCreator* creator)
29{
30 int numThreads = 1;
31 creator->GetIntParam("NumThreads", &numThreads, numThreads);
32 if (numThreads < 0) {
33 const std::string message = "NumThreads = " + std::to_string(numThreads) + " is negative; expected 0 (OpenMP's default), 1 (serial) or more.";
34 creator->ReportParameterError("NumThreads", message);
35 throw std::invalid_argument(message);
36 }
37#ifdef _OPENMP
38 if (numThreads == 0)
39 numThreads = omp_get_max_threads();
40#else
41 numThreads = 1; // built without OpenMP
42#endif
43 return std::max(numThreads, 1);
44}
45
47inline int ChunkBegin(const int count, const int chunk, const int chunks)
48{
49 return count * chunk / chunks;
50}
51
61template <class UpdateNodes, class AddForces>
62void SumForcesInChunks(const int chunks, const int numNodes, std::vector<double>& buffers, double* const nodeForce, UpdateNodes updateNodes, AddForces addForces)
63{
64 const size_t bufferSize = 3 * static_cast<size_t>(numNodes);
65 std::exception_ptr failure; // The first exception any thread met (MARE-0422).
66#ifdef _OPENMP
67# pragma omp parallel num_threads(chunks)
68#endif
69 {
70 // An exception that leaves an OpenMP region ends the process with std::terminate and no message. Each thread keeps
71 // the first one and still reaches the barrier; it is rethrown on the calling thread after the region.
72 const auto keepFailure = [&failure]() {
73#ifdef _OPENMP
74# pragma omp critical(net_threads_failure)
75#endif
76 {
77 if (!failure)
78 failure = std::current_exception();
79 }
80 };
81#ifdef _OPENMP
82 const int first = omp_get_thread_num();
83 const int stride = omp_get_num_threads();
84#else
85 const int first = 0;
86 const int stride = 1;
87#endif
88 try {
89 for (int chunk = first; chunk < chunks; chunk += stride)
90 updateNodes(ChunkBegin(numNodes, chunk, chunks), ChunkBegin(numNodes, chunk + 1, chunks));
91 } catch (...) {
92 keepFailure();
93 }
94#ifdef _OPENMP
95# pragma omp barrier
96#endif
97 try {
98 for (int chunk = first; chunk < chunks; chunk += stride) {
99 double* const forces = buffers.data() + chunk * bufferSize;
100 std::fill(forces, forces + bufferSize, 0.0);
101 addForces(chunk, chunks, forces);
102 }
103 } catch (...) {
104 keepFailure();
105 }
106 }
107 if (failure)
108 std::rethrow_exception(failure);
109 for (int chunk = 0; chunk < chunks; chunk++) {
110 const double* const forces = buffers.data() + chunk * bufferSize;
111 for (size_t i = 0; i < bufferSize; i++)
112 nodeForce[i] += forces[i];
113 }
114}
115} // namespace net_threads