OGS
ParallelVectorMatrixAssembler.cpp
Go to the documentation of this file.
1
12
13#include <cstdlib>
14#include <fstream>
15
16#include "BaseLib/StringTools.h"
22
23namespace
24{
26 const std::size_t mesh_item_id,
28 const NumLib::LocalToGlobalIndexMap& dof_table, const double t,
29 const double dt, const GlobalVector& x, const GlobalVector& x_prev,
30 std::vector<double>& local_M_data, std::vector<double>& local_K_data,
31 std::vector<double>& local_b_data, std::vector<double>& local_Jac_data,
32 std::vector<GlobalIndexType>& indices,
33 ProcessLib::AbstractJacobianAssembler& jacobian_assembler,
35{
36 indices = NumLib::getIndices(mesh_item_id, dof_table);
37
38 local_M_data.clear();
39 local_K_data.clear();
40 local_b_data.clear();
41 local_Jac_data.clear();
42
43 auto const local_x = x.get(indices);
44 auto const local_x_prev = x_prev.get(indices);
45 jacobian_assembler.assembleWithJacobian(
46 local_assembler, t, dt, local_x, local_x_prev, local_M_data,
47 local_K_data, local_b_data, local_Jac_data);
48
49 if (local_Jac_data.empty())
50 {
52 "No Jacobian has been assembled! This might be due to "
53 "programming errors in the local assembler of the "
54 "current process.");
55 }
56
57 cache.add(local_M_data, local_K_data, local_b_data, local_Jac_data,
58 indices);
59}
60
62{
63 char const* const num_threads_env = std::getenv("OGS_ASM_THREADS");
64
65 if (!num_threads_env)
66 {
67 return 1;
68 }
69
70 if (std::strlen(num_threads_env) == 0)
71 {
72 OGS_FATAL("The environment variable OGS_ASM_THREADS is set but empty.");
73 }
74
75 std::string num_threads_str{num_threads_env};
76 BaseLib::trim(num_threads_str);
77
78 std::istringstream num_threads_iss{num_threads_str};
79 int num_threads = -1;
80
81 num_threads_iss >> num_threads;
82
83 if (!num_threads_iss)
84 {
85 OGS_FATAL("Error parsing OGS_ASM_THREADS (= \"{}\").", num_threads_env);
86 }
87
88 if (!num_threads_iss.eof())
89 {
91 "Error parsing OGS_ASM_THREADS (= \"{}\"): not read entirely, the "
92 "remainder is \"{}\"",
93 num_threads_env,
94 num_threads_iss.str().substr(num_threads_iss.tellg()));
95 }
96
97 if (num_threads < 1)
98 {
100 "You asked (via OGS_ASM_THREADS) to assemble with {} < 1 thread.",
101 num_threads);
102 }
103
104 return num_threads;
105}
106} // namespace
107
108namespace ProcessLib::Assembly
109{
111 AbstractJacobianAssembler& jacobian_assembler)
112 : jacobian_assembler_{jacobian_assembler},
113 num_threads_(getNumberOfThreads())
114{
115}
116
119 LocalAssemblerInterface> const& local_assemblers,
120 std::vector<std::size_t> const& active_elements,
121 std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_tables,
122 const double t, double const dt, std::vector<GlobalVector*> const& xs,
123 std::vector<GlobalVector*> const& x_prevs, int const process_id,
125{
126 // checks //////////////////////////////////////////////////////////////////
127 if (process_id != 0)
128 {
129 OGS_FATAL("Process id is not 0 but {}", process_id);
130 }
131
132 if (dof_tables.size() != 1)
133 {
134 OGS_FATAL("More than 1 dof table");
135 }
136 auto const& dof_table = *(dof_tables.front());
137
138 if (xs.size() != 1)
139 {
140 OGS_FATAL("More than 1 solution vector");
141 }
142 auto const& x = *xs.front();
143
144 if (x_prevs.size() != 1)
145 {
146 OGS_FATAL("More than 1 x_prev vector");
147 }
148 auto const& x_prev = *x_prevs.front();
149
150 // algorithm ///////////////////////////////////////////////////////////////
151
153 ConcurrentMatrixView M_view(M);
154 ConcurrentMatrixView K_view(K);
155 ConcurrentMatrixView b_view(b);
156 ConcurrentMatrixView Jac_view(Jac);
157
158 ThreadException exception;
159 bool assembly_error = false;
160#pragma omp parallel num_threads(num_threads_)
161 {
162#ifdef _OPENMP
163#pragma omp single nowait
164 {
165 INFO("Number of threads: {}", omp_get_num_threads());
166 }
167#endif
168
169 // temporary data only stored here in order to avoid frequent memory
170 // reallocations.
171 std::vector<double> local_M_data;
172 std::vector<double> local_K_data;
173 std::vector<double> local_b_data;
174 std::vector<double> local_Jac_data;
175 std::vector<GlobalIndexType> indices;
176
177 // copy to avoid concurrent access
178 auto const jac_asm = jacobian_assembler_.copy();
179 auto stats_this_thread = stats->clone();
180
181 MultiMatrixElementCache cache{M_view, K_view, b_view, Jac_view,
182 stats_this_thread->data};
183
184 // TODO corner case: what if all elements on a submesh are deactivated?
185 if (active_elements.empty())
186 {
187 // due to MSVC++ error:
188 // error C3016: 'element_id': index variable in OpenMP 'for'
189 // statement must have signed integral type
190 std::ptrdiff_t const n_loc_asm =
191 static_cast<std::ptrdiff_t>(local_assemblers.size());
192
193#pragma omp for nowait
194 for (std::ptrdiff_t element_id = 0; element_id < n_loc_asm;
195 ++element_id)
196 {
197 if (assembly_error)
198 {
199 continue;
200 }
201 auto& loc_asm = local_assemblers[element_id];
202
203 try
204 {
205 assembleWithJacobianOneElement(
206 element_id, loc_asm, dof_table, t, dt, x, x_prev,
207 local_M_data, local_K_data, local_b_data,
208 local_Jac_data, indices, *jac_asm, cache);
209 }
210 catch (...)
211 {
212 exception.capture();
213 assembly_error = true;
214 continue;
215 }
216
217 local_matrix_output_(t, process_id, element_id, local_M_data,
218 local_K_data, local_b_data,
219 &local_Jac_data);
220 }
221 }
222 else
223 {
224 // due to MSVC++ error:
225 // error C3016: 'i': index variable in OpenMP 'for' statement must
226 // have signed integral type
227 std::ptrdiff_t const n_act_elem =
228 static_cast<std::ptrdiff_t>(active_elements.size());
229
230#pragma omp for nowait
231 for (std::ptrdiff_t i = 0; i < n_act_elem; ++i)
232 {
233 if (assembly_error)
234 {
235 continue;
236 }
237
238 auto const element_id = active_elements[i];
239 auto& loc_asm = local_assemblers[element_id];
240
241 try
242 {
243 assembleWithJacobianOneElement(
244 element_id, loc_asm, dof_table, t, dt, x, x_prev,
245 local_M_data, local_K_data, local_b_data,
246 local_Jac_data, indices, *jac_asm, cache);
247 }
248 catch (...)
249 {
250 exception.capture();
251 assembly_error = true;
252 continue;
253 }
254
255 local_matrix_output_(t, process_id, element_id, local_M_data,
256 local_K_data, local_b_data,
257 &local_Jac_data);
258 }
259 }
260 } // OpenMP parallel section
261
262 stats->print();
263
264 global_matrix_output_(t, process_id, M, K, b, &Jac);
265 exception.rethrow();
266}
267} // namespace ProcessLib::Assembly
#define OGS_FATAL(...)
Definition Error.h:26
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
Definition of string helper functions.
Global vector based on Eigen vector.
Definition EigenVector.h:25
double get(IndexType rowId) const
get entry
Definition EigenVector.h:58
Base class for Jacobian assemblers.
virtual std::unique_ptr< AbstractJacobianAssembler > copy() const =0
virtual void assembleWithJacobian(LocalAssemblerInterface &local_assembler, double const t, double const dt, std::vector< double > const &local_x, std::vector< double > const &local_x_prev, std::vector< double > &local_M_data, std::vector< double > &local_K_data, std::vector< double > &local_b_data, std::vector< double > &local_Jac_data)=0
static std::shared_ptr< CumulativeStats< Data > > create()
void add(std::vector< double > const &local_M_data, std::vector< double > const &local_K_data, std::vector< double > const &local_b_data, std::vector< double > const &local_Jac_data, std::vector< GlobalIndexType > const &indices)
void assembleWithJacobian(BaseLib::PolymorphicRandomAccessContainerView< LocalAssemblerInterface > const &local_assemblers, std::vector< std::size_t > const &active_elements, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, const double t, double const dt, std::vector< GlobalVector * > const &xs, std::vector< GlobalVector * > const &x_prevs, int const process_id, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b, GlobalMatrix &Jac)
ParallelVectorMatrixAssembler(AbstractJacobianAssembler &jacobian_assembler)
void trim(std::string &str, char ch)
std::vector< GlobalIndexType > getIndices(std::size_t const mesh_item_id, NumLib::LocalToGlobalIndexMap const &dof_table)
void assembleWithJacobianOneElement(const std::size_t mesh_item_id, ProcessLib::LocalAssemblerInterface &local_assembler, const NumLib::LocalToGlobalIndexMap &dof_table, const double t, const double dt, const GlobalVector &x, const GlobalVector &x_prev, std::vector< double > &local_M_data, std::vector< double > &local_K_data, std::vector< double > &local_b_data, std::vector< double > &local_Jac_data, std::vector< GlobalIndexType > &indices, ProcessLib::AbstractJacobianAssembler &jacobian_assembler, ProcessLib::Assembly::MultiMatrixElementCache &cache)